Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 34196 invoked from network); 13 Nov 2007 12:59:49 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 13 Nov 2007 12:59:49 -0000 Received: (qmail 21413 invoked by uid 500); 13 Nov 2007 12:59:37 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 21371 invoked by uid 500); 13 Nov 2007 12:59:36 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 21360 invoked by uid 99); 13 Nov 2007 12:59:36 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 13 Nov 2007 04:59:36 -0800 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 13 Nov 2007 12:59:47 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id ACF081A985B; Tue, 13 Nov 2007 04:59:04 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r594520 [10/10] - in /geronimo/javamail/trunk/geronimo-javamail_1.4: ./ geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/authentication/ geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/hand... Date: Tue, 13 Nov 2007 12:57:53 -0000 To: scm@geronimo.apache.org From: rickmcguire@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20071113125904.ACF081A985B@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/CommandFailedException.java URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/CommandFailedException.java?rev=594520&view=auto ============================================================================== --- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/CommandFailedException.java (added) +++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/CommandFailedException.java Tue Nov 13 04:57:39 2007 @@ -0,0 +1,35 @@ +/** + * 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.util; + +import javax.mail.MessagingException; + +public class CommandFailedException extends MessagingException { + public CommandFailedException() { + super(); + } + + public CommandFailedException(String message) { + super(message); + } + + public CommandFailedException(String message, Exception cause) { + super(message, cause); + } +} + Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/CommandFailedException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/CommandFailedException.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/CommandFailedException.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ConnectionException.java URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ConnectionException.java?rev=594520&view=auto ============================================================================== --- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ConnectionException.java (added) +++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ConnectionException.java Tue Nov 13 04:57:39 2007 @@ -0,0 +1,35 @@ +/** + * 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.util; + +import javax.mail.MessagingException; + +public class ConnectionException extends MessagingException { + public ConnectionException() { + super(); + } + + public ConnectionException(String message) { + super(message); + } + + public ConnectionException(String message, Exception cause) { + super(message, cause); + } +} + Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ConnectionException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ConnectionException.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ConnectionException.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/InvalidCommandException.java URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/InvalidCommandException.java?rev=594520&view=auto ============================================================================== --- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/InvalidCommandException.java (added) +++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/InvalidCommandException.java Tue Nov 13 04:57:39 2007 @@ -0,0 +1,35 @@ +/** + * 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.util; + +import javax.mail.MessagingException; + +public class InvalidCommandException extends MessagingException { + public InvalidCommandException() { + super(); + } + + public InvalidCommandException(String message) { + super(message); + } + + public InvalidCommandException(String message, Exception cause) { + super(message, cause); + } +} + Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/InvalidCommandException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/InvalidCommandException.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/InvalidCommandException.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java?rev=594520&view=auto ============================================================================== --- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java (added) +++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java Tue Nov 13 04:57:39 2007 @@ -0,0 +1,712 @@ +/** + * 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.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.net.ssl.SSLSocket; + +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.SASLAuthenticator; +import org.apache.geronimo.javamail.util.CommandFailedException; +import org.apache.geronimo.javamail.util.InvalidCommandException; + +/** + * Base class for all mail Store/Transport connection. Centralizes management + * of a lot of common connection handling. Actual protcol-specific + * functions are handled at the subclass level. + */ +public class MailConnection { + /** + * constants for EOL termination + */ + protected static final char CR = '\r'; + protected static final char LF = '\n'; + + /** + * property keys for protocol properties. + */ + protected static final String MAIL_AUTH = "auth"; + protected static final String MAIL_PORT = "port"; + protected static final String MAIL_LOCALHOST = "localhost"; + protected static final String MAIL_STARTTLS_ENABLE = "starttls.enable"; + protected static final String MAIL_SSL_ENABLE = "ssl.enable"; + 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_SASL_MECHANISMS = "sasl.mechanisms"; + protected static final String MAIL_PLAIN_DISABLE = "auth.plain.disable"; + protected static final String MAIL_LOGIN_DISABLE = "auth.login.disable"; + protected static final String MAIL_FACTORY_CLASS = "socketFactory.class"; + protected static final String MAIL_FACTORY_FALLBACK = "socketFactory.fallback"; + protected static final String MAIL_FACTORY_PORT = "socketFactory.port"; + protected static final String MAIL_SSL_FACTORY_CLASS = "SSLsocketFactory.class"; + protected static final String MAIL_SSL_FACTORY_FALLBACK = "SSLsocketFactory.fallback"; + protected static final String MAIL_SSL_FACTORY_PORT = "SSLsocketFactory.port"; + protected static final String MAIL_LOCALADDRESS = "localaddress"; + protected static final String MAIL_LOCALPORT = "localport"; + protected static final String MAIL_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 String CAPABILITY_STARTTLS = "STARTTLS"; + + 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 mail Session we're associated with + protected Session session; + // The protocol we're implementing + protected String protocol; + // There are usually SSL and non-SSL versions of these protocols. This + // indicates which version we're using. + protected boolean sslConnection; + // This is the default port we should be using for making a connection. Each + // protocol (and each ssl version of the protocol) normally has a different default that + // should be used. + protected int defaultPort; + + // a wrapper around our session to provide easier lookup of protocol + // specific property values + protected ProtocolProperties props; + + // The target server host + protected String serverHost; + // The target server port + protected int serverPort; + + // the connection socket...can be a plain socket or SSLSocket, if TLS is being used. + protected Socket socket; + + // our local host name + protected InetAddress localAddress; + // our local port value + protected int localPort; + // our timeout value + protected int timeout; + + // our login username + protected String username; + // our login password + protected String password; + // our SASL security realm + protected String realm; + // our authorization id + protected String authid; + + // 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 other end of the connection pipeline. + protected OutputStream outputStream; + + // 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 List authentications; + // map of server extension arguments + protected Map capabilities; + // property list of authentication mechanisms + protected List mechanisms; + + + + protected MailConnection(ProtocolProperties props) + { + // this is our properties retriever utility, which will look up + // properties based on the appropriate "mail.protocol." prefix. + // this also holds other information we might need for access, such as + // the protocol name and the Session; + this.props = props; + this.protocol = props.getProtocol(); + this.session = props.getSession(); + this.sslConnection = props.getSSLConnection(); + this.defaultPort = props.getDefaultPort(); + + // initialize our debug settings from the session + debug = session.getDebug(); + debugStream = session.getDebugOut(); + } + + + /** + * Create a transport connection object and connect it to the + * target server. + * + * @exception MessagingException + */ + protected void getConnection() throws IOException, MessagingException + { + // We might have been passed a socket to connect with...if not, we need to create one of the correct type. + if (socket == null) { + // get the connection properties that control how we set this up. + getConnectionProperties(); + // if this is the SSL version of the protocol, we start with an SSLSocket + if (sslConnection) { + getConnectedSSLSocket(); + } + else + { + getConnectedSocket(); + } + } + // if we already have a socket, get some information from it and override what we've been passed. + else { + localPort = socket.getPort(); + localAddress = socket.getInetAddress(); + } + + // now set up the input/output streams. + getConnectionStreams(); + } + + /** + * Get common connection properties before creating a connection socket. + */ + protected void getConnectionProperties() { + + // there are several protocol properties that can be set to tune the created socket. We need to + // retrieve those bits before creating the socket. + timeout = props.getIntProperty(MAIL_TIMEOUT, -1); + localAddress = null; + // see if we have a local address override. + String localAddrProp = props.getProperty(MAIL_LOCALADDRESS); + if (localAddrProp != null) { + try { + localAddress = InetAddress.getByName(localAddrProp); + } catch (UnknownHostException e) { + // not much we can do if this fails. + } + } + + // check for a local port...default is to allow socket to choose. + localPort = props.getIntProperty(MAIL_LOCALPORT, 0); + } + + + /** + * Creates a connected socket + * + * @exception MessagingException + */ + protected void getConnectedSocket() throws IOException { + if (debug) { + debugOut("Attempting plain socket connection to server " + serverHost + ":" + serverPort); + } + + // check the properties that control how we connect. + getConnectionProperties(); + + // the socket factory can be specified via a session property. By default, we just directly + // instantiate a socket without using a factory. + String socketFactory = props.getProperty(MAIL_FACTORY_CLASS); + + // make sure the socket is nulled out to start + socket = null; + + // if there is no socket factory defined (normal), we just create a socket directly. + if (socketFactory == null) { + socket = new Socket(serverHost, serverPort, localAddress, localPort); + } + + else { + try { + int socketFactoryPort = props.getIntProperty(MAIL_FACTORY_PORT, -1); + + // we choose the port used by the socket based on overrides. + Integer portArg = new Integer(socketFactoryPort == -1 ? serverPort : 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[] { serverHost, 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[] { serverHost, 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 (props.getBooleanProperty(MAIL_FACTORY_FALLBACK, false)) { + if (debug) { + 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 + // 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 " + serverHost + ", " + serverPort); + ioe.initCause(e); + throw ioe; + } + } + } + // if we have a timeout value, set that before returning + if (timeout >= 0) { + socket.setSoTimeout(timeout); + } + } + + + /** + * Creates a connected SSL socket for an initial SSL connection. + * + * @exception MessagingException + */ + protected void getConnectedSSLSocket() throws IOException { + if (debug) { + 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")); + + // make sure this is null + socket = null; + + // we'll try this with potentially two different factories if we're allowed to fall back. + boolean fallback = props.getBooleanProperty(MAIL_SSL_FACTORY_FALLBACK, false); + + while (true) { + try { + if (debug) { + debugOut("Creating SSL socket using factory " + socketFactory); + } + + int socketFactoryPort = props.getIntProperty(MAIL_SSL_FACTORY_PORT, -1); + + // we choose the port used by the socket based on overrides. + Integer portArg = new Integer(socketFactoryPort == -1 ? serverPort : 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[] { serverHost, portArg, localAddress, new Integer(localPort) }; + socket = (Socket)createSocket.invoke(defFactory, createSocketArgs); + break; + } + 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[] { serverHost, portArg }; + socket = (Socket)createSocket.invoke(defFactory, createSocketArgs); + break; + } + } catch (Throwable e) { + // if we're allowed to fallback, then use the default factory and try this again. We only + // allow this to happen once. + if (fallback) { + if (debug) { + debugOut("First attempt at creating SSL socket failed, falling back to default factory"); + } + socketFactory = "javax.net.ssl.SSLSocketFactory"; + fallback = false; + continue; + } + // we have an exception. We're going to throw an IOException, which may require unwrapping + // or rewrapping the exception. + else { + // we have an exception from the reflection, so unwrap the base exception + if (e instanceof InvocationTargetException) { + e = ((InvocationTargetException)e).getTargetException(); + } + + if (debug) { + 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); + throw ioe; + } + } + } + // and set the timeout value + if (timeout >= 0) { + socket.setSoTimeout(timeout); + } + } + + + /** + * Switch the connection to using TLS level security, + * switching to an SSL socket. + */ + protected void getConnectedTLSSocket() throws MessagingException { + if (debug) { + debugOut("Attempting to negotiate STARTTLS with server " + serverHost); + } + // it worked, now switch the socket into TLS mode + try { + + // we use the same target and port as the current connection. + String host = socket.getInetAddress().getHostName(); + int port = socket.getPort(); + + // the socket factory can be specified via a session property. By default, we use + // the native SSL factory. + String socketFactory = props.getProperty(MAIL_SSL_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory"); + + // 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 we need to invoke createSocket() + Class[] createSocketSig = new Class[] { Socket.class, String.class, Integer.TYPE, Boolean.TYPE }; + Method createSocket = factoryClass.getMethod("createSocket", createSocketSig); + + Object[] createSocketArgs = new Object[] { socket, host, new Integer(port), Boolean.TRUE }; + + // and finally create the socket + Socket sslSocket = (Socket)createSocket.invoke(defFactory, createSocketArgs); + + // if this is an instance of SSLSocket (very common), try setting the protocol to be + // "TLSv1". If this is some other class because of a factory override, we'll just have to + // accept that things will work. + if (sslSocket instanceof SSLSocket) { + ((SSLSocket)sslSocket).setEnabledProtocols(new String[] {"TLSv1"} ); + ((SSLSocket)sslSocket).setUseClientMode(true); + ((SSLSocket)sslSocket).startHandshake(); + } + + + // this is our active socket now + socket = sslSocket; + getConnectionStreams(); + } + catch (Exception e) { + if (debug) { + debugOut("Failure attempting to convert connection to TLS", e); + } + throw new MessagingException("Unable to convert connection to SSL", e); + } + } + + + /** + * Set up the input and output streams for server communications once the + * socket connection has been made. + * + * @exception MessagingException + */ + protected void getConnectionStreams() throws MessagingException, IOException { + // and finally, as a last step, replace our input streams with the secure ones. + // now set up the input/output streams. + inputStream = new TraceInputStream(socket.getInputStream(), debugStream, debug, props.getBooleanProperty( + MAIL_ENCODE_TRACE, false)); + outputStream = new TraceOutputStream(socket.getOutputStream(), debugStream, debug, props.getBooleanProperty( + MAIL_ENCODE_TRACE, false)); + } + + + /** + * Close the server connection at termination. + */ + public void closeServerConnection() + { + try { + socket.close(); + } catch (IOException ignored) { + } + + socket = null; + inputStream = null; + outputStream = null; + } + + + /** + * Verify that we have a good connection before + * attempting to send a command. + * + * @exception MessagingException + */ + protected void checkConnected() throws MessagingException { + if (socket == null || !socket.isConnected()) { + throw new MessagingException("no connection"); + } + } + + + /** + * Retrieve the SASL realm used for DIGEST-MD5 authentication. + * This will either be explicitly set, or retrieved using the + * mail.imap.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 = props.getProperty(MAIL_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; + } + + + /** + * Get a list of the SASL mechanisms we're configured to accept. + * + * @return A list of mechanisms we're allowed to use. + */ + protected List getSaslMechanisms() { + if (mechanisms == null) { + mechanisms = new ArrayList(); + String mechList = props.getProperty(MAIL_SASL_MECHANISMS); + if (mechList != null) { + // the mechanisms are a blank or comma-separated list + StringTokenizer tokenizer = new StringTokenizer(mechList, " ,"); + + while (tokenizer.hasMoreTokens()) { + String mech = tokenizer.nextToken().toUpperCase(); + mechanisms.add(mech); + } + } + } + return mechanisms; + } + + + /** + * Get the list of authentication mechanisms the server + * is supposed to support. + * + * @return A list of the server supported authentication + * mechanisms. + */ + protected List getServerMechanisms() { + return authentications; + } + + + /** + * Merge the configured SASL mechanisms with the capabilities that the + * server has indicated it supports, returning a merged list that can + * be used for selecting a mechanism. + * + * @return A List representing the intersection of the configured list and the + * capabilities list. + */ + protected List selectSaslMechanisms() { + List configured = getSaslMechanisms(); + List supported = getServerMechanisms(); + + // if not restricted, then we'll select from anything supported. + if (configured.isEmpty()) { + return supported; + } + + List merged = new ArrayList(); + + // we might need a subset of the supported ones + for (int i = 0; i < configured.size(); i++) { + // if this is in both lists, add to the merged one. + String mech = (String)configured.get(i); + if (supported.contains(mech)) { + merged.add(mech); + } + } + return merged; + } + + + /** + * Process SASL-type authentication. + * + * @return An authenticator to process the login challenge/response handling. + * @exception MessagingException + */ + protected ClientAuthenticator getLoginAuthenticator() throws MessagingException { + + // get the list of mechanisms we're allowed to use. + List mechs = selectSaslMechanisms(); + + try { + String[] mechArray = (String[])mechs.toArray(new String[0]); + // create a SASLAuthenticator, if we can. A failure likely indicates we're not + // running on a Java 5 VM, and the Sasl API isn't available. + return new SASLAuthenticator(mechArray, session.getProperties(), protocol, serverHost, getSASLRealm(), authid, username, password); + } catch (Throwable e) { + } + + + // now go through the progression of mechanisms we support, from the most secure to the + // least secure. + + if (mechs.contains(AUTHENTICATION_DIGESTMD5)) { + return new DigestMD5Authenticator(serverHost, username, password, getSASLRealm()); + } + else if (mechs.contains(AUTHENTICATION_CRAMMD5)) { + return new CramMD5Authenticator(username, password); + } + else if (mechs.contains(AUTHENTICATION_LOGIN)) { + return new LoginAuthenticator(username, password); + } + else if (mechs.contains(AUTHENTICATION_PLAIN)) { + return new PlainAuthenticator(username, password); + } + else { + // can't find a mechanism we support in common + return null; + } + } + + + /** + * Internal debug output routine. + * + * @param value The string value to output. + */ + protected void debugOut(String message) { + debugStream.println("IMAPStore 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); + } + + + /** + * Test if this connection has a given capability. + * + * @param capability The capability name. + * + * @return true if this capability is in the list, false for a mismatch. + */ + public boolean hasCapability(String capability) { + return capabilities.containsKey(capability); + } + + /** + * Get the capabilities map. + * + * @return The capabilities map for the connection. + */ + public Map getCapabilities() { + return capabilities; + } + + + /** + * Test if the server supports a given mechanism. + * + * @param mech The mechanism name. + * + * @return true if the server has asserted support for the named + * mechanism. + */ + public boolean supportsMechanism(String mech) { + return authentications.contains(mech); + } +} Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ProtocolProperties.java URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ProtocolProperties.java?rev=594520&view=auto ============================================================================== --- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ProtocolProperties.java (added) +++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ProtocolProperties.java Tue Nov 13 04:57:39 2007 @@ -0,0 +1,276 @@ +/** + * 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.util; + +import java.util.Properties; + +import javax.mail.Session; + +/** + * Interface for providing access to protocol specific properties to + * utility classes. + */ +public class ProtocolProperties { + // the protocol we're working with. + protected String protocol; + // a preconstructed prefix string to reduce concatenation operations. + protected String protocolPrefix; + // the Session that's the source of all of the properties + protected Session session; + // the sslConnection property. This indicates this protocol is to use SSL for + // all communications with the server. + protected boolean sslConnection; + // the default port property. The default port differs with the protocol + // and the sslConnection property. + protected int defaultPort; + + + public ProtocolProperties(Session session, String protocol, boolean sslConnection, int defaultPort) { + this.session = session; + this.protocol = protocol; + this.sslConnection = sslConnection; + this.defaultPort = defaultPort; + // this helps avoid a lot of concatentates when retrieving properties. + protocolPrefix = "mail." + protocol + "."; + } + + + /** + * Retrieve the Session associated with this property bundle instance. + * + * @return A Session object that's the source of the accessed properties. + */ + public Session getSession() { + return session; + } + + + /** + * Retrieve the name of the protocol used to access properties. + * + * @return The protocol String name. + */ + public String getProtocol() { + return protocol; + } + + + /** + * Retrieve the SSL Connection flag for this protocol; + * + * @return true if an SSL connection is required, false otherwise. + */ + public boolean getSSLConnection() { + return sslConnection; + } + + + /** + * Return the default port to use with this connection. + * + * @return The default port value. + */ + public int getDefaultPort() { + return defaultPort; + } + + + /** + * 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). + */ + public 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 + String fullName = protocolPrefix + 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). + */ + public 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 + String fullName = protocolPrefix + name; + String value = session.getProperty(fullName); + if (value == null) { + value = defaultValue; + } + return value; + } + + + /** + * 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. + */ + public int getIntProperty(String name, int defaultValue) + { + // retrieve the property + String value = getProperty(name); + // return the default value if not set. + if (value == null) { + return defaultValue; + } + return Integer.parseInt(value); + } + + + /** + * 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 + */ + public boolean getBooleanProperty(String name, boolean defaultValue) + { + // retrieve the property + String value = getProperty(name); + // return the default value if not set. + if (value == null) { + return defaultValue; + } + // just do a single test for true. + if ("true".equals(value)) { + return true; + } + // return false for anything other than true + return false; + } + + + /** + * Get a property associated with this mail session. Session + * properties all begin with "mail." + * + * @param name The name of the property. + * + * @return The property value (returns null if the property has not been set). + */ + public String getSessionProperty(String name) { + // the name we're given is the least qualified part of the name. + // We construct the full property name + // using the protocol + String fullName = "mail." + 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). + */ + public String getSessionProperty(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 + String fullName = "mail." + name; + String value = session.getProperty(fullName); + if (value == null) { + value = defaultValue; + } + return value; + } + + + /** + * 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. + */ + public int getIntSessionProperty(String name, int defaultValue) + { + // retrieve the property + String value = getSessionProperty(name); + // return the default value if not set. + if (value == null) { + return defaultValue; + } + return Integer.parseInt(value); + } + + + /** + * 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 + */ + public boolean getBooleanSessionProperty(String name, boolean defaultValue) + { + // retrieve the property + String value = getSessionProperty(name); + // return the default value if not set. + if (value == null) { + return defaultValue; + } + // just do a single test for true. + if ("true".equals(value)) { + return true; + } + // return false for anything other than true + return false; + } + + /** + * Get the complete set of properties associated with this Session. + * + * @return The Session properties bundle. + */ + public Properties getProperties() { + return session.getProperties(); + } + +} Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ProtocolProperties.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ProtocolProperties.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ProtocolProperties.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ResponseFormatException.java URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ResponseFormatException.java?rev=594520&view=auto ============================================================================== --- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ResponseFormatException.java (added) +++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ResponseFormatException.java Tue Nov 13 04:57:39 2007 @@ -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.util; + +import javax.mail.MessagingException; + +public class ResponseFormatException extends MessagingException { + public ResponseFormatException() { + super(); + } + + public ResponseFormatException(String message) { + super(message); + } + + public ResponseFormatException(String message, Exception cause) { + super(message, cause); + } +} Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ResponseFormatException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ResponseFormatException.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/ResponseFormatException.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers?rev=594520&r1=594519&r2=594520&view=diff ============================================================================== --- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers (original) +++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers Tue Nov 13 04:57:39 2007 @@ -35,4 +35,6 @@ protocol=nntp-post; type=transport; class=org.apache.geronimo.javamail.transport.nntp.NNTPTransport; 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=pop3; type=store; class=org.apache.geronimo.javamail.store.pop3.POP3Store; 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 +protocol=imaps; type=store; class=org.apache.geronimo.javamail.store.imap.IMAPSSLStore; vendor=Apache Software Foundation; version=1.0 Modified: geronimo/javamail/trunk/geronimo-javamail_1.4/pom.xml URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/pom.xml?rev=594520&r1=594519&r2=594520&view=diff ============================================================================== --- geronimo/javamail/trunk/geronimo-javamail_1.4/pom.xml (original) +++ geronimo/javamail/trunk/geronimo-javamail_1.4/pom.xml Tue Nov 13 04:57:39 2007 @@ -59,7 +59,7 @@ org.apache.geronimo.specs geronimo-javamail_1.4_spec - 1.1 + 1.2-SNAPSHOT @@ -67,6 +67,31 @@ + + org.apache.maven.plugins + maven-enforcer-plugin + + + validate + + enforce + + + + + + [1.5,1.6) + + + + + [2.0.5,) + + + + + + org.apache.maven.plugins maven-compiler-plugin