Add interface for detection of encrypted messages
This includes some capabilities that are not currently used by K-9 Mail, e.g. the ability to supply additional data to be inserted into the database.
This commit is contained in:
parent
18bbd76783
commit
a8f41118e3
21 changed files with 217 additions and 84 deletions
|
@ -0,0 +1,17 @@
|
|||
package com.fsck.k9.crypto
|
||||
|
||||
import android.content.ContentValues
|
||||
import com.fsck.k9.mail.Message
|
||||
import com.fsck.k9.message.extractors.PreviewResult
|
||||
|
||||
interface EncryptionExtractor {
|
||||
fun extractEncryption(message: Message): EncryptionResult?
|
||||
}
|
||||
|
||||
data class EncryptionResult(
|
||||
val encryptionType: String,
|
||||
val attachmentCount: Int,
|
||||
val previewResult: PreviewResult = PreviewResult.encrypted(),
|
||||
val textForSearchIndex: String? = null,
|
||||
val extraContentValues: ContentValues? = null
|
||||
)
|
|
@ -31,6 +31,8 @@ import com.fsck.k9.DI;
|
|||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.controller.MessageReference;
|
||||
import com.fsck.k9.backend.api.MessageRemovalListener;
|
||||
import com.fsck.k9.crypto.EncryptionExtractor;
|
||||
import com.fsck.k9.crypto.EncryptionResult;
|
||||
import com.fsck.k9.helper.FileHelper;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.Address;
|
||||
|
@ -77,6 +79,7 @@ public class LocalFolder extends Folder<LocalMessage> {
|
|||
private final SearchStatusManager searchStatusManager = DI.get(SearchStatusManager.class);
|
||||
private final LocalStore localStore;
|
||||
private final AttachmentInfoExtractor attachmentInfoExtractor;
|
||||
private final EncryptionExtractor encryptionExtractor = DI.get(EncryptionExtractor.class);
|
||||
|
||||
|
||||
private String serverId = null;
|
||||
|
@ -1379,17 +1382,34 @@ public class LocalFolder extends Folder<LocalMessage> {
|
|||
}
|
||||
|
||||
try {
|
||||
MessagePreviewCreator previewCreator = localStore.getMessagePreviewCreator();
|
||||
PreviewResult previewResult = previewCreator.createPreview(message);
|
||||
String encryptionType;
|
||||
PreviewResult previewResult;
|
||||
int attachmentCount;
|
||||
String fulltext;
|
||||
ContentValues extraContentValues;
|
||||
|
||||
EncryptionResult encryptionResult = encryptionExtractor.extractEncryption(message);
|
||||
if (encryptionResult != null) {
|
||||
encryptionType = encryptionResult.getEncryptionType();
|
||||
previewResult = encryptionResult.getPreviewResult();
|
||||
attachmentCount = encryptionResult.getAttachmentCount();
|
||||
fulltext = encryptionResult.getTextForSearchIndex();
|
||||
extraContentValues = encryptionResult.getExtraContentValues();
|
||||
} else {
|
||||
MessagePreviewCreator previewCreator = localStore.getMessagePreviewCreator();
|
||||
MessageFulltextCreator fulltextCreator = localStore.getMessageFulltextCreator();
|
||||
AttachmentCounter attachmentCounter = localStore.getAttachmentCounter();
|
||||
|
||||
encryptionType = null;
|
||||
previewResult = previewCreator.createPreview(message);
|
||||
attachmentCount = attachmentCounter.getAttachmentCount(message);
|
||||
fulltext = fulltextCreator.createFulltext(message);
|
||||
extraContentValues = null;
|
||||
}
|
||||
|
||||
PreviewType previewType = previewResult.getPreviewType();
|
||||
DatabasePreviewType databasePreviewType = DatabasePreviewType.fromPreviewType(previewType);
|
||||
|
||||
MessageFulltextCreator fulltextCreator = localStore.getMessageFulltextCreator();
|
||||
String fulltext = fulltextCreator.createFulltext(message);
|
||||
|
||||
AttachmentCounter attachmentCounter = localStore.getAttachmentCounter();
|
||||
int attachmentCount = attachmentCounter.getAttachmentCount(message);
|
||||
|
||||
long rootMessagePartId = saveMessageParts(db, message);
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
|
@ -1415,6 +1435,7 @@ public class LocalFolder extends Folder<LocalMessage> {
|
|||
? System.currentTimeMillis() : message.getInternalDate().getTime());
|
||||
cv.put("mime_type", message.getMimeType());
|
||||
cv.put("empty", 0);
|
||||
cv.put("encryption_type", encryptionType);
|
||||
|
||||
cv.put("preview_type", databasePreviewType.getDatabaseValue());
|
||||
if (previewResult.isPreviewTextAvailable()) {
|
||||
|
@ -1428,6 +1449,10 @@ public class LocalFolder extends Folder<LocalMessage> {
|
|||
cv.put("message_id", messageId);
|
||||
}
|
||||
|
||||
if (extraContentValues != null) {
|
||||
cv.putAll(extraContentValues);
|
||||
}
|
||||
|
||||
if (oldMessageId == -1) {
|
||||
msgId = db.insert("messages", "uid", cv);
|
||||
|
||||
|
|
|
@ -11,24 +11,12 @@ import com.fsck.k9.mail.internet.MessageExtractor;
|
|||
|
||||
|
||||
public class AttachmentCounter {
|
||||
private final EncryptionDetector encryptionDetector;
|
||||
|
||||
|
||||
AttachmentCounter(EncryptionDetector encryptionDetector) {
|
||||
this.encryptionDetector = encryptionDetector;
|
||||
}
|
||||
|
||||
public static AttachmentCounter newInstance() {
|
||||
TextPartFinder textPartFinder = new TextPartFinder();
|
||||
EncryptionDetector encryptionDetector = new EncryptionDetector(textPartFinder);
|
||||
return new AttachmentCounter(encryptionDetector);
|
||||
return new AttachmentCounter();
|
||||
}
|
||||
|
||||
public int getAttachmentCount(Message message) throws MessagingException {
|
||||
if (encryptionDetector.isEncrypted(message)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<Part> attachmentParts = new ArrayList<>();
|
||||
MessageExtractor.findViewablesAndAttachments(message, null, attachmentParts);
|
||||
|
||||
|
|
|
@ -15,29 +15,18 @@ public class MessageFulltextCreator {
|
|||
|
||||
|
||||
private final TextPartFinder textPartFinder;
|
||||
private final EncryptionDetector encryptionDetector;
|
||||
|
||||
|
||||
MessageFulltextCreator(TextPartFinder textPartFinder, EncryptionDetector encryptionDetector) {
|
||||
MessageFulltextCreator(TextPartFinder textPartFinder) {
|
||||
this.textPartFinder = textPartFinder;
|
||||
this.encryptionDetector = encryptionDetector;
|
||||
}
|
||||
|
||||
public static MessageFulltextCreator newInstance() {
|
||||
TextPartFinder textPartFinder = new TextPartFinder();
|
||||
EncryptionDetector encryptionDetector = new EncryptionDetector(textPartFinder);
|
||||
return new MessageFulltextCreator(textPartFinder, encryptionDetector);
|
||||
return new MessageFulltextCreator(textPartFinder);
|
||||
}
|
||||
|
||||
public String createFulltext(@NonNull Message message) {
|
||||
if (encryptionDetector.isEncrypted(message)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return extractText(message);
|
||||
}
|
||||
|
||||
private String extractText(Message message) {
|
||||
Part textPart = textPartFinder.findFirstTextPart(message);
|
||||
if (textPart == null || hasEmptyBody(textPart)) {
|
||||
return null;
|
||||
|
|
|
@ -10,32 +10,20 @@ import com.fsck.k9.mail.Part;
|
|||
public class MessagePreviewCreator {
|
||||
private final TextPartFinder textPartFinder;
|
||||
private final PreviewTextExtractor previewTextExtractor;
|
||||
private final EncryptionDetector encryptionDetector;
|
||||
|
||||
|
||||
MessagePreviewCreator(TextPartFinder textPartFinder, PreviewTextExtractor previewTextExtractor,
|
||||
EncryptionDetector encryptionDetector) {
|
||||
MessagePreviewCreator(TextPartFinder textPartFinder, PreviewTextExtractor previewTextExtractor) {
|
||||
this.textPartFinder = textPartFinder;
|
||||
this.previewTextExtractor = previewTextExtractor;
|
||||
this.encryptionDetector = encryptionDetector;
|
||||
}
|
||||
|
||||
public static MessagePreviewCreator newInstance() {
|
||||
TextPartFinder textPartFinder = new TextPartFinder();
|
||||
PreviewTextExtractor previewTextExtractor = new PreviewTextExtractor();
|
||||
EncryptionDetector encryptionDetector = new EncryptionDetector(textPartFinder);
|
||||
return new MessagePreviewCreator(textPartFinder, previewTextExtractor, encryptionDetector);
|
||||
return new MessagePreviewCreator(textPartFinder, previewTextExtractor);
|
||||
}
|
||||
|
||||
public PreviewResult createPreview(@NonNull Message message) {
|
||||
if (encryptionDetector.isEncrypted(message)) {
|
||||
return PreviewResult.encrypted();
|
||||
}
|
||||
|
||||
return extractText(message);
|
||||
}
|
||||
|
||||
private PreviewResult extractText(Message message) {
|
||||
Part textPart = textPartFinder.findFirstTextPart(message);
|
||||
if (textPart == null || hasEmptyBody(textPart)) {
|
||||
return PreviewResult.none();
|
||||
|
|
|
@ -12,7 +12,7 @@ import com.fsck.k9.mail.Part;
|
|||
import static com.fsck.k9.mail.internet.MimeUtility.isSameMimeType;
|
||||
|
||||
|
||||
class TextPartFinder {
|
||||
public class TextPartFinder {
|
||||
@Nullable
|
||||
public Part findFirstTextPart(@NonNull Part part) {
|
||||
String mimeType = part.getMimeType();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.fsck.k9
|
||||
|
||||
import android.app.Application
|
||||
import com.fsck.k9.crypto.EncryptionExtractor
|
||||
import com.fsck.k9.storage.storageModule
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import org.koin.dsl.module.applicationContext
|
||||
|
@ -20,4 +21,5 @@ class TestApp : Application() {
|
|||
val testModule = applicationContext {
|
||||
bean { AppConfig(emptyList()) }
|
||||
bean { mock<CoreResourceProvider>() }
|
||||
bean { mock<EncryptionExtractor>() }
|
||||
}
|
||||
|
|
|
@ -21,35 +21,19 @@ import static org.mockito.Mockito.when;
|
|||
public class MessagePreviewCreatorTest {
|
||||
private TextPartFinder textPartFinder;
|
||||
private PreviewTextExtractor previewTextExtractor;
|
||||
private EncryptionDetector encryptionDetector;
|
||||
private MessagePreviewCreator previewCreator;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
textPartFinder = mock(TextPartFinder.class);
|
||||
previewTextExtractor = mock(PreviewTextExtractor.class);
|
||||
encryptionDetector = mock(EncryptionDetector.class);
|
||||
|
||||
previewCreator = new MessagePreviewCreator(textPartFinder, previewTextExtractor, encryptionDetector);
|
||||
previewCreator = new MessagePreviewCreator(textPartFinder, previewTextExtractor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPreview_withEncryptedMessage() throws Exception {
|
||||
public void createPreview_withoutTextPart() {
|
||||
Message message = createDummyMessage();
|
||||
when(encryptionDetector.isEncrypted(message)).thenReturn(true);
|
||||
|
||||
PreviewResult result = previewCreator.createPreview(message);
|
||||
|
||||
assertFalse(result.isPreviewTextAvailable());
|
||||
assertEquals(PreviewType.ENCRYPTED, result.getPreviewType());
|
||||
verifyNoMoreInteractions(textPartFinder);
|
||||
verifyNoMoreInteractions(previewTextExtractor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPreview_withoutTextPart() throws Exception {
|
||||
Message message = createDummyMessage();
|
||||
when(encryptionDetector.isEncrypted(message)).thenReturn(false);
|
||||
when(textPartFinder.findFirstTextPart(message)).thenReturn(null);
|
||||
|
||||
PreviewResult result = previewCreator.createPreview(message);
|
||||
|
@ -63,7 +47,6 @@ public class MessagePreviewCreatorTest {
|
|||
public void createPreview_withEmptyTextPart() throws Exception {
|
||||
Message message = createDummyMessage();
|
||||
Part textPart = createEmptyPart("text/plain");
|
||||
when(encryptionDetector.isEncrypted(message)).thenReturn(false);
|
||||
when(textPartFinder.findFirstTextPart(message)).thenReturn(textPart);
|
||||
|
||||
PreviewResult result = previewCreator.createPreview(message);
|
||||
|
@ -77,7 +60,6 @@ public class MessagePreviewCreatorTest {
|
|||
public void createPreview_withTextPart() throws Exception {
|
||||
Message message = createDummyMessage();
|
||||
Part textPart = createTextPart("text/plain");
|
||||
when(encryptionDetector.isEncrypted(message)).thenReturn(false);
|
||||
when(textPartFinder.findFirstTextPart(message)).thenReturn(textPart);
|
||||
when(previewTextExtractor.extractPreview(textPart)).thenReturn("expected");
|
||||
|
||||
|
@ -92,7 +74,6 @@ public class MessagePreviewCreatorTest {
|
|||
public void createPreview_withPreviewTextExtractorThrowing() throws Exception {
|
||||
Message message = createDummyMessage();
|
||||
Part textPart = createTextPart("text/plain");
|
||||
when(encryptionDetector.isEncrypted(message)).thenReturn(false);
|
||||
when(textPartFinder.findFirstTextPart(message)).thenReturn(textPart);
|
||||
when(previewTextExtractor.extractPreview(textPart)).thenThrow(new PreviewExtractionException(""));
|
||||
|
||||
|
|
33
app/crypto-openpgp/build.gradle
Normal file
33
app/crypto-openpgp/build.gradle
Normal file
|
@ -0,0 +1,33 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'org.jetbrains.kotlin.android'
|
||||
|
||||
apply from: "${rootProject.projectDir}/gradle/plugins/checkstyle-android.gradle"
|
||||
apply from: "${rootProject.projectDir}/gradle/plugins/findbugs-android.gradle"
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
|
||||
|
||||
implementation project(":app:core")
|
||||
|
||||
testImplementation "junit:junit:${versions.junit}"
|
||||
testImplementation "org.mockito:mockito-core:${versions.mockito}"
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion buildConfig.compileSdk
|
||||
buildToolsVersion buildConfig.buildTools
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion buildConfig.minSdk
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
lintConfig file("$rootProject.projectDir/config/lint/lint.xml")
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
}
|
2
app/crypto-openpgp/src/main/AndroidManifest.xml
Normal file
2
app/crypto-openpgp/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.fsck.k9.crypto.openpgp" />
|
|
@ -1,4 +1,4 @@
|
|||
package com.fsck.k9.message.extractors;
|
||||
package com.fsck.k9.crypto.openpgp;
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
@ -9,10 +9,12 @@ import com.fsck.k9.mail.BodyPart;
|
|||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Multipart;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.message.extractors.TextPartFinder;
|
||||
|
||||
import static com.fsck.k9.mail.internet.MimeUtility.isSameMimeType;
|
||||
|
||||
|
||||
//FIXME: Make this only detect OpenPGP messages. Move support for S/MIME messages to separate module.
|
||||
class EncryptionDetector {
|
||||
private final TextPartFinder textPartFinder;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.fsck.k9.crypto.openpgp
|
||||
|
||||
import com.fsck.k9.crypto.EncryptionExtractor
|
||||
import com.fsck.k9.crypto.EncryptionResult
|
||||
import com.fsck.k9.mail.Message
|
||||
import com.fsck.k9.message.extractors.TextPartFinder
|
||||
|
||||
class OpenPgpEncryptionExtractor internal constructor(
|
||||
private val encryptionDetector: EncryptionDetector
|
||||
) : EncryptionExtractor {
|
||||
|
||||
override fun extractEncryption(message: Message): EncryptionResult? {
|
||||
return if (encryptionDetector.isEncrypted(message)) {
|
||||
EncryptionResult(ENCRYPTION_TYPE, 0)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val ENCRYPTION_TYPE = "openpgp"
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(): OpenPgpEncryptionExtractor {
|
||||
val textPartFinder = TextPartFinder()
|
||||
val encryptionDetector = EncryptionDetector(textPartFinder)
|
||||
return OpenPgpEncryptionExtractor(encryptionDetector)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,15 @@
|
|||
package com.fsck.k9.message.extractors;
|
||||
package com.fsck.k9.crypto.openpgp;
|
||||
|
||||
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.message.extractors.TextPartFinder;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.fsck.k9.message.MessageCreationHelper.createMessage;
|
||||
import static com.fsck.k9.message.MessageCreationHelper.createMultipartMessage;
|
||||
import static com.fsck.k9.message.MessageCreationHelper.createPart;
|
||||
import static com.fsck.k9.message.MessageCreationHelper.createTextMessage;
|
||||
import static com.fsck.k9.crypto.openpgp.MessageCreationHelper.createMessage;
|
||||
import static com.fsck.k9.crypto.openpgp.MessageCreationHelper.createMultipartMessage;
|
||||
import static com.fsck.k9.crypto.openpgp.MessageCreationHelper.createPart;
|
||||
import static com.fsck.k9.crypto.openpgp.MessageCreationHelper.createTextMessage;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
@ -24,14 +25,14 @@ public class EncryptionDetectorTest {
|
|||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
public void setUp() {
|
||||
textPartFinder = mock(TextPartFinder.class);
|
||||
|
||||
encryptionDetector = new EncryptionDetector(textPartFinder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEncrypted_withTextPlain_shouldReturnFalse() throws Exception {
|
||||
public void isEncrypted_withTextPlain_shouldReturnFalse() {
|
||||
Message message = createTextMessage("text/plain", "plain text");
|
||||
|
||||
boolean encrypted = encryptionDetector.isEncrypted(message);
|
||||
|
@ -50,7 +51,7 @@ public class EncryptionDetectorTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void isEncrypted_withSMimePart_shouldReturnTrue() throws Exception {
|
||||
public void isEncrypted_withSMimePart_shouldReturnTrue() {
|
||||
Message message = createMessage("application/pkcs7-mime");
|
||||
|
||||
boolean encrypted = encryptionDetector.isEncrypted(message);
|
||||
|
@ -69,7 +70,7 @@ public class EncryptionDetectorTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void isEncrypted_withInlinePgp_shouldReturnTrue() throws Exception {
|
||||
public void isEncrypted_withInlinePgp_shouldReturnTrue() {
|
||||
Message message = createTextMessage("text/plain", "" +
|
||||
"-----BEGIN PGP MESSAGE-----" + CRLF +
|
||||
"some encrypted stuff here" + CRLF +
|
||||
|
@ -82,7 +83,7 @@ public class EncryptionDetectorTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void isEncrypted_withPlainTextAndPreambleWithInlinePgp_shouldReturnFalse() throws Exception {
|
||||
public void isEncrypted_withPlainTextAndPreambleWithInlinePgp_shouldReturnFalse() {
|
||||
Message message = createTextMessage("text/plain", "" +
|
||||
"preamble" + CRLF +
|
||||
"-----BEGIN PGP MESSAGE-----" + CRLF +
|
||||
|
@ -97,7 +98,7 @@ public class EncryptionDetectorTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void isEncrypted_withQuotedInlinePgp_shouldReturnFalse() throws Exception {
|
||||
public void isEncrypted_withQuotedInlinePgp_shouldReturnFalse() {
|
||||
Message message = createTextMessage("text/plain", "" +
|
||||
"good talk!" + CRLF +
|
||||
CRLF +
|
|
@ -0,0 +1,51 @@
|
|||
package com.fsck.k9.crypto.openpgp;
|
||||
|
||||
|
||||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||
import com.fsck.k9.mail.internet.MimeHeader;
|
||||
import com.fsck.k9.mail.internet.MimeMessage;
|
||||
import com.fsck.k9.mail.internet.MimeMultipart;
|
||||
import com.fsck.k9.mail.internet.TextBody;
|
||||
import com.fsck.k9.mailstore.BinaryMemoryBody;
|
||||
|
||||
|
||||
public class MessageCreationHelper {
|
||||
public static BodyPart createPart(String mimeType) throws MessagingException {
|
||||
BinaryMemoryBody body = new BinaryMemoryBody(new byte[0], "utf-8");
|
||||
return new MimeBodyPart(body, mimeType);
|
||||
}
|
||||
|
||||
public static Message createTextMessage(String mimeType, String text) {
|
||||
TextBody body = new TextBody(text);
|
||||
return createMessage(mimeType, body);
|
||||
}
|
||||
|
||||
public static Message createMultipartMessage(String mimeType, BodyPart... parts) {
|
||||
MimeMultipart body = createMultipartBody(mimeType, parts);
|
||||
return createMessage(mimeType, body);
|
||||
}
|
||||
|
||||
public static Message createMessage(String mimeType) {
|
||||
return createMessage(mimeType, null);
|
||||
}
|
||||
|
||||
private static Message createMessage(String mimeType, Body body) {
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setBody(body);
|
||||
message.setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
private static MimeMultipart createMultipartBody(String mimeType, BodyPart[] parts) {
|
||||
MimeMultipart multipart = new MimeMultipart(mimeType, "boundary");
|
||||
for (BodyPart part : parts) {
|
||||
multipart.addBodyPart(part);
|
||||
}
|
||||
return multipart;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ dependencies {
|
|||
implementation project(":app:ui")
|
||||
implementation project(":app:core")
|
||||
implementation project(":app:storage")
|
||||
implementation project(":app:crypto-openpgp")
|
||||
implementation project(":backend:imap")
|
||||
implementation project(":backend:pop3")
|
||||
implementation project(":backend:webdav")
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.fsck.k9
|
|||
|
||||
import com.fsck.k9.backends.backendsModule
|
||||
import com.fsck.k9.controller.ControllerExtension
|
||||
import com.fsck.k9.crypto.EncryptionExtractor
|
||||
import com.fsck.k9.crypto.openpgp.OpenPgpEncryptionExtractor
|
||||
import com.fsck.k9.external.BroadcastSenderListener
|
||||
import com.fsck.k9.external.externalModule
|
||||
import com.fsck.k9.notification.notificationModule
|
||||
|
@ -23,6 +25,7 @@ private val mainAppModule = applicationContext {
|
|||
))
|
||||
}
|
||||
bean("controllerExtensions") { emptyList<ControllerExtension>() }
|
||||
bean { OpenPgpEncryptionExtractor.newInstance() as EncryptionExtractor }
|
||||
}
|
||||
|
||||
val appModules = listOf(
|
||||
|
|
|
@ -12,7 +12,7 @@ import timber.log.Timber;
|
|||
|
||||
|
||||
class StoreSchemaDefinition implements SchemaDefinition {
|
||||
static final int DB_VERSION = 65;
|
||||
static final int DB_VERSION = 66;
|
||||
|
||||
private final MigrationsHelper migrationsHelper;
|
||||
|
||||
|
@ -134,7 +134,8 @@ class StoreSchemaDefinition implements SchemaDefinition {
|
|||
"flagged INTEGER default 0, " +
|
||||
"answered INTEGER default 0, " +
|
||||
"forwarded INTEGER default 0, " +
|
||||
"message_part_id INTEGER" +
|
||||
"message_part_id INTEGER," +
|
||||
"encryption_type TEXT" +
|
||||
")");
|
||||
|
||||
db.execSQL("DROP TABLE IF EXISTS message_parts");
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.fsck.k9.storage.migrations
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
|
||||
|
||||
internal object MigrationTo66 {
|
||||
@JvmStatic
|
||||
fun addEncryptionTypeColumnToMessagesTable(db: SQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE messages ADD encryption_type TEXT")
|
||||
|
||||
db.execSQL("UPDATE messages SET encryption_type = 'openpgp' WHERE preview_type = 'encrypted'")
|
||||
}
|
||||
}
|
|
@ -88,6 +88,8 @@ public class Migrations {
|
|||
MigrationTo64.addExtraValuesTables(db);
|
||||
case 64:
|
||||
MigrationTo65.addLocalOnlyColumnToFoldersTable(db, migrationsHelper);
|
||||
case 65:
|
||||
MigrationTo66.addEncryptionTypeColumnToMessagesTable(db);
|
||||
}
|
||||
|
||||
if (shouldBuildFtsTable) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.fsck.k9.Core
|
|||
import com.fsck.k9.CoreResourceProvider
|
||||
import com.fsck.k9.DI
|
||||
import com.fsck.k9.K9
|
||||
import com.fsck.k9.crypto.EncryptionExtractor
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import org.koin.dsl.module.applicationContext
|
||||
|
||||
|
@ -24,4 +25,5 @@ class TestApp : Application() {
|
|||
val testModule = applicationContext {
|
||||
bean { AppConfig(emptyList()) }
|
||||
bean { mock<CoreResourceProvider>() }
|
||||
bean { mock<EncryptionExtractor>() }
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ include ':app:k9mail'
|
|||
include ':app:ui'
|
||||
include ':app:core'
|
||||
include ':app:storage'
|
||||
include ':app:crypto-openpgp'
|
||||
include ':mail:common'
|
||||
include ':mail:testing'
|
||||
include ':mail:protocols:imap'
|
||||
|
|
Loading…
Reference in a new issue