diff options
author | Eric Erfanian <erfanian@google.com> | 2017-03-15 14:41:07 -0700 |
---|---|---|
committer | Eric Erfanian <erfanian@google.com> | 2017-03-15 16:24:23 -0700 |
commit | d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9 (patch) | |
tree | b54abbb51fb7d66e7755a1fbb5db023ff601090b /java/com/android/voicemailomtp/mail/MailTransport.java | |
parent | 30436e7e6d3f2c8755a91b2b6222b74d465a9e87 (diff) |
Update Dialer source from latest green build.
* Refactor voicemail component
* Add new enriched calling components
Test: treehugger, manual aosp testing
Change-Id: I521a0f86327d4b42e14d93927c7d613044ed5942
Diffstat (limited to 'java/com/android/voicemailomtp/mail/MailTransport.java')
-rw-r--r-- | java/com/android/voicemailomtp/mail/MailTransport.java | 344 |
1 files changed, 0 insertions, 344 deletions
diff --git a/java/com/android/voicemailomtp/mail/MailTransport.java b/java/com/android/voicemailomtp/mail/MailTransport.java deleted file mode 100644 index 3bf851fd8..000000000 --- a/java/com/android/voicemailomtp/mail/MailTransport.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2015 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.voicemailomtp.mail; - -import android.content.Context; -import android.net.Network; -import android.support.annotation.VisibleForTesting; -import com.android.voicemailomtp.OmtpEvents; -import com.android.voicemailomtp.imap.ImapHelper; -import com.android.voicemailomtp.mail.store.ImapStore; -import com.android.voicemailomtp.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.util.ArrayList; -import java.util.List; -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; - -/** - * Make connection and perform operations on mail server by reading and writing lines. - */ -public class MailTransport { - private static final String TAG = "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 Context mContext; - private final ImapHelper mImapHelper; - private final Network mNetwork; - private final String mHost; - private final int mPort; - private Socket mSocket; - private BufferedInputStream mIn; - private BufferedOutputStream mOut; - private final int mFlags; - private SocketCreator mSocketCreator; - private InetSocketAddress mAddress; - - public MailTransport(Context context, ImapHelper imapHelper, Network network, String address, - int port, int flags) { - mContext = context; - mImapHelper = imapHelper; - mNetwork = network; - mHost = address; - mPort = port; - mFlags = flags; - } - - /** - * Returns a new transport, using the current transport as a model. The new transport is - * configured identically, but not opened or connected in any way. - */ - @Override - public MailTransport clone() { - return new MailTransport(mContext, mImapHelper, mNetwork, mHost, mPort, mFlags); - } - - public boolean canTrySslSecurity() { - return (mFlags & ImapStore.FLAG_SSL) != 0; - } - - public boolean canTrustAllCertificates() { - return (mFlags & ImapStore.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 { - LogUtils.d(TAG, "*** IMAP open " + mHost + ":" + String.valueOf(mPort)); - - List<InetSocketAddress> socketAddresses = new ArrayList<InetSocketAddress>(); - - if (mNetwork == null) { - socketAddresses.add(new InetSocketAddress(mHost, mPort)); - } else { - try { - InetAddress[] inetAddresses = mNetwork.getAllByName(mHost); - if (inetAddresses.length == 0) { - throw new MessagingException(MessagingException.IOERROR, - "Host name " + mHost + "cannot be resolved on designated network"); - } - for (int i = 0; i < inetAddresses.length; i++) { - socketAddresses.add(new InetSocketAddress(inetAddresses[i], mPort)); - } - } catch (IOException ioe) { - LogUtils.d(TAG, ioe.toString()); - mImapHelper.handleEvent(OmtpEvents.DATA_CANNOT_RESOLVE_HOST_ON_NETWORK); - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - } - - boolean success = false; - while (socketAddresses.size() > 0) { - mSocket = createSocket(); - try { - mAddress = socketAddresses.remove(0); - mSocket.connect(mAddress, SOCKET_CONNECT_TIMEOUT); - - if (canTrySslSecurity()) { - /* - SSLSocket cannot be created with a connection timeout, so instead of doing a - direct SSL connection, we connect with a normal connection and upgrade it into - SSL - */ - reopenTls(); - } else { - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - mSocket.setSoTimeout(SOCKET_READ_TIMEOUT); - } - success = true; - return; - } catch (IOException ioe) { - LogUtils.d(TAG, ioe.toString()); - if (socketAddresses.size() == 0) { - // Only throw an error when there are no more sockets to try. - mImapHelper.handleEvent(OmtpEvents.DATA_ALL_SOCKET_CONNECTION_FAILED); - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - } finally { - if (!success) { - try { - mSocket.close(); - mSocket = null; - } catch (IOException ioe) { - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - - } - } - } - } - - // For testing. We need something that can replace the behavior of "new Socket()" - @VisibleForTesting - interface SocketCreator { - - Socket createSocket() throws MessagingException; - } - - @VisibleForTesting - void setSocketCreator(SocketCreator creator) { - mSocketCreator = creator; - } - - protected Socket createSocket() throws MessagingException { - if (mSocketCreator != null) { - return mSocketCreator.createSocket(); - } - - if (mNetwork == null) { - LogUtils.v(TAG, "createSocket: network not specified"); - return new Socket(); - } - - try { - LogUtils.v(TAG, "createSocket: network specified"); - return mNetwork.getSocketFactory().createSocket(); - } catch (IOException ioe) { - LogUtils.d(TAG, ioe.toString()); - throw new MessagingException(MessagingException.IOERROR, ioe.toString()); - } - } - - /** - * Attempts to reopen a normal connection into a TLS connection. - */ - public void reopenTls() throws MessagingException { - try { - LogUtils.d(TAG, "open: converting to TLS socket"); - mSocket = HttpsURLConnection.getDefaultSSLSocketFactory() - .createSocket(mSocket, mAddress.getHostName(), mAddress.getPort(), true); - // After the socket connects to an SSL server, confirm that the hostname is as - // expected - if (!canTrustAllCertificates()) { - verifyHostname(mSocket, mHost); - } - mSocket.setSoTimeout(SOCKET_READ_TIMEOUT); - mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); - mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512); - - } catch (SSLException e) { - LogUtils.d(TAG, e.toString()); - throw new CertificateValidationException(e.getMessage(), e); - } catch (IOException ioe) { - LogUtils.d(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. 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 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) { - mImapHelper.handleEvent(OmtpEvents.DATA_CANNOT_ESTABLISH_SSL_SESSION); - 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)) { - mImapHelper.handleEvent(OmtpEvents.DATA_SSL_INVALID_HOST_NAME); - throw new SSLPeerUnverifiedException("Certificate hostname not useable for server: " - + session.getPeerPrincipal()); - } - } - - 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 String getHost() { - return mHost; - } - - 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 (sensitiveReplacement != null) { - LogUtils.d(TAG, ">>> " + sensitiveReplacement); - } else { - LogUtils.d(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) { - LogUtils.d(TAG, "End of stream reached while trying to read line."); - } - String ret = sb.toString(); - if (loggable) { - LogUtils.d(TAG, "<<< " + ret); - } - return ret; - } -} |