Issue #1988, escape special chars in Migration51 content ID replacement

Without this fix, content IDs containing '$' would cause the replaceAll() to interpret the string as a capture group backreference and throw an ArrayIndexOutOfBoundsException, which would cause the migration to fail and all messages in the mailbox to be lost.
This commit is contained in:
Jason Khallouf 2017-12-09 13:55:19 +11:00
parent 1a12b18f0c
commit 79975cacd0

View file

@ -7,6 +7,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import android.content.ContentValues; import android.content.ContentValues;
@ -341,7 +342,7 @@ class MigrationTo51 {
private static MimeStructureState migrateComplexMailContent(SQLiteDatabase db, private static MimeStructureState migrateComplexMailContent(SQLiteDatabase db,
File attachmentDirOld, File attachmentDirNew, long messageId, String htmlContent, String textContent, File attachmentDirOld, File attachmentDirNew, long messageId, String htmlContent, String textContent,
MimeHeader mimeHeader, MimeStructureState structureState) throws IOException { MimeHeader mimeHeader, MimeStructureState structureState) throws IOException {
Timber.d("Processing mail with complex data structure as multipart/mixed"); Timber.d("Processing mail with complex data structure as multipart/mixed - message ID %d", messageId);
String boundary = MimeUtility.getHeaderParameter( String boundary = MimeUtility.getHeaderParameter(
mimeHeader.getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE), "boundary"); mimeHeader.getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE), "boundary");
@ -389,8 +390,9 @@ class MigrationTo51 {
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
String contentUriString = cursor.getString(0); String contentUriString = cursor.getString(0);
String contentId = cursor.getString(1); String contentId = cursor.getString(1);
// this is not super efficient, but occurs only once or twice // this is not super efficient, but occurs only once or twice
htmlContent = htmlContent.replaceAll(Pattern.quote(contentUriString), "cid:" + contentId); htmlContent = htmlContent.replaceAll(Pattern.quote(contentUriString), Matcher.quoteReplacement("cid:" + contentId));
} }
} finally { } finally {
cursor.close(); cursor.close();