15c523858385176c33a7456bb84035de78552d22dMarc Blank/*
25c523858385176c33a7456bb84035de78552d22dMarc Blank * Copyright (C) 2011 The Android Open Source Project
35c523858385176c33a7456bb84035de78552d22dMarc Blank *
45c523858385176c33a7456bb84035de78552d22dMarc Blank * Licensed under the Apache License, Version 2.0 (the "License");
55c523858385176c33a7456bb84035de78552d22dMarc Blank * you may not use this file except in compliance with the License.
65c523858385176c33a7456bb84035de78552d22dMarc Blank * You may obtain a copy of the License at
75c523858385176c33a7456bb84035de78552d22dMarc Blank *
85c523858385176c33a7456bb84035de78552d22dMarc Blank *      http://www.apache.org/licenses/LICENSE-2.0
95c523858385176c33a7456bb84035de78552d22dMarc Blank *
105c523858385176c33a7456bb84035de78552d22dMarc Blank * Unless required by applicable law or agreed to in writing, software
115c523858385176c33a7456bb84035de78552d22dMarc Blank * distributed under the License is distributed on an "AS IS" BASIS,
125c523858385176c33a7456bb84035de78552d22dMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135c523858385176c33a7456bb84035de78552d22dMarc Blank * See the License for the specific language governing permissions and
145c523858385176c33a7456bb84035de78552d22dMarc Blank * limitations under the License.
155c523858385176c33a7456bb84035de78552d22dMarc Blank */
165c523858385176c33a7456bb84035de78552d22dMarc Blank
175c523858385176c33a7456bb84035de78552d22dMarc Blankpackage com.android.email.mail.store;
185c523858385176c33a7456bb84035de78552d22dMarc Blank
195c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.text.TextUtils;
205c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.util.Log;
215c523858385176c33a7456bb84035de78552d22dMarc Blank
22bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.Email;
23bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.mail.Transport;
245c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.mail.store.ImapStore.ImapException;
255c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.mail.store.imap.ImapConstants;
265c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.mail.store.imap.ImapList;
275c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.mail.store.imap.ImapResponse;
285c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.mail.store.imap.ImapResponseParser;
295c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.mail.store.imap.ImapUtility;
305c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.mail.transport.DiscourseLogger;
315c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.mail.transport.MailTransport;
325c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.Logging;
335c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.mail.AuthenticationFailedException;
345c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.mail.CertificateValidationException;
355c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.mail.MessagingException;
365c523858385176c33a7456bb84035de78552d22dMarc Blank
375c523858385176c33a7456bb84035de78552d22dMarc Blankimport java.io.IOException;
385c523858385176c33a7456bb84035de78552d22dMarc Blankimport java.util.ArrayList;
395c523858385176c33a7456bb84035de78552d22dMarc Blankimport java.util.Collections;
405c523858385176c33a7456bb84035de78552d22dMarc Blankimport java.util.List;
415c523858385176c33a7456bb84035de78552d22dMarc Blankimport java.util.concurrent.atomic.AtomicInteger;
425c523858385176c33a7456bb84035de78552d22dMarc Blank
435c523858385176c33a7456bb84035de78552d22dMarc Blankimport javax.net.ssl.SSLException;
445c523858385176c33a7456bb84035de78552d22dMarc Blank
455c523858385176c33a7456bb84035de78552d22dMarc Blank/**
465c523858385176c33a7456bb84035de78552d22dMarc Blank * A cacheable class that stores the details for a single IMAP connection.
475c523858385176c33a7456bb84035de78552d22dMarc Blank */
485c523858385176c33a7456bb84035de78552d22dMarc Blankclass ImapConnection {
495c523858385176c33a7456bb84035de78552d22dMarc Blank    // Always check in FALSE
505c523858385176c33a7456bb84035de78552d22dMarc Blank    private static final boolean DEBUG_FORCE_SEND_ID = false;
515c523858385176c33a7456bb84035de78552d22dMarc Blank
525c523858385176c33a7456bb84035de78552d22dMarc Blank    /** ID capability per RFC 2971*/
535c523858385176c33a7456bb84035de78552d22dMarc Blank    public static final int CAPABILITY_ID        = 1 << 0;
545c523858385176c33a7456bb84035de78552d22dMarc Blank    /** NAMESPACE capability per RFC 2342 */
555c523858385176c33a7456bb84035de78552d22dMarc Blank    public static final int CAPABILITY_NAMESPACE = 1 << 1;
565c523858385176c33a7456bb84035de78552d22dMarc Blank    /** STARTTLS capability per RFC 3501 */
575c523858385176c33a7456bb84035de78552d22dMarc Blank    public static final int CAPABILITY_STARTTLS  = 1 << 2;
585c523858385176c33a7456bb84035de78552d22dMarc Blank    /** UIDPLUS capability per RFC 4315 */
595c523858385176c33a7456bb84035de78552d22dMarc Blank    public static final int CAPABILITY_UIDPLUS   = 1 << 3;
605c523858385176c33a7456bb84035de78552d22dMarc Blank
615c523858385176c33a7456bb84035de78552d22dMarc Blank    /** The capabilities supported; a set of CAPABILITY_* values. */
625c523858385176c33a7456bb84035de78552d22dMarc Blank    private int mCapabilities;
635c523858385176c33a7456bb84035de78552d22dMarc Blank    private static final String IMAP_REDACTED_LOG = "[IMAP command redacted]";
64bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook    Transport mTransport;
655c523858385176c33a7456bb84035de78552d22dMarc Blank    private ImapResponseParser mParser;
665c523858385176c33a7456bb84035de78552d22dMarc Blank    private ImapStore mImapStore;
675c523858385176c33a7456bb84035de78552d22dMarc Blank    private String mUsername;
685c523858385176c33a7456bb84035de78552d22dMarc Blank    private String mLoginPhrase;
695c523858385176c33a7456bb84035de78552d22dMarc Blank    private String mIdPhrase = null;
705c523858385176c33a7456bb84035de78552d22dMarc Blank    /** # of command/response lines to log upon crash. */
715c523858385176c33a7456bb84035de78552d22dMarc Blank    private static final int DISCOURSE_LOGGER_SIZE = 64;
725c523858385176c33a7456bb84035de78552d22dMarc Blank    private final DiscourseLogger mDiscourse = new DiscourseLogger(DISCOURSE_LOGGER_SIZE);
735c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
745c523858385176c33a7456bb84035de78552d22dMarc Blank     * Next tag to use.  All connections associated to the same ImapStore instance share the same
755c523858385176c33a7456bb84035de78552d22dMarc Blank     * counter to make tests simpler.
765c523858385176c33a7456bb84035de78552d22dMarc Blank     * (Some of the tests involve multiple connections but only have a single counter to track the
775c523858385176c33a7456bb84035de78552d22dMarc Blank     * tag.)
785c523858385176c33a7456bb84035de78552d22dMarc Blank     */
795c523858385176c33a7456bb84035de78552d22dMarc Blank    private final AtomicInteger mNextCommandTag = new AtomicInteger(0);
805c523858385176c33a7456bb84035de78552d22dMarc Blank
815c523858385176c33a7456bb84035de78552d22dMarc Blank
825c523858385176c33a7456bb84035de78552d22dMarc Blank    // Keep others from instantiating directly
835c523858385176c33a7456bb84035de78552d22dMarc Blank    ImapConnection(ImapStore store, String username, String password) {
845c523858385176c33a7456bb84035de78552d22dMarc Blank        setStore(store, username, password);
855c523858385176c33a7456bb84035de78552d22dMarc Blank    }
865c523858385176c33a7456bb84035de78552d22dMarc Blank
875c523858385176c33a7456bb84035de78552d22dMarc Blank    void setStore(ImapStore store, String username, String password) {
885c523858385176c33a7456bb84035de78552d22dMarc Blank        if (username != null && password != null) {
895c523858385176c33a7456bb84035de78552d22dMarc Blank            mUsername = username;
905c523858385176c33a7456bb84035de78552d22dMarc Blank
915c523858385176c33a7456bb84035de78552d22dMarc Blank            // build the LOGIN string once (instead of over-and-over again.)
925c523858385176c33a7456bb84035de78552d22dMarc Blank            // apply the quoting here around the built-up password
935c523858385176c33a7456bb84035de78552d22dMarc Blank            mLoginPhrase = ImapConstants.LOGIN + " " + mUsername + " "
945c523858385176c33a7456bb84035de78552d22dMarc Blank                    + ImapUtility.imapQuoted(password);
955c523858385176c33a7456bb84035de78552d22dMarc Blank        }
965c523858385176c33a7456bb84035de78552d22dMarc Blank        mImapStore = store;
975c523858385176c33a7456bb84035de78552d22dMarc Blank    }
985c523858385176c33a7456bb84035de78552d22dMarc Blank    void open() throws IOException, MessagingException {
995c523858385176c33a7456bb84035de78552d22dMarc Blank        if (mTransport != null && mTransport.isOpen()) {
1005c523858385176c33a7456bb84035de78552d22dMarc Blank            return;
1015c523858385176c33a7456bb84035de78552d22dMarc Blank        }
1025c523858385176c33a7456bb84035de78552d22dMarc Blank
1035c523858385176c33a7456bb84035de78552d22dMarc Blank        try {
1045c523858385176c33a7456bb84035de78552d22dMarc Blank            // copy configuration into a clean transport, if necessary
1055c523858385176c33a7456bb84035de78552d22dMarc Blank            if (mTransport == null) {
1065c523858385176c33a7456bb84035de78552d22dMarc Blank                mTransport = mImapStore.cloneTransport();
1075c523858385176c33a7456bb84035de78552d22dMarc Blank            }
1085c523858385176c33a7456bb84035de78552d22dMarc Blank
1095c523858385176c33a7456bb84035de78552d22dMarc Blank            mTransport.open();
1105c523858385176c33a7456bb84035de78552d22dMarc Blank            mTransport.setSoTimeout(MailTransport.SOCKET_READ_TIMEOUT);
1115c523858385176c33a7456bb84035de78552d22dMarc Blank
1125c523858385176c33a7456bb84035de78552d22dMarc Blank            createParser();
1135c523858385176c33a7456bb84035de78552d22dMarc Blank
1145c523858385176c33a7456bb84035de78552d22dMarc Blank            // BANNER
1155c523858385176c33a7456bb84035de78552d22dMarc Blank            mParser.readResponse();
1165c523858385176c33a7456bb84035de78552d22dMarc Blank
1175c523858385176c33a7456bb84035de78552d22dMarc Blank            // CAPABILITY
1185c523858385176c33a7456bb84035de78552d22dMarc Blank            ImapResponse capabilities = queryCapabilities();
1195c523858385176c33a7456bb84035de78552d22dMarc Blank
1205c523858385176c33a7456bb84035de78552d22dMarc Blank            boolean hasStartTlsCapability =
1215c523858385176c33a7456bb84035de78552d22dMarc Blank                capabilities.contains(ImapConstants.STARTTLS);
1225c523858385176c33a7456bb84035de78552d22dMarc Blank
1235c523858385176c33a7456bb84035de78552d22dMarc Blank            // TLS
1245c523858385176c33a7456bb84035de78552d22dMarc Blank            ImapResponse newCapabilities = doStartTls(hasStartTlsCapability);
1255c523858385176c33a7456bb84035de78552d22dMarc Blank            if (newCapabilities != null) {
1265c523858385176c33a7456bb84035de78552d22dMarc Blank                capabilities = newCapabilities;
1275c523858385176c33a7456bb84035de78552d22dMarc Blank            }
1285c523858385176c33a7456bb84035de78552d22dMarc Blank
1295c523858385176c33a7456bb84035de78552d22dMarc Blank            // NOTE: An IMAP response MUST be processed before issuing any new IMAP
1305c523858385176c33a7456bb84035de78552d22dMarc Blank            // requests. Subsequent requests may destroy previous response data. As
1315c523858385176c33a7456bb84035de78552d22dMarc Blank            // such, we save away capability information here for future use.
1325c523858385176c33a7456bb84035de78552d22dMarc Blank            setCapabilities(capabilities);
1335c523858385176c33a7456bb84035de78552d22dMarc Blank            String capabilityString = capabilities.flatten();
1345c523858385176c33a7456bb84035de78552d22dMarc Blank
1355c523858385176c33a7456bb84035de78552d22dMarc Blank            // ID
1365c523858385176c33a7456bb84035de78552d22dMarc Blank            doSendId(isCapable(CAPABILITY_ID), capabilityString);
1375c523858385176c33a7456bb84035de78552d22dMarc Blank
1385c523858385176c33a7456bb84035de78552d22dMarc Blank            // LOGIN
1395c523858385176c33a7456bb84035de78552d22dMarc Blank            doLogin();
1405c523858385176c33a7456bb84035de78552d22dMarc Blank
1415c523858385176c33a7456bb84035de78552d22dMarc Blank            // NAMESPACE (only valid in the Authenticated state)
1425c523858385176c33a7456bb84035de78552d22dMarc Blank            doGetNamespace(isCapable(CAPABILITY_NAMESPACE));
1435c523858385176c33a7456bb84035de78552d22dMarc Blank
1445c523858385176c33a7456bb84035de78552d22dMarc Blank            // Gets the path separator from the server
1455c523858385176c33a7456bb84035de78552d22dMarc Blank            doGetPathSeparator();
1465c523858385176c33a7456bb84035de78552d22dMarc Blank
1475c523858385176c33a7456bb84035de78552d22dMarc Blank            mImapStore.ensurePrefixIsValid();
1485c523858385176c33a7456bb84035de78552d22dMarc Blank        } catch (SSLException e) {
149bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook            if (Email.DEBUG) {
1505c523858385176c33a7456bb84035de78552d22dMarc Blank                Log.d(Logging.LOG_TAG, e.toString());
1515c523858385176c33a7456bb84035de78552d22dMarc Blank            }
1525c523858385176c33a7456bb84035de78552d22dMarc Blank            throw new CertificateValidationException(e.getMessage(), e);
1535c523858385176c33a7456bb84035de78552d22dMarc Blank        } catch (IOException ioe) {
1545c523858385176c33a7456bb84035de78552d22dMarc Blank            // NOTE:  Unlike similar code in POP3, I'm going to rethrow as-is.  There is a lot
1555c523858385176c33a7456bb84035de78552d22dMarc Blank            // of other code here that catches IOException and I don't want to break it.
1565c523858385176c33a7456bb84035de78552d22dMarc Blank            // This catch is only here to enhance logging of connection-time issues.
157bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook            if (Email.DEBUG) {
1585c523858385176c33a7456bb84035de78552d22dMarc Blank                Log.d(Logging.LOG_TAG, ioe.toString());
1595c523858385176c33a7456bb84035de78552d22dMarc Blank            }
1605c523858385176c33a7456bb84035de78552d22dMarc Blank            throw ioe;
1615c523858385176c33a7456bb84035de78552d22dMarc Blank        } finally {
1625c523858385176c33a7456bb84035de78552d22dMarc Blank            destroyResponses();
1635c523858385176c33a7456bb84035de78552d22dMarc Blank        }
1645c523858385176c33a7456bb84035de78552d22dMarc Blank    }
1655c523858385176c33a7456bb84035de78552d22dMarc Blank
1665c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
1675c523858385176c33a7456bb84035de78552d22dMarc Blank     * Closes the connection and releases all resources. This connection can not be used again
1685c523858385176c33a7456bb84035de78552d22dMarc Blank     * until {@link #setStore(ImapStore, String, String)} is called.
1695c523858385176c33a7456bb84035de78552d22dMarc Blank     */
1705c523858385176c33a7456bb84035de78552d22dMarc Blank    void close() {
1715c523858385176c33a7456bb84035de78552d22dMarc Blank        if (mTransport != null) {
1725c523858385176c33a7456bb84035de78552d22dMarc Blank            mTransport.close();
1735c523858385176c33a7456bb84035de78552d22dMarc Blank            mTransport = null;
1745c523858385176c33a7456bb84035de78552d22dMarc Blank        }
1755c523858385176c33a7456bb84035de78552d22dMarc Blank        destroyResponses();
1765c523858385176c33a7456bb84035de78552d22dMarc Blank        mParser = null;
1775c523858385176c33a7456bb84035de78552d22dMarc Blank        mImapStore = null;
1785c523858385176c33a7456bb84035de78552d22dMarc Blank    }
1795c523858385176c33a7456bb84035de78552d22dMarc Blank
1805c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
1815c523858385176c33a7456bb84035de78552d22dMarc Blank     * Returns whether or not the specified capability is supported by the server.
1825c523858385176c33a7456bb84035de78552d22dMarc Blank     */
1835c523858385176c33a7456bb84035de78552d22dMarc Blank    private boolean isCapable(int capability) {
1845c523858385176c33a7456bb84035de78552d22dMarc Blank        return (mCapabilities & capability) != 0;
1855c523858385176c33a7456bb84035de78552d22dMarc Blank    }
1865c523858385176c33a7456bb84035de78552d22dMarc Blank
1875c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
1885c523858385176c33a7456bb84035de78552d22dMarc Blank     * Sets the capability flags according to the response provided by the server.
1895c523858385176c33a7456bb84035de78552d22dMarc Blank     * Note: We only set the capability flags that we are interested in. There are many IMAP
1905c523858385176c33a7456bb84035de78552d22dMarc Blank     * capabilities that we do not track.
1915c523858385176c33a7456bb84035de78552d22dMarc Blank     */
1925c523858385176c33a7456bb84035de78552d22dMarc Blank    private void setCapabilities(ImapResponse capabilities) {
1935c523858385176c33a7456bb84035de78552d22dMarc Blank        if (capabilities.contains(ImapConstants.ID)) {
1945c523858385176c33a7456bb84035de78552d22dMarc Blank            mCapabilities |= CAPABILITY_ID;
1955c523858385176c33a7456bb84035de78552d22dMarc Blank        }
1965c523858385176c33a7456bb84035de78552d22dMarc Blank        if (capabilities.contains(ImapConstants.NAMESPACE)) {
1975c523858385176c33a7456bb84035de78552d22dMarc Blank            mCapabilities |= CAPABILITY_NAMESPACE;
1985c523858385176c33a7456bb84035de78552d22dMarc Blank        }
1995c523858385176c33a7456bb84035de78552d22dMarc Blank        if (capabilities.contains(ImapConstants.UIDPLUS)) {
2005c523858385176c33a7456bb84035de78552d22dMarc Blank            mCapabilities |= CAPABILITY_UIDPLUS;
2015c523858385176c33a7456bb84035de78552d22dMarc Blank        }
2025c523858385176c33a7456bb84035de78552d22dMarc Blank        if (capabilities.contains(ImapConstants.STARTTLS)) {
2035c523858385176c33a7456bb84035de78552d22dMarc Blank            mCapabilities |= CAPABILITY_STARTTLS;
2045c523858385176c33a7456bb84035de78552d22dMarc Blank        }
2055c523858385176c33a7456bb84035de78552d22dMarc Blank    }
2065c523858385176c33a7456bb84035de78552d22dMarc Blank
2075c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
2085c523858385176c33a7456bb84035de78552d22dMarc Blank     * Create an {@link ImapResponseParser} from {@code mTransport.getInputStream()} and
2095c523858385176c33a7456bb84035de78552d22dMarc Blank     * set it to {@link #mParser}.
2105c523858385176c33a7456bb84035de78552d22dMarc Blank     *
2115c523858385176c33a7456bb84035de78552d22dMarc Blank     * If we already have an {@link ImapResponseParser}, we
2125c523858385176c33a7456bb84035de78552d22dMarc Blank     * {@link #destroyResponses()} and throw it away.
2135c523858385176c33a7456bb84035de78552d22dMarc Blank     */
2145c523858385176c33a7456bb84035de78552d22dMarc Blank    private void createParser() {
2155c523858385176c33a7456bb84035de78552d22dMarc Blank        destroyResponses();
2165c523858385176c33a7456bb84035de78552d22dMarc Blank        mParser = new ImapResponseParser(mTransport.getInputStream(), mDiscourse);
2175c523858385176c33a7456bb84035de78552d22dMarc Blank    }
2185c523858385176c33a7456bb84035de78552d22dMarc Blank
2195c523858385176c33a7456bb84035de78552d22dMarc Blank    void destroyResponses() {
2205c523858385176c33a7456bb84035de78552d22dMarc Blank        if (mParser != null) {
2215c523858385176c33a7456bb84035de78552d22dMarc Blank            mParser.destroyResponses();
2225c523858385176c33a7456bb84035de78552d22dMarc Blank        }
2235c523858385176c33a7456bb84035de78552d22dMarc Blank    }
2245c523858385176c33a7456bb84035de78552d22dMarc Blank
2255c523858385176c33a7456bb84035de78552d22dMarc Blank    boolean isTransportOpenForTest() {
2265c523858385176c33a7456bb84035de78552d22dMarc Blank        return mTransport != null ? mTransport.isOpen() : false;
2275c523858385176c33a7456bb84035de78552d22dMarc Blank    }
2285c523858385176c33a7456bb84035de78552d22dMarc Blank
2295c523858385176c33a7456bb84035de78552d22dMarc Blank    ImapResponse readResponse() throws IOException, MessagingException {
2305c523858385176c33a7456bb84035de78552d22dMarc Blank        return mParser.readResponse();
2315c523858385176c33a7456bb84035de78552d22dMarc Blank    }
2325c523858385176c33a7456bb84035de78552d22dMarc Blank
2335c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
2345c523858385176c33a7456bb84035de78552d22dMarc Blank     * Send a single command to the server.  The command will be preceded by an IMAP command
2355c523858385176c33a7456bb84035de78552d22dMarc Blank     * tag and followed by \r\n (caller need not supply them).
2365c523858385176c33a7456bb84035de78552d22dMarc Blank     *
2375c523858385176c33a7456bb84035de78552d22dMarc Blank     * @param command The command to send to the server
2385c523858385176c33a7456bb84035de78552d22dMarc Blank     * @param sensitive If true, the command will not be logged
2395c523858385176c33a7456bb84035de78552d22dMarc Blank     * @return Returns the command tag that was sent
2405c523858385176c33a7456bb84035de78552d22dMarc Blank     */
2415c523858385176c33a7456bb84035de78552d22dMarc Blank    String sendCommand(String command, boolean sensitive)
2425c523858385176c33a7456bb84035de78552d22dMarc Blank        throws MessagingException, IOException {
2435c523858385176c33a7456bb84035de78552d22dMarc Blank        open();
2445c523858385176c33a7456bb84035de78552d22dMarc Blank        String tag = Integer.toString(mNextCommandTag.incrementAndGet());
2455c523858385176c33a7456bb84035de78552d22dMarc Blank        String commandToSend = tag + " " + command;
2465c523858385176c33a7456bb84035de78552d22dMarc Blank        mTransport.writeLine(commandToSend, sensitive ? IMAP_REDACTED_LOG : null);
2475c523858385176c33a7456bb84035de78552d22dMarc Blank        mDiscourse.addSentCommand(sensitive ? IMAP_REDACTED_LOG : commandToSend);
2485c523858385176c33a7456bb84035de78552d22dMarc Blank        return tag;
2495c523858385176c33a7456bb84035de78552d22dMarc Blank    }
2505c523858385176c33a7456bb84035de78552d22dMarc Blank
2515c523858385176c33a7456bb84035de78552d22dMarc Blank
2525c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
2535c523858385176c33a7456bb84035de78552d22dMarc Blank     * Send a single, complex command to the server.  The command will be preceded by an IMAP
2545c523858385176c33a7456bb84035de78552d22dMarc Blank     * command tag and followed by \r\n (caller need not supply them).  After each piece of the
2555c523858385176c33a7456bb84035de78552d22dMarc Blank     * command, a response will be read which MUST be a continuation request.
2565c523858385176c33a7456bb84035de78552d22dMarc Blank     *
2575c523858385176c33a7456bb84035de78552d22dMarc Blank     * @param commands An array of Strings comprising the command to be sent to the server
2585c523858385176c33a7456bb84035de78552d22dMarc Blank     * @return Returns the command tag that was sent
2595c523858385176c33a7456bb84035de78552d22dMarc Blank     */
2605c523858385176c33a7456bb84035de78552d22dMarc Blank    String sendComplexCommand(List<String> commands, boolean sensitive) throws MessagingException,
2615c523858385176c33a7456bb84035de78552d22dMarc Blank            IOException {
2625c523858385176c33a7456bb84035de78552d22dMarc Blank        open();
2635c523858385176c33a7456bb84035de78552d22dMarc Blank        String tag = Integer.toString(mNextCommandTag.incrementAndGet());
2645c523858385176c33a7456bb84035de78552d22dMarc Blank        int len = commands.size();
2655c523858385176c33a7456bb84035de78552d22dMarc Blank        for (int i = 0; i < len; i++) {
2665c523858385176c33a7456bb84035de78552d22dMarc Blank            String commandToSend = commands.get(i);
2675c523858385176c33a7456bb84035de78552d22dMarc Blank            // The first part of the command gets the tag
2685c523858385176c33a7456bb84035de78552d22dMarc Blank            if (i == 0) {
2695c523858385176c33a7456bb84035de78552d22dMarc Blank                commandToSend = tag + " " + commandToSend;
2705c523858385176c33a7456bb84035de78552d22dMarc Blank            } else {
2715c523858385176c33a7456bb84035de78552d22dMarc Blank                // Otherwise, read the response from the previous part of the command
2725c523858385176c33a7456bb84035de78552d22dMarc Blank                ImapResponse response = readResponse();
2735c523858385176c33a7456bb84035de78552d22dMarc Blank                // If it isn't a continuation request, that's an error
2745c523858385176c33a7456bb84035de78552d22dMarc Blank                if (!response.isContinuationRequest()) {
2755c523858385176c33a7456bb84035de78552d22dMarc Blank                    throw new MessagingException("Expected continuation request");
2765c523858385176c33a7456bb84035de78552d22dMarc Blank                }
2775c523858385176c33a7456bb84035de78552d22dMarc Blank            }
2785c523858385176c33a7456bb84035de78552d22dMarc Blank            // Send the command
2795c523858385176c33a7456bb84035de78552d22dMarc Blank            mTransport.writeLine(commandToSend, null);
2805c523858385176c33a7456bb84035de78552d22dMarc Blank            mDiscourse.addSentCommand(sensitive ? IMAP_REDACTED_LOG : commandToSend);
2815c523858385176c33a7456bb84035de78552d22dMarc Blank        }
2825c523858385176c33a7456bb84035de78552d22dMarc Blank        return tag;
2835c523858385176c33a7456bb84035de78552d22dMarc Blank    }
2845c523858385176c33a7456bb84035de78552d22dMarc Blank
2855c523858385176c33a7456bb84035de78552d22dMarc Blank    List<ImapResponse> executeSimpleCommand(String command) throws IOException,
2865c523858385176c33a7456bb84035de78552d22dMarc Blank            MessagingException {
2875c523858385176c33a7456bb84035de78552d22dMarc Blank        return executeSimpleCommand(command, false);
2885c523858385176c33a7456bb84035de78552d22dMarc Blank    }
2895c523858385176c33a7456bb84035de78552d22dMarc Blank
2905c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
2915c523858385176c33a7456bb84035de78552d22dMarc Blank     * Read and return all of the responses from the most recent command sent to the server
2925c523858385176c33a7456bb84035de78552d22dMarc Blank     *
2935c523858385176c33a7456bb84035de78552d22dMarc Blank     * @return a list of ImapResponses
2945c523858385176c33a7456bb84035de78552d22dMarc Blank     * @throws IOException
2955c523858385176c33a7456bb84035de78552d22dMarc Blank     * @throws MessagingException
2965c523858385176c33a7456bb84035de78552d22dMarc Blank     */
2975c523858385176c33a7456bb84035de78552d22dMarc Blank    List<ImapResponse> getCommandResponses() throws IOException, MessagingException {
2985c523858385176c33a7456bb84035de78552d22dMarc Blank        ArrayList<ImapResponse> responses = new ArrayList<ImapResponse>();
2995c523858385176c33a7456bb84035de78552d22dMarc Blank        ImapResponse response;
3005c523858385176c33a7456bb84035de78552d22dMarc Blank        do {
3015c523858385176c33a7456bb84035de78552d22dMarc Blank            response = mParser.readResponse();
3025c523858385176c33a7456bb84035de78552d22dMarc Blank            responses.add(response);
3035c523858385176c33a7456bb84035de78552d22dMarc Blank        } while (!response.isTagged());
3045c523858385176c33a7456bb84035de78552d22dMarc Blank        if (!response.isOk()) {
3055c523858385176c33a7456bb84035de78552d22dMarc Blank            final String toString = response.toString();
3065c523858385176c33a7456bb84035de78552d22dMarc Blank            final String alert = response.getAlertTextOrEmpty().getString();
3075c523858385176c33a7456bb84035de78552d22dMarc Blank            destroyResponses();
3085c523858385176c33a7456bb84035de78552d22dMarc Blank            throw new ImapException(toString, alert);
3095c523858385176c33a7456bb84035de78552d22dMarc Blank        }
3105c523858385176c33a7456bb84035de78552d22dMarc Blank        return responses;
3115c523858385176c33a7456bb84035de78552d22dMarc Blank    }
3125c523858385176c33a7456bb84035de78552d22dMarc Blank
3135c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
3145c523858385176c33a7456bb84035de78552d22dMarc Blank     * Execute a simple command at the server, a simple command being one that is sent in a single
3155c523858385176c33a7456bb84035de78552d22dMarc Blank     * line of text
3165c523858385176c33a7456bb84035de78552d22dMarc Blank     *
3175c523858385176c33a7456bb84035de78552d22dMarc Blank     * @param command the command to send to the server
3185c523858385176c33a7456bb84035de78552d22dMarc Blank     * @param sensitive whether the command should be redacted in logs (used for login)
3195c523858385176c33a7456bb84035de78552d22dMarc Blank     * @return a list of ImapResponses
3205c523858385176c33a7456bb84035de78552d22dMarc Blank     * @throws IOException
3215c523858385176c33a7456bb84035de78552d22dMarc Blank     * @throws MessagingException
3225c523858385176c33a7456bb84035de78552d22dMarc Blank     */
3235c523858385176c33a7456bb84035de78552d22dMarc Blank     List<ImapResponse> executeSimpleCommand(String command, boolean sensitive)
3245c523858385176c33a7456bb84035de78552d22dMarc Blank            throws IOException, MessagingException {
3255c523858385176c33a7456bb84035de78552d22dMarc Blank        sendCommand(command, sensitive);
3265c523858385176c33a7456bb84035de78552d22dMarc Blank        return getCommandResponses();
3275c523858385176c33a7456bb84035de78552d22dMarc Blank    }
3285c523858385176c33a7456bb84035de78552d22dMarc Blank
3295c523858385176c33a7456bb84035de78552d22dMarc Blank     /**
3305c523858385176c33a7456bb84035de78552d22dMarc Blank      * Execute a complex command at the server, a complex command being one that must be sent in
3315c523858385176c33a7456bb84035de78552d22dMarc Blank      * multiple lines due to the use of string literals
3325c523858385176c33a7456bb84035de78552d22dMarc Blank      *
3335c523858385176c33a7456bb84035de78552d22dMarc Blank      * @param commands a list of strings that comprise the command to be sent to the server
3345c523858385176c33a7456bb84035de78552d22dMarc Blank      * @param sensitive whether the command should be redacted in logs (used for login)
3355c523858385176c33a7456bb84035de78552d22dMarc Blank      * @return a list of ImapResponses
3365c523858385176c33a7456bb84035de78552d22dMarc Blank      * @throws IOException
3375c523858385176c33a7456bb84035de78552d22dMarc Blank      * @throws MessagingException
3385c523858385176c33a7456bb84035de78552d22dMarc Blank      */
3395c523858385176c33a7456bb84035de78552d22dMarc Blank      List<ImapResponse> executeComplexCommand(List<String> commands, boolean sensitive)
3405c523858385176c33a7456bb84035de78552d22dMarc Blank            throws IOException, MessagingException {
3415c523858385176c33a7456bb84035de78552d22dMarc Blank        sendComplexCommand(commands, sensitive);
3425c523858385176c33a7456bb84035de78552d22dMarc Blank        return getCommandResponses();
3435c523858385176c33a7456bb84035de78552d22dMarc Blank    }
3445c523858385176c33a7456bb84035de78552d22dMarc Blank
3455c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
3465c523858385176c33a7456bb84035de78552d22dMarc Blank     * Query server for capabilities.
3475c523858385176c33a7456bb84035de78552d22dMarc Blank     */
3485c523858385176c33a7456bb84035de78552d22dMarc Blank    private ImapResponse queryCapabilities() throws IOException, MessagingException {
3495c523858385176c33a7456bb84035de78552d22dMarc Blank        ImapResponse capabilityResponse = null;
3505c523858385176c33a7456bb84035de78552d22dMarc Blank        for (ImapResponse r : executeSimpleCommand(ImapConstants.CAPABILITY)) {
3515c523858385176c33a7456bb84035de78552d22dMarc Blank            if (r.is(0, ImapConstants.CAPABILITY)) {
3525c523858385176c33a7456bb84035de78552d22dMarc Blank                capabilityResponse = r;
3535c523858385176c33a7456bb84035de78552d22dMarc Blank                break;
3545c523858385176c33a7456bb84035de78552d22dMarc Blank            }
3555c523858385176c33a7456bb84035de78552d22dMarc Blank        }
3565c523858385176c33a7456bb84035de78552d22dMarc Blank        if (capabilityResponse == null) {
3575c523858385176c33a7456bb84035de78552d22dMarc Blank            throw new MessagingException("Invalid CAPABILITY response received");
3585c523858385176c33a7456bb84035de78552d22dMarc Blank        }
3595c523858385176c33a7456bb84035de78552d22dMarc Blank        return capabilityResponse;
3605c523858385176c33a7456bb84035de78552d22dMarc Blank    }
3615c523858385176c33a7456bb84035de78552d22dMarc Blank
3625c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
3635c523858385176c33a7456bb84035de78552d22dMarc Blank     * Sends client identification information to the IMAP server per RFC 2971. If
3645c523858385176c33a7456bb84035de78552d22dMarc Blank     * the server does not support the ID command, this will perform no operation.
3655c523858385176c33a7456bb84035de78552d22dMarc Blank     *
3665c523858385176c33a7456bb84035de78552d22dMarc Blank     * Interoperability hack:  Never send ID to *.secureserver.net, which sends back a
3675c523858385176c33a7456bb84035de78552d22dMarc Blank     * malformed response that our parser can't deal with.
3685c523858385176c33a7456bb84035de78552d22dMarc Blank     */
3695c523858385176c33a7456bb84035de78552d22dMarc Blank    private void doSendId(boolean hasIdCapability, String capabilities)
3705c523858385176c33a7456bb84035de78552d22dMarc Blank            throws MessagingException {
3715c523858385176c33a7456bb84035de78552d22dMarc Blank        if (!hasIdCapability) return;
3725c523858385176c33a7456bb84035de78552d22dMarc Blank
3735c523858385176c33a7456bb84035de78552d22dMarc Blank        // Never send ID to *.secureserver.net
3745c523858385176c33a7456bb84035de78552d22dMarc Blank        String host = mTransport.getHost();
3755c523858385176c33a7456bb84035de78552d22dMarc Blank        if (host.toLowerCase().endsWith(".secureserver.net")) return;
3765c523858385176c33a7456bb84035de78552d22dMarc Blank
3775c523858385176c33a7456bb84035de78552d22dMarc Blank        // Assign user-agent string (for RFC2971 ID command)
3785c523858385176c33a7456bb84035de78552d22dMarc Blank        String mUserAgent =
3795c523858385176c33a7456bb84035de78552d22dMarc Blank                ImapStore.getImapId(mImapStore.getContext(), mUsername, host, capabilities);
3805c523858385176c33a7456bb84035de78552d22dMarc Blank
3815c523858385176c33a7456bb84035de78552d22dMarc Blank        if (mUserAgent != null) {
3825c523858385176c33a7456bb84035de78552d22dMarc Blank            mIdPhrase = ImapConstants.ID + " (" + mUserAgent + ")";
3835c523858385176c33a7456bb84035de78552d22dMarc Blank        } else if (DEBUG_FORCE_SEND_ID) {
3845c523858385176c33a7456bb84035de78552d22dMarc Blank            mIdPhrase = ImapConstants.ID + " " + ImapConstants.NIL;
3855c523858385176c33a7456bb84035de78552d22dMarc Blank        }
3865c523858385176c33a7456bb84035de78552d22dMarc Blank        // else: mIdPhrase = null, no ID will be emitted
3875c523858385176c33a7456bb84035de78552d22dMarc Blank
3885c523858385176c33a7456bb84035de78552d22dMarc Blank        // Send user-agent in an RFC2971 ID command
3895c523858385176c33a7456bb84035de78552d22dMarc Blank        if (mIdPhrase != null) {
3905c523858385176c33a7456bb84035de78552d22dMarc Blank            try {
3915c523858385176c33a7456bb84035de78552d22dMarc Blank                executeSimpleCommand(mIdPhrase);
3925c523858385176c33a7456bb84035de78552d22dMarc Blank            } catch (ImapException ie) {
3935c523858385176c33a7456bb84035de78552d22dMarc Blank                // Log for debugging, but this is not a fatal problem.
394bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook                if (Email.DEBUG) {
3955c523858385176c33a7456bb84035de78552d22dMarc Blank                    Log.d(Logging.LOG_TAG, ie.toString());
3965c523858385176c33a7456bb84035de78552d22dMarc Blank                }
3975c523858385176c33a7456bb84035de78552d22dMarc Blank            } catch (IOException ioe) {
3985c523858385176c33a7456bb84035de78552d22dMarc Blank                // Special case to handle malformed OK responses and ignore them.
3995c523858385176c33a7456bb84035de78552d22dMarc Blank                // A true IOException will recur on the following login steps
4005c523858385176c33a7456bb84035de78552d22dMarc Blank                // This can go away after the parser is fixed - see bug 2138981
4015c523858385176c33a7456bb84035de78552d22dMarc Blank            }
4025c523858385176c33a7456bb84035de78552d22dMarc Blank        }
4035c523858385176c33a7456bb84035de78552d22dMarc Blank    }
4045c523858385176c33a7456bb84035de78552d22dMarc Blank
4055c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
4065c523858385176c33a7456bb84035de78552d22dMarc Blank     * Gets the user's Personal Namespace from the IMAP server per RFC 2342. If the user
4075c523858385176c33a7456bb84035de78552d22dMarc Blank     * explicitly sets a namespace (using setup UI) or if the server does not support the
4085c523858385176c33a7456bb84035de78552d22dMarc Blank     * namespace command, this will perform no operation.
4095c523858385176c33a7456bb84035de78552d22dMarc Blank     */
4105c523858385176c33a7456bb84035de78552d22dMarc Blank    private void doGetNamespace(boolean hasNamespaceCapability) throws MessagingException {
4115c523858385176c33a7456bb84035de78552d22dMarc Blank        // user did not specify a hard-coded prefix; try to get it from the server
4125c523858385176c33a7456bb84035de78552d22dMarc Blank        if (hasNamespaceCapability && !mImapStore.isUserPrefixSet()) {
4135c523858385176c33a7456bb84035de78552d22dMarc Blank            List<ImapResponse> responseList = Collections.emptyList();
4145c523858385176c33a7456bb84035de78552d22dMarc Blank
4155c523858385176c33a7456bb84035de78552d22dMarc Blank            try {
4165c523858385176c33a7456bb84035de78552d22dMarc Blank                responseList = executeSimpleCommand(ImapConstants.NAMESPACE);
4175c523858385176c33a7456bb84035de78552d22dMarc Blank            } catch (ImapException ie) {
4185c523858385176c33a7456bb84035de78552d22dMarc Blank                // Log for debugging, but this is not a fatal problem.
419bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook                if (Email.DEBUG) {
4205c523858385176c33a7456bb84035de78552d22dMarc Blank                    Log.d(Logging.LOG_TAG, ie.toString());
4215c523858385176c33a7456bb84035de78552d22dMarc Blank                }
4225c523858385176c33a7456bb84035de78552d22dMarc Blank            } catch (IOException ioe) {
4235c523858385176c33a7456bb84035de78552d22dMarc Blank                // Special case to handle malformed OK responses and ignore them.
4245c523858385176c33a7456bb84035de78552d22dMarc Blank            }
4255c523858385176c33a7456bb84035de78552d22dMarc Blank
4265c523858385176c33a7456bb84035de78552d22dMarc Blank            for (ImapResponse response: responseList) {
4275c523858385176c33a7456bb84035de78552d22dMarc Blank                if (response.isDataResponse(0, ImapConstants.NAMESPACE)) {
4285c523858385176c33a7456bb84035de78552d22dMarc Blank                    ImapList namespaceList = response.getListOrEmpty(1);
4295c523858385176c33a7456bb84035de78552d22dMarc Blank                    ImapList namespace = namespaceList.getListOrEmpty(0);
4305c523858385176c33a7456bb84035de78552d22dMarc Blank                    String namespaceString = namespace.getStringOrEmpty(0).getString();
4315c523858385176c33a7456bb84035de78552d22dMarc Blank                    if (!TextUtils.isEmpty(namespaceString)) {
4325c523858385176c33a7456bb84035de78552d22dMarc Blank                        mImapStore.setPathPrefix(ImapStore.decodeFolderName(namespaceString, null));
4335c523858385176c33a7456bb84035de78552d22dMarc Blank                        mImapStore.setPathSeparator(namespace.getStringOrEmpty(1).getString());
4345c523858385176c33a7456bb84035de78552d22dMarc Blank                    }
4355c523858385176c33a7456bb84035de78552d22dMarc Blank                }
4365c523858385176c33a7456bb84035de78552d22dMarc Blank            }
4375c523858385176c33a7456bb84035de78552d22dMarc Blank        }
4385c523858385176c33a7456bb84035de78552d22dMarc Blank    }
4395c523858385176c33a7456bb84035de78552d22dMarc Blank
4405c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
4415c523858385176c33a7456bb84035de78552d22dMarc Blank     * Logs into the IMAP server
4425c523858385176c33a7456bb84035de78552d22dMarc Blank     */
4435c523858385176c33a7456bb84035de78552d22dMarc Blank    private void doLogin()
4445c523858385176c33a7456bb84035de78552d22dMarc Blank            throws IOException, MessagingException, AuthenticationFailedException {
4455c523858385176c33a7456bb84035de78552d22dMarc Blank        try {
4465c523858385176c33a7456bb84035de78552d22dMarc Blank            // TODO eventually we need to add additional authentication
4475c523858385176c33a7456bb84035de78552d22dMarc Blank            // options such as SASL
4485c523858385176c33a7456bb84035de78552d22dMarc Blank            executeSimpleCommand(mLoginPhrase, true);
4495c523858385176c33a7456bb84035de78552d22dMarc Blank        } catch (ImapException ie) {
450bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook            if (Email.DEBUG) {
4515c523858385176c33a7456bb84035de78552d22dMarc Blank                Log.d(Logging.LOG_TAG, ie.toString());
4525c523858385176c33a7456bb84035de78552d22dMarc Blank            }
4535c523858385176c33a7456bb84035de78552d22dMarc Blank            throw new AuthenticationFailedException(ie.getAlertText(), ie);
4545c523858385176c33a7456bb84035de78552d22dMarc Blank
4555c523858385176c33a7456bb84035de78552d22dMarc Blank        } catch (MessagingException me) {
4565c523858385176c33a7456bb84035de78552d22dMarc Blank            throw new AuthenticationFailedException(null, me);
4575c523858385176c33a7456bb84035de78552d22dMarc Blank        }
4585c523858385176c33a7456bb84035de78552d22dMarc Blank    }
4595c523858385176c33a7456bb84035de78552d22dMarc Blank
4605c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
4615c523858385176c33a7456bb84035de78552d22dMarc Blank     * Gets the path separator per the LIST command in RFC 3501. If the path separator
4625c523858385176c33a7456bb84035de78552d22dMarc Blank     * was obtained while obtaining the namespace or there is no prefix defined, this
4635c523858385176c33a7456bb84035de78552d22dMarc Blank     * will perform no operation.
4645c523858385176c33a7456bb84035de78552d22dMarc Blank     */
4655c523858385176c33a7456bb84035de78552d22dMarc Blank    private void doGetPathSeparator() throws MessagingException {
4665c523858385176c33a7456bb84035de78552d22dMarc Blank        // user did not specify a hard-coded prefix; try to get it from the server
4675c523858385176c33a7456bb84035de78552d22dMarc Blank        if (mImapStore.isUserPrefixSet()) {
4685c523858385176c33a7456bb84035de78552d22dMarc Blank            List<ImapResponse> responseList = Collections.emptyList();
4695c523858385176c33a7456bb84035de78552d22dMarc Blank
4705c523858385176c33a7456bb84035de78552d22dMarc Blank            try {
4715c523858385176c33a7456bb84035de78552d22dMarc Blank                responseList = executeSimpleCommand(ImapConstants.LIST + " \"\" \"\"");
4725c523858385176c33a7456bb84035de78552d22dMarc Blank            } catch (ImapException ie) {
4735c523858385176c33a7456bb84035de78552d22dMarc Blank                // Log for debugging, but this is not a fatal problem.
474bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook                if (Email.DEBUG) {
4755c523858385176c33a7456bb84035de78552d22dMarc Blank                    Log.d(Logging.LOG_TAG, ie.toString());
4765c523858385176c33a7456bb84035de78552d22dMarc Blank                }
4775c523858385176c33a7456bb84035de78552d22dMarc Blank            } catch (IOException ioe) {
4785c523858385176c33a7456bb84035de78552d22dMarc Blank                // Special case to handle malformed OK responses and ignore them.
4795c523858385176c33a7456bb84035de78552d22dMarc Blank            }
4805c523858385176c33a7456bb84035de78552d22dMarc Blank
4815c523858385176c33a7456bb84035de78552d22dMarc Blank            for (ImapResponse response: responseList) {
4825c523858385176c33a7456bb84035de78552d22dMarc Blank                if (response.isDataResponse(0, ImapConstants.LIST)) {
4835c523858385176c33a7456bb84035de78552d22dMarc Blank                    mImapStore.setPathSeparator(response.getStringOrEmpty(2).getString());
4845c523858385176c33a7456bb84035de78552d22dMarc Blank                }
4855c523858385176c33a7456bb84035de78552d22dMarc Blank            }
4865c523858385176c33a7456bb84035de78552d22dMarc Blank        }
4875c523858385176c33a7456bb84035de78552d22dMarc Blank    }
4885c523858385176c33a7456bb84035de78552d22dMarc Blank
4895c523858385176c33a7456bb84035de78552d22dMarc Blank    /**
4905c523858385176c33a7456bb84035de78552d22dMarc Blank     * Starts a TLS session with the IMAP server per RFC 3501. If the user has not opted
4915c523858385176c33a7456bb84035de78552d22dMarc Blank     * to use TLS or the server does not support the TLS capability, this will perform
4925c523858385176c33a7456bb84035de78552d22dMarc Blank     * no operation.
4935c523858385176c33a7456bb84035de78552d22dMarc Blank     */
4945c523858385176c33a7456bb84035de78552d22dMarc Blank    private ImapResponse doStartTls(boolean hasStartTlsCapability)
4955c523858385176c33a7456bb84035de78552d22dMarc Blank            throws IOException, MessagingException {
4965c523858385176c33a7456bb84035de78552d22dMarc Blank        if (mTransport.canTryTlsSecurity()) {
4975c523858385176c33a7456bb84035de78552d22dMarc Blank            if (hasStartTlsCapability) {
4985c523858385176c33a7456bb84035de78552d22dMarc Blank                // STARTTLS
4995c523858385176c33a7456bb84035de78552d22dMarc Blank                executeSimpleCommand(ImapConstants.STARTTLS);
5005c523858385176c33a7456bb84035de78552d22dMarc Blank
5015c523858385176c33a7456bb84035de78552d22dMarc Blank                mTransport.reopenTls();
5025c523858385176c33a7456bb84035de78552d22dMarc Blank                mTransport.setSoTimeout(MailTransport.SOCKET_READ_TIMEOUT);
5035c523858385176c33a7456bb84035de78552d22dMarc Blank                createParser();
5045c523858385176c33a7456bb84035de78552d22dMarc Blank                // Per RFC requirement (3501-6.2.1) gather new capabilities
5055c523858385176c33a7456bb84035de78552d22dMarc Blank                return(queryCapabilities());
5065c523858385176c33a7456bb84035de78552d22dMarc Blank            } else {
507bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook                if (Email.DEBUG) {
5085c523858385176c33a7456bb84035de78552d22dMarc Blank                    Log.d(Logging.LOG_TAG, "TLS not supported but required");
5095c523858385176c33a7456bb84035de78552d22dMarc Blank                }
5105c523858385176c33a7456bb84035de78552d22dMarc Blank                throw new MessagingException(MessagingException.TLS_REQUIRED);
5115c523858385176c33a7456bb84035de78552d22dMarc Blank            }
5125c523858385176c33a7456bb84035de78552d22dMarc Blank        }
5135c523858385176c33a7456bb84035de78552d22dMarc Blank        return null;
5145c523858385176c33a7456bb84035de78552d22dMarc Blank    }
5155c523858385176c33a7456bb84035de78552d22dMarc Blank
5165c523858385176c33a7456bb84035de78552d22dMarc Blank    /** @see DiscourseLogger#logLastDiscourse() */
5175c523858385176c33a7456bb84035de78552d22dMarc Blank    void logLastDiscourse() {
5185c523858385176c33a7456bb84035de78552d22dMarc Blank        mDiscourse.logLastDiscourse();
5195c523858385176c33a7456bb84035de78552d22dMarc Blank    }
5205c523858385176c33a7456bb84035de78552d22dMarc Blank}