Merge pull request #3497 from k9mail/send_functionality_in_backend

Add 'send message' functionality to Backend interface
This commit is contained in:
cketti 2018-07-13 13:59:40 +02:00 committed by GitHub
commit 5fe780a828
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 119 additions and 95 deletions

View file

@ -2,7 +2,6 @@ package com.fsck.k9
import android.content.Context
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.mail.TransportProvider
import com.fsck.k9.mail.power.PowerManager
import com.fsck.k9.mailstore.StorageManager
import com.fsck.k9.power.TracingPowerManager
@ -11,7 +10,6 @@ import org.koin.dsl.module.applicationContext
val mainModule = applicationContext {
bean { Preferences.getPreferences(get()) }
bean { MessagingController.getInstance(get()) }
bean { TransportProvider() }
bean { get<Context>().resources }
bean { StorageManager.getInstance(get()) }
bean { TracingPowerManager.getPowerManager(get()) as PowerManager }

View file

@ -10,6 +10,7 @@ import com.fsck.k9.mail.oauth.OAuth2TokenProvider
import com.fsck.k9.mail.power.PowerManager
import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory
import com.fsck.k9.mail.store.imap.ImapStore
import com.fsck.k9.mail.transport.smtp.SmtpTransport
import com.fsck.k9.mailstore.K9BackendStorage
class ImapBackendFactory(
@ -22,7 +23,8 @@ class ImapBackendFactory(
val accountName = account.description
val backendStorage = K9BackendStorage(preferences, account, account.localStore)
val imapStore = createImapStore(account)
return ImapBackend(accountName, backendStorage, imapStore, powerManager)
val smtpTransport = createSmtpTransport(account)
return ImapBackend(accountName, backendStorage, imapStore, powerManager, smtpTransport)
}
private fun createImapStore(account: Account): ImapStore {
@ -34,4 +36,9 @@ class ImapBackendFactory(
oAuth2TokenProvider
)
}
private fun createSmtpTransport(account: Account): SmtpTransport {
val oauth2TokenProvider: OAuth2TokenProvider? = null
return SmtpTransport(account, DefaultTrustedSocketFactory(context), oauth2TokenProvider)
}
}

View file

@ -5,8 +5,10 @@ import com.fsck.k9.Account
import com.fsck.k9.Preferences
import com.fsck.k9.backend.api.Backend
import com.fsck.k9.backend.pop3.Pop3Backend
import com.fsck.k9.mail.oauth.OAuth2TokenProvider
import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory
import com.fsck.k9.mail.store.pop3.Pop3Store
import com.fsck.k9.mail.transport.smtp.SmtpTransport
import com.fsck.k9.mailstore.K9BackendStorage
class Pop3BackendFactory(private val context: Context, private val preferences: Preferences) : BackendFactory {
@ -15,10 +17,16 @@ class Pop3BackendFactory(private val context: Context, private val preferences:
val accountName = account.description
val backendStorage = K9BackendStorage(preferences, account, account.localStore)
val pop3Store = createPop3Store(account)
return Pop3Backend(accountName, backendStorage, pop3Store)
val smtpTransport = createSmtpTransport(account)
return Pop3Backend(accountName, backendStorage, pop3Store, smtpTransport)
}
private fun createPop3Store(account: Account): Pop3Store {
return Pop3Store(account, DefaultTrustedSocketFactory(context))
}
private fun createSmtpTransport(account: Account): SmtpTransport {
val oauth2TokenProvider: OAuth2TokenProvider? = null
return SmtpTransport(account, DefaultTrustedSocketFactory(context), oauth2TokenProvider)
}
}

View file

@ -5,6 +5,7 @@ import com.fsck.k9.Preferences
import com.fsck.k9.backend.api.Backend
import com.fsck.k9.backend.webdav.WebDavBackend
import com.fsck.k9.mail.store.webdav.WebDavStore
import com.fsck.k9.mail.transport.WebDavTransport
import com.fsck.k9.mailstore.K9BackendStorage
class WebDavBackendFactory(private val preferences: Preferences) : BackendFactory {
@ -13,7 +14,8 @@ class WebDavBackendFactory(private val preferences: Preferences) : BackendFactor
val accountName = account.description
val backendStorage = K9BackendStorage(preferences, account, account.localStore)
val webDavStore = createWebDavStore(account)
return WebDavBackend(accountName, backendStorage, webDavStore)
val webDavTransport = WebDavTransport(account)
return WebDavBackend(accountName, backendStorage, webDavStore, webDavTransport)
}
private fun createWebDavStore(account: Account): WebDavStore {

View file

@ -71,8 +71,6 @@ import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.PushReceiver;
import com.fsck.k9.mail.Pusher;
import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.TransportProvider;
import com.fsck.k9.mail.internet.MessageExtractor;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mailstore.LocalFolder;
@ -128,7 +126,6 @@ public class MessagingController {
private final ConcurrentHashMap<Account, Pusher> pushers = new ConcurrentHashMap<>();
private final ExecutorService threadPool = Executors.newCachedThreadPool();
private final MemorizingMessagingListener memorizingMessagingListener = new MemorizingMessagingListener();
private final TransportProvider transportProvider;
private final AccountStatsCollector accountStatsCollector;
private final CoreResourceProvider resourceProvider;
@ -142,10 +139,9 @@ public class MessagingController {
Context appContext = context.getApplicationContext();
NotificationController notificationController = DI.get(NotificationController.class);
Contacts contacts = Contacts.getInstance(context);
TransportProvider transportProvider = TransportProvider.getInstance();
AccountStatsCollector accountStatsCollector = new DefaultAccountStatsCollector(context);
CoreResourceProvider resourceProvider = DI.get(CoreResourceProvider.class);
inst = new MessagingController(appContext, notificationController, contacts, transportProvider,
inst = new MessagingController(appContext, notificationController, contacts,
accountStatsCollector, resourceProvider);
}
return inst;
@ -154,12 +150,10 @@ public class MessagingController {
@VisibleForTesting
MessagingController(Context context, NotificationController notificationController, Contacts contacts,
TransportProvider transportProvider, AccountStatsCollector accountStatsCollector,
CoreResourceProvider resourceProvider) {
AccountStatsCollector accountStatsCollector, CoreResourceProvider resourceProvider) {
this.context = context;
this.notificationController = notificationController;
this.contacts = contacts;
this.transportProvider = transportProvider;
this.accountStatsCollector = accountStatsCollector;
this.resourceProvider = resourceProvider;
@ -1497,6 +1491,10 @@ public class MessagingController {
}
}
public void sendMessageBlocking(Account account, Message message) throws MessagingException {
Backend backend = getBackend(account);
backend.sendMessage(message);
}
public void sendPendingMessages(MessagingListener listener) {
final Preferences prefs = Preferences.getPreferences(context);
@ -1603,7 +1601,7 @@ public class MessagingController {
Timber.i("Scanning folder '%s' (%d) for messages to send",
account.getOutboxFolder(), localFolder.getDatabaseId());
Transport transport = transportProvider.getTransport(context, account);
Backend backend = getBackend(account);
for (LocalMessage message : localMessages) {
if (message.isSet(Flag.DELETED)) {
@ -1638,7 +1636,7 @@ public class MessagingController {
message.setFlag(Flag.X_SEND_IN_PROGRESS, true);
Timber.i("Sending message with UID %s", message.getUid());
transport.sendMessage(message);
backend.sendMessage(message);
message.setFlag(Flag.X_SEND_IN_PROGRESS, false);
message.setFlag(Flag.SEEN, true);
@ -1851,8 +1849,12 @@ public class MessagingController {
return getBackend(account).getSupportsSearchByDate();
}
public void checkServerSettings(Account account) throws MessagingException {
getBackend(account).checkServerSettings();
public void checkIncomingServerSettings(Account account) throws MessagingException {
getBackend(account).checkIncomingServerSettings();
}
public void checkOutgoingServerSettings(Account account) throws MessagingException {
getBackend(account).checkOutgoingServerSettings();
}
public void moveMessages(final Account srcAccount, final String srcFolder,

View file

@ -1,31 +0,0 @@
package com.fsck.k9.mail;
import android.content.Context;
import com.fsck.k9.mail.oauth.OAuth2TokenProvider;
import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory;
import com.fsck.k9.mail.store.StoreConfig;
import com.fsck.k9.mail.transport.smtp.SmtpTransport;
import com.fsck.k9.mail.transport.WebDavTransport;
public class TransportProvider {
private static TransportProvider transportProvider = new TransportProvider();
public static TransportProvider getInstance() {
return transportProvider;
}
public synchronized Transport getTransport(Context context, StoreConfig storeConfig)
throws MessagingException {
String uri = storeConfig.getTransportUri();
if (uri.startsWith("smtp")) {
OAuth2TokenProvider oauth2TokenProvider = null;
return new SmtpTransport(storeConfig, new DefaultTrustedSocketFactory(context), oauth2TokenProvider);
} else if (uri.startsWith("webdav")) {
return new WebDavTransport(storeConfig);
} else {
throw new MessagingException("Unable to locate an applicable Transport for " + uri);
}
}
}

View file

@ -26,8 +26,6 @@ import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.TransportProvider;
import com.fsck.k9.mailstore.LocalFolder;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalStore;
@ -97,10 +95,6 @@ public class MessagingControllerTest extends K9RobolectricTest {
private LocalStore localStore;
@Mock
private NotificationController notificationController;
@Mock
private TransportProvider transportProvider;
@Mock
private Transport transport;
@Captor
private ArgumentCaptor<List<LocalFolder>> localFolderListCaptor;
@Captor
@ -144,7 +138,7 @@ public class MessagingControllerTest extends K9RobolectricTest {
MessagingControllerTestExtra.backendManagerProvides(backend);
controller = new MessagingController(appContext, notificationController, contacts, transportProvider,
controller = new MessagingController(appContext, notificationController, contacts,
accountStatsCollector, mock(CoreResourceProvider.class));
configureAccount();
@ -537,7 +531,7 @@ public class MessagingControllerTest extends K9RobolectricTest {
controller.sendPendingMessagesSynchronous(account);
verify(transport).sendMessage(localMessageToSend1);
verify(backend).sendMessage(localMessageToSend1);
}
@Test
@ -546,9 +540,9 @@ public class MessagingControllerTest extends K9RobolectricTest {
controller.sendPendingMessagesSynchronous(account);
InOrder ordering = inOrder(localMessageToSend1, transport);
InOrder ordering = inOrder(localMessageToSend1, backend);
ordering.verify(localMessageToSend1).setFlag(Flag.X_SEND_IN_PROGRESS, true);
ordering.verify(transport).sendMessage(localMessageToSend1);
ordering.verify(backend).sendMessage(localMessageToSend1);
ordering.verify(localMessageToSend1).setFlag(Flag.X_SEND_IN_PROGRESS, false);
}
@ -582,7 +576,7 @@ public class MessagingControllerTest extends K9RobolectricTest {
@Test
public void sendPendingMessagesSynchronous_withAuthenticationFailure_shouldNotify() throws MessagingException {
setupAccountWithMessageToSend();
doThrow(new AuthenticationFailedException("Test")).when(transport).sendMessage(localMessageToSend1);
doThrow(new AuthenticationFailedException("Test")).when(backend).sendMessage(localMessageToSend1);
controller.sendPendingMessagesSynchronous(account);
@ -592,7 +586,7 @@ public class MessagingControllerTest extends K9RobolectricTest {
@Test
public void sendPendingMessagesSynchronous_withCertificateFailure_shouldNotify() throws MessagingException {
setupAccountWithMessageToSend();
doThrow(new CertificateValidationException("Test")).when(transport).sendMessage(localMessageToSend1);
doThrow(new CertificateValidationException("Test")).when(backend).sendMessage(localMessageToSend1);
controller.sendPendingMessagesSynchronous(account);
@ -615,7 +609,6 @@ public class MessagingControllerTest extends K9RobolectricTest {
when(localStore.getFolder(SENT_FOLDER_NAME)).thenReturn(sentFolder);
when(sentFolder.getDatabaseId()).thenReturn(1L);
when(localFolder.exists()).thenReturn(true);
when(transportProvider.getTransport(appContext, account)).thenReturn(transport);
when(localFolder.getMessages(null)).thenReturn(Collections.singletonList(localMessageToSend1));
when(localMessageToSend1.getUid()).thenReturn("localMessageToSend1");
when(localMessageToSend1.getHeader(K9.IDENTITY_HEADER)).thenReturn(new String[]{});

View file

@ -13,7 +13,6 @@ import java.util.Locale;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
@ -41,8 +40,6 @@ import com.fsck.k9.mail.Folder.FolderClass;
import com.fsck.k9.mail.Folder.FolderType;
import com.fsck.k9.mail.MailServerDirection;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.TransportProvider;
import com.fsck.k9.mail.filter.Hex;
import com.fsck.k9.mailstore.LocalFolder;
import com.fsck.k9.mailstore.LocalStore;
@ -490,14 +487,8 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
if (!isWebDavAccount()) {
publishProgress(R.string.account_setup_check_settings_check_outgoing_msg);
}
Context context = DI.get(Context.class);
Transport transport = TransportProvider.getInstance().getTransport(context, account);
transport.close();
try {
transport.open();
} finally {
transport.close();
}
messagingController.checkOutgoingServerSettings(account);
}
private void checkIncoming() throws MessagingException {
@ -507,7 +498,7 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
publishProgress(R.string.account_setup_check_settings_check_incoming_msg);
}
messagingController.checkServerSettings(account);
messagingController.checkIncomingServerSettings(account);
if (isWebDavAccount()) {
publishProgress(R.string.account_setup_check_settings_fetch);

View file

@ -4,12 +4,9 @@ package com.fsck.k9.ui.endtoend
import android.app.PendingIntent
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.Observer
import android.content.Context
import com.fsck.k9.Account
import com.fsck.k9.Preferences
import com.fsck.k9.mail.TransportProvider
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
import org.openintents.openpgp.OpenPgpApiManager
import org.openintents.openpgp.OpenPgpApiManager.OpenPgpApiManagerCallback
@ -19,9 +16,7 @@ import timber.log.Timber
class AutocryptKeyTransferPresenter internal constructor(
lifecycleOwner: LifecycleOwner,
private val context: Context,
private val openPgpApiManager: OpenPgpApiManager,
private val transportProvider: TransportProvider,
private val preferences: Preferences,
private val viewModel: AutocryptKeyTransferViewModel,
private val view: AutocryptKeyTransferActivity
@ -83,8 +78,7 @@ class AutocryptKeyTransferPresenter internal constructor(
view.setLoadingStateSending()
view.sceneGeneratingAndSending()
val transport = transportProvider.getTransport(context, account)
viewModel.autocryptSetupTransferLiveEvent.sendMessageAsync(transport, setupMsg)
viewModel.autocryptSetupTransferLiveEvent.sendMessageAsync(account, setupMsg)
}
private fun onLoadedAutocryptSetupTransfer(result: AutocryptSetupTransferResult?) {

View file

@ -1,18 +1,22 @@
package com.fsck.k9.ui.endtoend
import android.app.PendingIntent
import com.fsck.k9.Account
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.helper.SingleLiveEvent
import com.fsck.k9.mail.Transport
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
import org.jetbrains.anko.coroutines.experimental.bg
class AutocryptSetupTransferLiveEvent : SingleLiveEvent<AutocryptSetupTransferResult>() {
fun sendMessageAsync(transport: Transport, setupMsg: AutocryptSetupMessage) {
class AutocryptSetupTransferLiveEvent(
private val messagingController: MessagingController
) : SingleLiveEvent<AutocryptSetupTransferResult>() {
fun sendMessageAsync(account: Account, setupMsg: AutocryptSetupMessage) {
launch(UI) {
val setupMessage = bg {
transport.sendMessage(setupMsg.setupMessage)
messagingController.sendMessageBlocking(account, setupMsg.setupMessage)
}
delay(2000)

View file

@ -5,16 +5,14 @@ import org.koin.dsl.module.applicationContext
val endToEndUiModule = applicationContext {
factory { AutocryptSetupMessageLiveEvent(get()) }
factory { AutocryptSetupTransferLiveEvent() }
factory { AutocryptSetupTransferLiveEvent(get()) }
factory { params ->
AutocryptKeyTransferPresenter(
params["lifecycleOwner"],
get(),
get(parameters = { params.values }),
get(),
get(),
get(),
params["autocryptTransferView"])
}
viewModel { AutocryptKeyTransferViewModel(get(), get()) }
}
}

View file

@ -82,5 +82,11 @@ interface Backend {
fun createPusher(receiver: PushReceiver): Pusher
@Throws(MessagingException::class)
fun checkServerSettings()
fun checkIncomingServerSettings()
@Throws(MessagingException::class)
fun sendMessage(message: Message)
@Throws(MessagingException::class)
fun checkOutgoingServerSettings()
}

View file

@ -13,6 +13,7 @@ dependencies {
api project(":backend:api")
implementation project(":mail:protocols:imap")
implementation project(":mail:protocols:smtp")
implementation "com.jakewharton.timber:timber:${versions.timber}"

View file

@ -22,6 +22,7 @@ import com.fsck.k9.mail.Pusher;
import com.fsck.k9.mail.power.PowerManager;
import com.fsck.k9.mail.store.imap.ImapPusher;
import com.fsck.k9.mail.store.imap.ImapStore;
import com.fsck.k9.mail.transport.smtp.SmtpTransport;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -29,6 +30,7 @@ import org.jetbrains.annotations.Nullable;
public class ImapBackend implements Backend {
private final ImapStore imapStore;
private final PowerManager powerManager;
private final SmtpTransport smtpTransport;
private final ImapSync imapSync;
private final CommandGetFolders commandGetFolders;
private final CommandSetFlag commandSetFlag;
@ -43,9 +45,10 @@ public class ImapBackend implements Backend {
public ImapBackend(String accountName, BackendStorage backendStorage, ImapStore imapStore,
PowerManager powerManager) {
PowerManager powerManager, SmtpTransport smtpTransport) {
this.imapStore = imapStore;
this.powerManager = powerManager;
this.smtpTransport = smtpTransport;
imapSync = new ImapSync(accountName, backendStorage, imapStore);
commandSetFlag = new CommandSetFlag(imapStore);
@ -194,7 +197,17 @@ public class ImapBackend implements Backend {
}
@Override
public void checkServerSettings() throws MessagingException {
public void checkIncomingServerSettings() throws MessagingException {
imapStore.checkSettings();
}
@Override
public void sendMessage(@NotNull Message message) throws MessagingException {
smtpTransport.sendMessage(message);
}
@Override
public void checkOutgoingServerSettings() throws MessagingException {
smtpTransport.checkSettings();
}
}

View file

@ -13,6 +13,7 @@ dependencies {
api project(":backend:api")
implementation project(":mail:protocols:pop3")
implementation project(":mail:protocols:smtp")
implementation "com.jakewharton.timber:timber:${versions.timber}"

View file

@ -14,8 +14,14 @@ import com.fsck.k9.mail.Part
import com.fsck.k9.mail.PushReceiver
import com.fsck.k9.mail.Pusher
import com.fsck.k9.mail.store.pop3.Pop3Store
import com.fsck.k9.mail.transport.smtp.SmtpTransport
class Pop3Backend(accountName: String, backendStorage: BackendStorage, private val pop3Store: Pop3Store) : Backend {
class Pop3Backend(
accountName: String,
backendStorage: BackendStorage,
private val pop3Store: Pop3Store,
private val smtpTransport: SmtpTransport
) : Backend {
private val pop3Sync: Pop3Sync = Pop3Sync(accountName, backendStorage, pop3Store)
private val commandGetFolders = CommandGetFolders()
private val commandSetFlag = CommandSetFlag(pop3Store)
@ -107,7 +113,15 @@ class Pop3Backend(accountName: String, backendStorage: BackendStorage, private v
throw UnsupportedOperationException("not supported")
}
override fun checkServerSettings() {
override fun checkIncomingServerSettings() {
pop3Store.checkSettings()
}
override fun sendMessage(message: Message) {
smtpTransport.sendMessage(message)
}
override fun checkOutgoingServerSettings() {
smtpTransport.checkSettings()
}
}

View file

@ -15,11 +15,13 @@ import com.fsck.k9.mail.Part
import com.fsck.k9.mail.PushReceiver
import com.fsck.k9.mail.Pusher
import com.fsck.k9.mail.store.webdav.WebDavStore
import com.fsck.k9.mail.transport.WebDavTransport
class WebDavBackend(
accountName: String,
backendStorage: BackendStorage,
private val webDavStore: WebDavStore
private val webDavStore: WebDavStore,
private val webDavTransport: WebDavTransport
) : Backend {
private val webDavSync: WebDavSync = WebDavSync(accountName, backendStorage, webDavStore)
private val commandGetFolders = CommandGetFolders(webDavStore)
@ -116,7 +118,15 @@ class WebDavBackend(
throw UnsupportedOperationException("not supported")
}
override fun checkServerSettings() {
override fun checkIncomingServerSettings() {
webDavStore.checkSettings()
}
override fun sendMessage(message: Message) {
webDavTransport.sendMessage(message)
}
override fun checkOutgoingServerSettings() {
webDavTransport.checkSettings()
}
}

View file

@ -843,4 +843,13 @@ public class SmtpTransport extends Transport {
protected String getHostAddress(InetAddress localAddress) {
return localAddress.getHostAddress();
}
public void checkSettings() throws MessagingException {
close();
try {
open();
} finally {
close();
}
}
}

View file

@ -38,4 +38,8 @@ public class WebDavTransport extends Transport {
public void sendMessage(Message message) throws MessagingException {
store.sendMessages(Collections.singletonList(message));
}
public void checkSettings() throws MessagingException {
store.checkSettings();
}
}