diff options
Diffstat (limited to 'src/com/android/email/mail/transport')
-rw-r--r-- | src/com/android/email/mail/transport/DiscourseLogger.java | 119 | ||||
-rw-r--r-- | src/com/android/email/mail/transport/MailTransport.java | 320 |
2 files changed, 0 insertions, 439 deletions
diff --git a/src/com/android/email/mail/transport/DiscourseLogger.java b/src/com/android/email/mail/transport/DiscourseLogger.java deleted file mode 100644 index 67f4e115b..000000000 --- a/src/com/android/email/mail/transport/DiscourseLogger.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed 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 com.android.email.mail.transport; - -import com.android.emailcommon.Logging; -import com.android.mail.utils.LogUtils; - -import java.util.ArrayList; - -/** - * A class to keep last N of lines sent to the server and responses received from the server. - * They are sent to logcat when {@link #logLastDiscourse} is called. - * - * <p>This class is used to log the recent network activities when a response parser crashes. - */ -public class DiscourseLogger { - private final int mBufferSize; - private String[] mBuffer; - private int mPos; - private final StringBuilder mReceivingLine = new StringBuilder(100); - - public DiscourseLogger(int bufferSize) { - mBufferSize = bufferSize; - initBuffer(); - } - - private void initBuffer() { - mBuffer = new String[mBufferSize]; - } - - /** Add a single line to {@link #mBuffer}. */ - private void addLine(String s) { - mBuffer[mPos] = s; - mPos++; - if (mPos >= mBufferSize) { - mPos = 0; - } - } - - private void addReceivingLineToBuffer() { - if (mReceivingLine.length() > 0) { - addLine(mReceivingLine.toString()); - mReceivingLine.delete(0, Integer.MAX_VALUE); - } - } - - /** - * Store a single byte received from the server in {@link #mReceivingLine}. When LF is - * received, the content of {@link #mReceivingLine} is added to {@link #mBuffer}. - */ - public void addReceivedByte(int b) { - if (0x20 <= b && b <= 0x7e) { // Append only printable ASCII chars. - mReceivingLine.append((char) b); - } else if (b == '\n') { // LF - addReceivingLineToBuffer(); - } else if (b == '\r') { // CR - } else { - final String hex = "00" + Integer.toHexString(b); - mReceivingLine.append("\\x" + hex.substring(hex.length() - 2, hex.length())); - } - } - - /** Add a line sent to the server to {@link #mBuffer}. */ - public void addSentCommand(String command) { - addLine(command); - } - - /** @return the contents of {@link #mBuffer} as a String array. */ - /* package for testing */ String[] getLines() { - addReceivingLineToBuffer(); - - ArrayList<String> list = new ArrayList<String>(); - - final int start = mPos; - int pos = mPos; - do { - String s = mBuffer[pos]; - if (s != null) { - list.add(s); - } - pos = (pos + 1) % mBufferSize; - } while (pos != start); - - String[] ret = new String[list.size()]; - list.toArray(ret); - return ret; - } - - /** - * Log the contents of the {@link mBuffer}, and clears it out. (So it's okay to call this - * method successively more than once. There will be no duplicate log.) - */ - public void logLastDiscourse() { - String[] lines = getLines(); - if (lines.length == 0) { - return; - } - - LogUtils.w(Logging.LOG_TAG, "Last network activities:"); - for (String r : getLines()) { - LogUtils.w(Logging.LOG_TAG, "%s", r); - } - initBuffer(); - } -} diff --git a/src/com/android/email/mail/transport/MailTransport.java b/src/com/android/email/mail/transport/MailTransport.java deleted file mode 100644 index 213fbfc99..000000000 --- a/src/com/android/email/mail/transport/MailTransport.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed 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 com.android.email.mail.transport; - -import android.content.Context; - -import com.android.email.DebugUtils; -import com.android.emailcommon.Logging; -import com.android.emailcommon.mail.CertificateValidationException; -import com.android.emailcommon.mail.MessagingException; -import com.android.emailcommon.provider.HostAuth; -import com.android.emailcommon.utility.SSLUtils; -import com.android.mail.utils.LogUtils; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.SocketException; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; - -public class MailTransport { - - // TODO protected eventually - /*protected*/ public static final int SOCKET_CONNECT_TIMEOUT = 10000; - /*protected*/ public static final int SOCKET_READ_TIMEOUT = 60000; - - private static final HostnameVerifier HOSTNAME_VERIFIER = - HttpsURLConnection.getDefaultHostnameVerifier(); - - private final String mDebugLabel; - private final Context mContext; - protected final HostAuth mHostAuth; - - private Socket mSocket; - private InputStream mIn; - private OutputStream mOut; - - public MailTransport(Context context, String debugLabel, HostAuth hostAuth) { - super(); - mContext = context; - mDebugLabel = debugLabel; - mHostAuth = hostAuth; - } - - /** - * Returns a new transport, using the current transport as a model. The new transport is - * configured identically (as if {@link #setSecurity(int, boolean)}, {@link #setPort(int)} - * and {@link #setHost(String)} were invoked), but not opened or connected in any way. - */ - @Override - public MailTransport clone() { - return new MailTransport(mContext, mDebugLabel, mHostAuth); - } - - public String getHost() { - return mHostAuth.mAddress; - } - - public int getPort() { - return mHostAuth.mPort; - } - - public boolean canTrySslSecurity() { - return (mHostAuth.mFlags & HostAuth.FLAG_SSL) != 0; - } - - public boolean canTryTlsSecurity() { - return (mHostAuth.mFlags & HostAuth.FLAG_TLS) != 0; - } - - public boolean canTrustAllCertificates() { - return (mHostAuth.mFlags & HostAuth.FLAG_TRUST_ALL) != 0; - } - - /** - * Attempts to open a connection using the Uri supplied for connection parameters. Will attempt - * an SSL connection if indicated. - */ - public void open() throws MessagingException, CertificateValidationException { - if (DebugUtils.DEBUG) { - LogUtils.d(Logging.LOG_TAG, "*** " + mDebugLabel + " open " + - getHost() + ":" + String.valueOf(getPort())); - } - - try { - SocketAddress socketAddress = new InetSocketAddress(getHost(), getPort()); - if (canTrySslSecurity()) { - mSocket = SSLUtils.getSSLSocketFactory( - mContext, mHostAuth, canTrustAllCertificates()).createSocket(); - } else { - mSocket = new Socket(); - } - mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); - // After the socket connects to an SSL server, confirm that the hostname is as expected - if (canTrySslSecurity() && !canTrustAllCertificates()) { - verifyHostname(mSocket, getHost()); - } - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - mSocket.setSoTimeout(SOCKET_READ_TIMEOUT); - } catch (SSLException e) { - if (DebugUtils.DEBUG) { - LogUtils.d(Logging.LOG_TAG, e.toString()); - } - throw new CertificateValidationException(e.getMessage(), e); - } catch (IOException ioe) { - if (DebugUtils.DEBUG) { - LogUtils.d(Logging.LOG_TAG, ioe.toString()); - } - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } catch (IllegalArgumentException iae) { - if (DebugUtils.DEBUG) { - LogUtils.d(Logging.LOG_TAG, iae.toString()); - } - throw new MessagingException(MessagingException.UNSPECIFIED_EXCEPTION, iae.toString()); - } - } - - /** - * Attempts to reopen a TLS connection using the Uri supplied for connection parameters. - * - * NOTE: No explicit hostname verification is required here, because it's handled automatically - * by the call to createSocket(). - * - * TODO should we explicitly close the old socket? This seems funky to abandon it. - */ - public void reopenTls() throws MessagingException { - try { - mSocket = SSLUtils.getSSLSocketFactory(mContext, mHostAuth, canTrustAllCertificates()) - .createSocket(mSocket, getHost(), getPort(), true); - mSocket.setSoTimeout(SOCKET_READ_TIMEOUT); - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - - } catch (SSLException e) { - if (DebugUtils.DEBUG) { - LogUtils.d(Logging.LOG_TAG, e.toString()); - } - throw new CertificateValidationException(e.getMessage(), e); - } catch (IOException ioe) { - if (DebugUtils.DEBUG) { - LogUtils.d(Logging.LOG_TAG, ioe.toString()); - } - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - } - - /** - * Lightweight version of SSLCertificateSocketFactory.verifyHostname, which provides this - * service but is not in the public API. - * - * Verify the hostname of the certificate used by the other end of a - * connected socket. You MUST call this if you did not supply a hostname - * to SSLCertificateSocketFactory.createSocket(). It is harmless to call this method - * redundantly if the hostname has already been verified. - * - * <p>Wildcard certificates are allowed to verify any matching hostname, - * so "foo.bar.example.com" is verified if the peer has a certificate - * for "*.example.com". - * - * @param socket An SSL socket which has been connected to a server - * @param hostname The expected hostname of the remote server - * @throws IOException if something goes wrong handshaking with the server - * @throws SSLPeerUnverifiedException if the server cannot prove its identity - */ - private static void verifyHostname(Socket socket, String hostname) throws IOException { - // The code at the start of OpenSSLSocketImpl.startHandshake() - // ensures that the call is idempotent, so we can safely call it. - SSLSocket ssl = (SSLSocket) socket; - ssl.startHandshake(); - - SSLSession session = ssl.getSession(); - if (session == null) { - throw new SSLException("Cannot verify SSL socket without session"); - } - // TODO: Instead of reporting the name of the server we think we're connecting to, - // we should be reporting the bad name in the certificate. Unfortunately this is buried - // in the verifier code and is not available in the verifier API, and extracting the - // CN & alts is beyond the scope of this patch. - if (!HOSTNAME_VERIFIER.verify(hostname, session)) { - throw new SSLPeerUnverifiedException( - "Certificate hostname not useable for server: " + hostname); - } - } - - /** - * Get the socket timeout. - * @return the read timeout value in milliseconds - * @throws SocketException - */ - public int getSoTimeout() throws SocketException { - return mSocket.getSoTimeout(); - } - - /** - * Set the socket timeout. - * @param timeoutMilliseconds the read timeout value if greater than {@code 0}, or - * {@code 0} for an infinite timeout. - */ - public void setSoTimeout(int timeoutMilliseconds) throws SocketException { - mSocket.setSoTimeout(timeoutMilliseconds); - } - - public boolean isOpen() { - return (mIn != null && mOut != null && - mSocket != null && mSocket.isConnected() && !mSocket.isClosed()); - } - - /** - * Close the connection. MUST NOT return any exceptions - must be "best effort" and safe. - */ - public void close() { - try { - mIn.close(); - } catch (Exception e) { - // May fail if the connection is already closed. - } - try { - mOut.close(); - } catch (Exception e) { - // May fail if the connection is already closed. - } - try { - mSocket.close(); - } catch (Exception e) { - // May fail if the connection is already closed. - } - mIn = null; - mOut = null; - mSocket = null; - } - - public InputStream getInputStream() { - return mIn; - } - - public OutputStream getOutputStream() { - return mOut; - } - - /** - * Writes a single line to the server using \r\n termination. - */ - public void writeLine(String s, String sensitiveReplacement) throws IOException { - if (DebugUtils.DEBUG) { - if (sensitiveReplacement != null && !Logging.DEBUG_SENSITIVE) { - LogUtils.d(Logging.LOG_TAG, ">>> " + sensitiveReplacement); - } else { - LogUtils.d(Logging.LOG_TAG, ">>> " + s); - } - } - - OutputStream out = getOutputStream(); - out.write(s.getBytes()); - out.write('\r'); - out.write('\n'); - out.flush(); - } - - /** - * Reads a single line from the server, using either \r\n or \n as the delimiter. The - * delimiter char(s) are not included in the result. - */ - public String readLine(boolean loggable) throws IOException { - StringBuffer sb = new StringBuffer(); - InputStream in = getInputStream(); - int d; - while ((d = in.read()) != -1) { - if (((char)d) == '\r') { - continue; - } else if (((char)d) == '\n') { - break; - } else { - sb.append((char)d); - } - } - if (d == -1 && DebugUtils.DEBUG) { - LogUtils.d(Logging.LOG_TAG, "End of stream reached while trying to read line."); - } - String ret = sb.toString(); - if (loggable && DebugUtils.DEBUG) { - LogUtils.d(Logging.LOG_TAG, "<<< " + ret); - } - return ret; - } - - public InetAddress getLocalAddress() { - if (isOpen()) { - return mSocket.getLocalAddress(); - } else { - return null; - } - } -} |