Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7874fe7e authored by cketti's avatar cketti
Browse files

Properly handle responses to the IDLE command

When waiting for the command continuation request response ignore irrelevant responses and keep track of relevant untagged responses.
parent acbeff5b
Loading
Loading
Loading
Loading
+18 −6
Original line number Diff line number Diff line
@@ -91,13 +91,25 @@ internal class RealImapFolderIdler(
                idleSent = true
            }

            val initialResponse = connection.readResponse()
            if (!initialResponse.isContinuationRequested) {
                Timber.w("%s.idle(): Received something other than a continuation response", logTag)
            var receivedRelevantResponse = false
            do {
                val response = connection.readResponse()
                if (response.tag == tag) {
                    Timber.w("%s.idle(): IDLE command completed without a continuation request response", logTag)
                    return IdleResult.NOT_SUPPORTED
                } else if (response.isRelevant) {
                    receivedRelevantResponse = true
                }
            } while (!response.isContinuationRequested)

            if (receivedRelevantResponse) {
                Timber.v("%s.idle(): Received a relevant untagged response right after sending IDLE command", logTag)
                result = IdleResult.SYNC
                stopIdle = true
                sendDone()
            } else {
                connection.setSocketIdleReadTimeout()
            }

            var response: ImapResponse
            do {
+41 −0
Original line number Diff line number Diff line
@@ -294,6 +294,47 @@ class RealImapFolderIdlerTest {
        latch.awaitWithTimeout()
        assertThat(imapFolder.isOpen).isFalse()
    }

    @Test
    fun `irrelevant untagged response to IDLE command before continuation request`() {
        val latch = CountDownLatch(1)

        thread {
            val idleResult = idler.idle()

            assertThat(idleResult).isEqualTo(IdleResult.STOPPED)
            latch.countDown()
        }

        imapConnection.waitForCommand("IDLE")
        imapConnection.enqueueUntaggedServerResponse("OK irrelevant")
        imapConnection.enqueueContinuationServerResponse()

        wakeLock.waitForRelease()
        idler.stop()
        imapConnection.waitForCommand("DONE")
        imapConnection.enqueueTaggedServerResponse("OK")
        latch.awaitWithTimeout()
    }

    @Test
    fun `relevant untagged response to IDLE command before continuation request`() {
        val latch = CountDownLatch(1)

        thread {
            val idleResult = idler.idle()

            assertThat(idleResult).isEqualTo(IdleResult.SYNC)
            latch.countDown()
        }

        imapConnection.waitForCommand("IDLE")
        imapConnection.enqueueUntaggedServerResponse("1 EXISTS")
        imapConnection.enqueueContinuationServerResponse()
        imapConnection.waitForCommand("DONE")
        imapConnection.enqueueTaggedServerResponse("OK")
        latch.awaitWithTimeout()
    }
}

private fun CountDownLatch.awaitWithTimeout() {