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

Commit 037afd05 authored by cketti's avatar cketti
Browse files

Add support for UTF-8 data in BODYSTRUCTURE response

parent dd3d103f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ internal const val SEMICOLON = ';'
internal const val EQUALS_SIGN = '='
internal const val ASTERISK = '*'
internal const val SINGLE_QUOTE = '\''
internal const val BACKSLASH = '\\'

internal fun Char.isTSpecial() = this in TSPECIALS

+17 −1
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ object MimeParameterEncoder {

    private fun String.isQuotable() = all { it.isQuotable() }

    fun String.quoted(): String {
    private fun String.quoted(): String {
        // quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS]
        // qcontent      = qtext / quoted-pair
        // quoted-pair   = ("\" (VCHAR / WSP))
@@ -165,6 +165,22 @@ object MimeParameterEncoder {
        }
    }

    // RFC 6532-style header values
    // Right now we only create such values for internal use (see IMAP BODYSTRUCTURE response parsing code)
    fun String.quotedUtf8(): String {
        return buildString(capacity = length + 16) {
            append(DQUOTE)
            for (c in this@quotedUtf8) {
                if (c == DQUOTE || c == BACKSLASH) {
                    append('\\').append(c)
                } else {
                    append(c)
                }
            }
            append(DQUOTE)
        }
    }

    private fun String.quotedLength(): Int {
        var length = 2 /* start and end quote */
        for (c in this) {
+3 −5
Original line number Diff line number Diff line
@@ -16,14 +16,12 @@ import com.fsck.k9.mail.internet.MimeHeader
import com.fsck.k9.mail.internet.MimeMessageHelper
import com.fsck.k9.mail.internet.MimeMultipart
import com.fsck.k9.mail.internet.MimeParameterEncoder.isToken
import com.fsck.k9.mail.internet.MimeParameterEncoder.quoted
import com.fsck.k9.mail.internet.MimeParameterEncoder.quotedUtf8
import com.fsck.k9.mail.internet.MimeUtility
import java.io.IOException
import java.io.InputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.HashMap
import java.util.LinkedHashSet
import java.util.Locale
import kotlin.math.max
import kotlin.math.min
@@ -891,7 +889,7 @@ internal class RealImapFolder(
                for (i in bodyParams.indices step 2) {
                    val paramName = bodyParams.getString(i)
                    val paramValue = bodyParams.getString(i + 1)
                    val encodedValue = if (paramValue.isToken()) paramValue else paramValue.quoted()
                    val encodedValue = if (paramValue.isToken()) paramValue else paramValue.quotedUtf8()
                    contentType.append(String.format(";\r\n %s=%s", paramName, encodedValue))
                }
            }
@@ -918,7 +916,7 @@ internal class RealImapFolder(
                    for (i in bodyDispositionParams.indices step 2) {
                        val paramName = bodyDispositionParams.getString(i).lowercase()
                        val paramValue = bodyDispositionParams.getString(i + 1)
                        val encodedValue = if (paramValue.isToken()) paramValue else paramValue.quoted()
                        val encodedValue = if (paramValue.isToken()) paramValue else paramValue.quotedUtf8()
                        contentDisposition.append(String.format(";\r\n %s=%s", paramName, encodedValue))
                    }
                }
+19 −0
Original line number Diff line number Diff line
@@ -770,6 +770,15 @@ class RealImapFolderTest {
        )
    }

    @Test
    fun `fetch() with UTF-8 encoded content type parameter`() {
        testHeaderFromBodyStructure(
            bodyStructure = """("text" "plain" ("name" "filenäme.ext") NIL NIL "7bit" 42 23)""",
            headerName = MimeHeader.HEADER_CONTENT_TYPE,
            expectedHeaderValue = "text/plain;\r\n name=\"filenäme.ext\""
        )
    }

    @Test
    fun `fetch() with simple content disposition parameter`() {
        testHeaderFromBodyStructure(
@@ -810,6 +819,16 @@ class RealImapFolderTest {
        )
    }

    @Test
    fun `fetch() with UTF-8 encoded content disposition parameter`() {
        testHeaderFromBodyStructure(
            bodyStructure = """("application" "octet-stream" NIL NIL NIL "8bit" 23 NIL """ +
                """("attachment" ("filename" "filenäme.ext")) NIL NIL)""",
            headerName = MimeHeader.HEADER_CONTENT_DISPOSITION,
            expectedHeaderValue = "attachment;\r\n filename=\"filenäme.ext\";\r\n size=23"
        )
    }

    @Test
    fun fetch_withBodySaneFetchProfile_shouldIssueRespectiveCommand() {
        val folder = createFolder("Folder")