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}