JMAP: Implement Backend.setFlag()

This commit is contained in:
cketti 2020-02-17 20:04:38 +01:00
parent 4d4a04a5aa
commit 1deed00f45
4 changed files with 73 additions and 9 deletions

View file

@ -0,0 +1,55 @@
package com.fsck.k9.backend.jmap
import com.fsck.k9.mail.Flag
import rs.ltt.jmap.client.JmapClient
import rs.ltt.jmap.common.method.call.email.SetEmailMethodCall
import rs.ltt.jmap.common.method.response.email.SetEmailMethodResponse
import rs.ltt.jmap.common.util.Patches
import timber.log.Timber
class CommandSetFlag(
private val jmapClient: JmapClient,
private val accountId: String
) {
fun setFlag(messageServerIds: List<String>, flag: Flag, newState: Boolean) {
if (newState) {
Timber.v("Setting flag %s for messages %s", flag, messageServerIds)
} else {
Timber.v("Removing flag %s for messages %s", flag, messageServerIds)
}
val keyword = flag.toKeyword()
val keywordsPatch = if (newState) {
Patches.set("keywords/$keyword", true)
} else {
Patches.remove("keywords/$keyword")
}
val session = jmapClient.session.get()
val maxObjectsInSet = session.maxObjectsInSet
messageServerIds.chunked(maxObjectsInSet).forEach { emailIds ->
val updates = emailIds.map { emailId ->
emailId to keywordsPatch
}.toMap()
val setEmailCall = jmapClient.call(
SetEmailMethodCall.builder()
.accountId(accountId)
.update(updates)
.build()
)
setEmailCall.getMainResponseBlocking<SetEmailMethodResponse>()
}
}
private fun Flag.toKeyword(): String = when (this) {
Flag.SEEN -> "\$seen"
Flag.FLAGGED -> "\$flagged"
Flag.DRAFT -> "\$draft"
Flag.ANSWERED -> "\$answered"
Flag.FORWARDED -> "\$forwarded"
else -> error("Unsupported flag: $name")
}
}

View file

@ -17,7 +17,6 @@ import rs.ltt.jmap.client.api.UnauthorizedException
import rs.ltt.jmap.client.http.HttpAuthentication
import rs.ltt.jmap.client.session.Session
import rs.ltt.jmap.common.entity.Email
import rs.ltt.jmap.common.entity.capability.CoreCapability
import rs.ltt.jmap.common.entity.filter.EmailFilterCondition
import rs.ltt.jmap.common.entity.query.EmailQuery
import rs.ltt.jmap.common.method.call.email.GetEmailMethodCall
@ -173,7 +172,7 @@ class CommandSync(
Timber.d("New messages on server: %s", newServerIds)
val session = jmapClient.session.get()
val maxObjectsInGet = session.maxObjectsInGet()
val maxObjectsInGet = session.maxObjectsInGet
val messageInfoList = fetchMessageInfo(session, maxObjectsInGet, newServerIds)
val total = messageInfoList.size
@ -251,7 +250,7 @@ class CommandSync(
Timber.v("Fetching flags for messages: %s", emailIds)
val session = jmapClient.session.get()
val maxObjectsInGet = session.maxObjectsInGet()
val maxObjectsInGet = session.maxObjectsInGet
emailIds
.asSequence()
@ -296,11 +295,6 @@ class CommandSync(
else -> null
}
private fun Session.maxObjectsInGet(): Int {
val coreCapability = getCapability(CoreCapability::class.java)
return minOf(Int.MAX_VALUE.toLong(), coreCapability.maxObjectsInGet).toInt()
}
private fun BackendFolder.saveQueryState(queryState: String?) {
setFolderExtraString(EXTRA_QUERY_STATE, queryState)
}

View file

@ -28,6 +28,7 @@ class JmapBackend(
private val accountId = config.accountId
private val commandRefreshFolderList = CommandRefreshFolderList(backendStorage, jmapClient, accountId)
private val commandSync = CommandSync(backendStorage, jmapClient, okHttpClient, accountId, httpAuthentication)
private val commandSetFlag = CommandSetFlag(jmapClient, accountId)
override val supportsSeenFlag = true
override val supportsExpunge = false
override val supportsMove = true
@ -51,7 +52,7 @@ class JmapBackend(
}
override fun setFlag(folderServerId: String, messageServerIds: List<String>, flag: Flag, newState: Boolean) {
throw UnsupportedOperationException("not implemented")
commandSetFlag.setFlag(messageServerIds, flag, newState)
}
override fun markAllAsRead(folderServerId: String) {

View file

@ -4,6 +4,8 @@ import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.ExecutionException
import rs.ltt.jmap.client.JmapRequest
import rs.ltt.jmap.client.MethodResponses
import rs.ltt.jmap.client.session.Session
import rs.ltt.jmap.common.entity.capability.CoreCapability
import rs.ltt.jmap.common.method.MethodResponse
internal inline fun <reified T : MethodResponse> ListenableFuture<MethodResponses>.getMainResponseBlocking(): T {
@ -21,3 +23,15 @@ internal inline fun <T> ListenableFuture<T>.futureGetOrThrow(): T {
throw e.cause ?: e
}
}
internal val Session.maxObjectsInGet: Int
get() {
val coreCapability = getCapability(CoreCapability::class.java)
return coreCapability.maxObjectsInGet.coerceAtMost(Int.MAX_VALUE.toLong()).toInt()
}
internal val Session.maxObjectsInSet: Int
get() {
val coreCapability = getCapability(CoreCapability::class.java)
return coreCapability.maxObjectsInSet.coerceAtMost(Int.MAX_VALUE.toLong()).toInt()
}