Change delimiter in address fields from ASCII 0 to 1 (#5863)

Fixes search by sender name.

Co-authored-by: Fath <fath@147dda1a2773.ant.amazon.com>
This commit is contained in:
parkerfath 2022-01-14 10:40:28 -08:00 committed by GitHub
parent 343ead3fda
commit 722e6b923f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 7 deletions

View file

@ -12,7 +12,7 @@ import timber.log.Timber;
class StoreSchemaDefinition implements SchemaDefinition {
static final int DB_VERSION = 83;
static final int DB_VERSION = 84;
private final MigrationsHelper migrationsHelper;

View file

@ -0,0 +1,60 @@
package com.fsck.k9.storage.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import androidx.core.database.getStringOrNull
import com.fsck.k9.helper.map
/**
* Write the address fields to use ASCII 1 instead of ASCII 0 as separator.
* Separator was previously ASCII 0 but this caused problems with LIKE and searching.
*/
internal class MigrationTo84(private val db: SQLiteDatabase) {
fun rewriteAddresses() {
val addressSets = db.rawQuery(
"SELECT id, to_list, cc_list, bcc_list, reply_to_list, sender_list FROM messages WHERE empty = 0 AND deleted = 0",
null
).use { cursor ->
cursor.map {
val messageId = it.getLong(0)
messageId to AddressSet(
toList = it.getStringOrNull(1),
ccList = it.getStringOrNull(2),
bccList = it.getStringOrNull(3),
replyToList = it.getStringOrNull(4),
senderList = it.getStringOrNull(5)
)
}.toMap()
}
for ((messageId, addressSet) in addressSets) {
rewriteAddresses(messageId, addressSet)
}
}
private fun rewriteAddress(inAddress: String?): String? {
return inAddress?.replace(oldChar = '\u0000', newChar = '\u0001')
}
private fun rewriteAddresses(messageId: Long, addressSet: AddressSet) {
val cv = ContentValues().apply {
put("to_list", rewriteAddress(addressSet.toList))
put("cc_list", rewriteAddress(addressSet.ccList))
put("bcc_list", rewriteAddress(addressSet.bccList))
put("reply_to_list", rewriteAddress(addressSet.replyToList))
put("sender_list", rewriteAddress(addressSet.senderList))
}
db.update("messages", cv, "id = ?", arrayOf(messageId.toString()))
}
}
private data class AddressSet(
val toList: String?,
val ccList: String?,
val bccList: String?,
val replyToList: String?,
val senderList: String?
)

View file

@ -29,5 +29,6 @@ object Migrations {
if (oldVersion < 81) MigrationTo81(db).addNotificationsTable()
if (oldVersion < 82) MigrationTo82(db).addNewMessageColumn()
if (oldVersion < 83) MigrationTo83(db, migrationsHelper).rewriteHighestKnownUid()
if (oldVersion < 84) MigrationTo84(db).rewriteAddresses()
}
}

View file

@ -219,11 +219,11 @@ public class Address implements Serializable {
int pairEndIndex = 0;
int addressEndIndex = 0;
while (pairStartIndex < length) {
pairEndIndex = addressList.indexOf(",\u0000", pairStartIndex);
pairEndIndex = addressList.indexOf(",\u0001", pairStartIndex);
if (pairEndIndex == -1) {
pairEndIndex = length;
}
addressEndIndex = addressList.indexOf(";\u0000", pairStartIndex);
addressEndIndex = addressList.indexOf(";\u0001", pairStartIndex);
String address = null;
String personal = null;
if (addressEndIndex == -1 || addressEndIndex > pairEndIndex) {
@ -241,8 +241,8 @@ public class Address implements Serializable {
/**
* Packs an address list into a String that is very quick to read
* and parse. Packed lists can be unpacked with unpackAddressList()
* The packed list is a ",\u0000" separated list of:
* address;\u0000personal
* The packed list is a ",\u0001" separated list of:
* address;\u0001personal
* @param addresses Array of addresses to pack.
* @return Packed addresses.
*/
@ -256,13 +256,13 @@ public class Address implements Serializable {
sb.append(address.getAddress());
String personal = address.getPersonal();
if (personal != null) {
sb.append(";\u0000");
sb.append(";\u0001");
// Escape quotes in the address part on the way in
personal = personal.replaceAll("\"", "\\\"");
sb.append(personal);
}
if (i < count - 1) {
sb.append(",\u0000");
sb.append(",\u0001");
}
}
return sb.toString();