diff options
author | Jorge Ruesga <jorge@ruesga.com> | 2015-05-01 21:35:23 +0200 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2015-10-18 14:05:32 -0700 |
commit | 08ace26ed605946d788ce56f5c9aefc65131a63b (patch) | |
tree | f1014dc39087078bf19111b76427ab58ba78ad4b /provider_src/com/android/email/mail/store/ImapConnection.java | |
parent | 3b1b30873e9c07139e2cc9fdaa796151592fea69 (diff) | |
download | android_packages_apps_Email-08ace26ed605946d788ce56f5c9aefc65131a63b.tar.gz android_packages_apps_Email-08ace26ed605946d788ce56f5c9aefc65131a63b.tar.bz2 android_packages_apps_Email-08ace26ed605946d788ce56f5c9aefc65131a63b.zip |
email: imap push
Change-Id: I8a184a5644e4322ee65d969e14cd47fe119f5df2
Signed-off-by: Jorge Ruesga <jorge@ruesga.com>
Diffstat (limited to 'provider_src/com/android/email/mail/store/ImapConnection.java')
-rw-r--r-- | provider_src/com/android/email/mail/store/ImapConnection.java | 85 |
1 files changed, 77 insertions, 8 deletions
diff --git a/provider_src/com/android/email/mail/store/ImapConnection.java b/provider_src/com/android/email/mail/store/ImapConnection.java index bf4bb2a4c..bef5f346e 100644 --- a/provider_src/com/android/email/mail/store/ImapConnection.java +++ b/provider_src/com/android/email/mail/store/ImapConnection.java @@ -36,6 +36,7 @@ import com.android.emailcommon.mail.MessagingException; import com.android.mail.utils.LogUtils; import java.io.IOException; +import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -50,6 +51,15 @@ class ImapConnection { // Always check in FALSE private static final boolean DEBUG_FORCE_SEND_ID = false; + // RFC 2177 defines that IDLE connections must be refreshed at least every 29 minutes + public static final int PING_IDLE_TIMEOUT = 29 * 60 * 1000; + + // Special timeout for DONE operations + public static final int DONE_TIMEOUT = 5 * 1000; + + // Time to wait between the first idle message and triggering the changes + private static final int IDLE_OP_READ_TIMEOUT = 500; + /** ID capability per RFC 2971*/ public static final int CAPABILITY_ID = 1 << 0; /** NAMESPACE capability per RFC 2342 */ @@ -58,6 +68,8 @@ class ImapConnection { public static final int CAPABILITY_STARTTLS = 1 << 2; /** UIDPLUS capability per RFC 4315 */ public static final int CAPABILITY_UIDPLUS = 1 << 3; + /** IDLE capability per RFC 2177 */ + public static final int CAPABILITY_IDLE = 1 << 4; /** The capabilities supported; a set of CAPABILITY_* values. */ private int mCapabilities; @@ -69,6 +81,8 @@ class ImapConnection { private String mAccessToken; private String mIdPhrase = null; + private boolean mIdling = false; + /** # of command/response lines to log upon crash. */ private static final int DISCOURSE_LOGGER_SIZE = 64; private final DiscourseLogger mDiscourse = new DiscourseLogger(DISCOURSE_LOGGER_SIZE); @@ -210,10 +224,23 @@ class ImapConnection { mImapStore = null; } + int getReadTimeout() throws IOException { + if (mTransport == null) { + return MailTransport.SOCKET_READ_TIMEOUT; + } + return mTransport.getReadTimeout(); + } + + void setReadTimeout(int timeout) throws IOException { + if (mTransport != null) { + mTransport.setReadTimeout(timeout); + } + } + /** * Returns whether or not the specified capability is supported by the server. */ - private boolean isCapable(int capability) { + public boolean isCapable(int capability) { return (mCapabilities & capability) != 0; } @@ -235,6 +262,9 @@ class ImapConnection { if (capabilities.contains(ImapConstants.STARTTLS)) { mCapabilities |= CAPABILITY_STARTTLS; } + if (capabilities.contains(ImapConstants.IDLE)) { + mCapabilities |= CAPABILITY_IDLE; + } } /** @@ -273,6 +303,12 @@ class ImapConnection { */ String sendCommand(String command, boolean sensitive) throws MessagingException, IOException { + // Don't allow any command other than DONE when idling + if (mIdling && !command.equals(ImapConstants.DONE)) { + return null; + } + mIdling = command.equals(ImapConstants.IDLE); + LogUtils.d(Logging.LOG_TAG, "sendCommand %s", (sensitive ? IMAP_REDACTED_LOG : command)); open(); return sendCommandInternal(command, sensitive); @@ -284,7 +320,13 @@ class ImapConnection { throw new IOException("Null transport"); } String tag = Integer.toString(mNextCommandTag.incrementAndGet()); - String commandToSend = tag + " " + command; + final String commandToSend; + if (command.equals(ImapConstants.DONE)) { + // Do not send a tag for DONE command + commandToSend = command; + } else { + commandToSend = tag + " " + command; + } mTransport.writeLine(commandToSend, sensitive ? IMAP_REDACTED_LOG : null); mDiscourse.addSentCommand(sensitive ? IMAP_REDACTED_LOG : commandToSend); return tag; @@ -327,6 +369,11 @@ class ImapConnection { return executeSimpleCommand(command, false); } + List<ImapResponse> executeIdleCommand() throws IOException, MessagingException { + mParser.expectIdlingResponse(); + return executeSimpleCommand(ImapConstants.IDLE, false); + } + /** * Read and return all of the responses from the most recent command sent to the server * @@ -336,13 +383,35 @@ class ImapConnection { */ List<ImapResponse> getCommandResponses() throws IOException, MessagingException { final List<ImapResponse> responses = new ArrayList<ImapResponse>(); - ImapResponse response; - do { - response = mParser.readResponse(); - responses.add(response); - } while (!response.isTagged()); + ImapResponse response = null; + boolean idling = false; + boolean throwSocketTimeoutEx = true; + int lastSocketTimeout = getReadTimeout(); + try { + do { + response = mParser.readResponse(); + if (idling) { + setReadTimeout(IDLE_OP_READ_TIMEOUT); + throwSocketTimeoutEx = false; + } + responses.add(response); + if (response.isIdling()) { + idling = true; + } + } while (idling || !response.isTagged()); + } catch (SocketTimeoutException ex) { + if (throwSocketTimeoutEx) { + throw ex; + } + } finally { + mParser.resetIdlingStatus(); + if (lastSocketTimeout != getReadTimeout()) { + setReadTimeout(lastSocketTimeout); + } + } - if (!response.isOk()) { + // When idling, any response is valid; otherwise it must be OK + if (!response.isOk() && !idling) { final String toString = response.toString(); final String status = response.getStatusOrEmpty().getString(); final String alert = response.getAlertTextOrEmpty().getString(); |