package com.fsck.k9.ui.messageview; import android.app.Activity; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import com.fsck.k9.Account; import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.mailstore.CryptoResultAnnotation; import com.fsck.k9.mailstore.MessageViewInfo; import com.fsck.k9.view.MessageCryptoDisplayStatus; import timber.log.Timber; public class MessageCryptoPresenter implements OnCryptoClickListener { public static final int REQUEST_CODE_UNKNOWN_KEY = 123; public static final int REQUEST_CODE_SECURITY_WARNING = 124; // injected state private final MessageCryptoMvpView messageCryptoMvpView; // persistent state private boolean overrideCryptoWarning; // transient state private CryptoResultAnnotation cryptoResultAnnotation; private boolean reloadOnResumeWithoutRecreateFlag; public MessageCryptoPresenter(Bundle savedInstanceState, MessageCryptoMvpView messageCryptoMvpView) { this.messageCryptoMvpView = messageCryptoMvpView; if (savedInstanceState != null) { overrideCryptoWarning = savedInstanceState.getBoolean("overrideCryptoWarning"); } } public void onSaveInstanceState(Bundle outState) { outState.putBoolean("overrideCryptoWarning", overrideCryptoWarning); } public void onResume() { if (reloadOnResumeWithoutRecreateFlag) { reloadOnResumeWithoutRecreateFlag = false; messageCryptoMvpView.restartMessageCryptoProcessing(); } } public boolean maybeHandleShowMessage(MessageTopView messageView, Account account, MessageViewInfo messageViewInfo) { this.cryptoResultAnnotation = messageViewInfo.cryptoResultAnnotation; MessageCryptoDisplayStatus displayStatus = MessageCryptoDisplayStatus.fromResultAnnotation(messageViewInfo.cryptoResultAnnotation); if (displayStatus == MessageCryptoDisplayStatus.DISABLED) { return false; } boolean suppressSignOnlyMessages = !K9.getOpenPgpSupportSignOnly(); if (suppressSignOnlyMessages && displayStatus.isUnencryptedSigned()) { return false; } if (cryptoResultAnnotation.isOverrideSecurityWarning()) { overrideCryptoWarning = true; } messageView.getMessageHeaderView().setCryptoStatus(displayStatus); switch (displayStatus) { case UNENCRYPTED_SIGN_REVOKED: case ENCRYPTED_SIGN_REVOKED: { showMessageCryptoWarning(messageView, account, messageViewInfo, R.string.messageview_crypto_warning_revoked); break; } case UNENCRYPTED_SIGN_EXPIRED: case ENCRYPTED_SIGN_EXPIRED: { showMessageCryptoWarning(messageView, account, messageViewInfo, R.string.messageview_crypto_warning_expired); break; } case UNENCRYPTED_SIGN_INSECURE: case ENCRYPTED_SIGN_INSECURE: { showMessageCryptoWarning(messageView, account, messageViewInfo, R.string.messageview_crypto_warning_insecure); break; } case UNENCRYPTED_SIGN_ERROR: case ENCRYPTED_SIGN_ERROR: { showMessageCryptoWarning(messageView, account, messageViewInfo, R.string.messageview_crypto_warning_error); break; } case ENCRYPTED_UNSIGNED: { showMessageCryptoWarning(messageView, account, messageViewInfo, R.string.messageview_crypto_warning_unsigned); break; } case CANCELLED: { Drawable providerIcon = getOpenPgpApiProviderIcon(messageView.getContext()); messageView.showMessageCryptoCancelledView(messageViewInfo, providerIcon); break; } case INCOMPLETE_ENCRYPTED: { Drawable providerIcon = getOpenPgpApiProviderIcon(messageView.getContext()); messageView.showMessageEncryptedButIncomplete(messageViewInfo, providerIcon); break; } case ENCRYPTED_ERROR: case ENCRYPTED_INSECURE: case UNSUPPORTED_ENCRYPTED: { Drawable providerIcon = getOpenPgpApiProviderIcon(messageView.getContext()); if (messageViewInfo.cryptoResultAnnotation.hasReplacementData()) { showMessageCryptoWarning(messageView, account, messageViewInfo, R.string.messageview_crypto_warning_insecure); } else { messageView.showMessageCryptoErrorView(messageViewInfo, providerIcon); } break; } case ENCRYPTED_NO_PROVIDER: { messageView.showCryptoProviderNotConfigured(messageViewInfo); break; } case INCOMPLETE_SIGNED: case UNSUPPORTED_SIGNED: default: { messageView.showMessage(account, messageViewInfo); break; } case LOADING: { throw new IllegalStateException("Displaying message while in loading state!"); } } return true; } private void showMessageCryptoWarning(MessageTopView messageView, Account account, MessageViewInfo messageViewInfo, @StringRes int warningStringRes) { if (overrideCryptoWarning) { messageView.showMessage(account, messageViewInfo); return; } Drawable providerIcon = getOpenPgpApiProviderIcon(messageView.getContext()); boolean showDetailButton = cryptoResultAnnotation.hasOpenPgpInsecureWarningPendingIntent(); messageView.showMessageCryptoWarning(messageViewInfo, providerIcon, warningStringRes, showDetailButton); } @Override public void onCryptoClick() { if (cryptoResultAnnotation == null) { return; } MessageCryptoDisplayStatus displayStatus = MessageCryptoDisplayStatus.fromResultAnnotation(cryptoResultAnnotation); switch (displayStatus) { case LOADING: // no need to do anything, there is a progress bar... break; case UNENCRYPTED_SIGN_UNKNOWN: launchPendingIntent(cryptoResultAnnotation); break; default: displayCryptoInfoDialog(displayStatus); break; } } @SuppressWarnings("UnusedParameters") // for consistency with Activity.onActivityResult public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_UNKNOWN_KEY) { if (resultCode != Activity.RESULT_OK) { return; } messageCryptoMvpView.restartMessageCryptoProcessing(); } else if (requestCode == REQUEST_CODE_SECURITY_WARNING) { if (overrideCryptoWarning || resultCode != Activity.RESULT_OK) { return; } overrideCryptoWarning = true; messageCryptoMvpView.redisplayMessage(); } else { throw new IllegalStateException("got an activity result that wasn't meant for us. this is a bug!"); } } private void displayCryptoInfoDialog(MessageCryptoDisplayStatus displayStatus) { messageCryptoMvpView.showCryptoInfoDialog( displayStatus, cryptoResultAnnotation.hasOpenPgpInsecureWarningPendingIntent()); } private void launchPendingIntent(CryptoResultAnnotation cryptoResultAnnotation) { try { PendingIntent pendingIntent = cryptoResultAnnotation.getOpenPgpPendingIntent(); if (pendingIntent != null) { messageCryptoMvpView.startPendingIntentForCryptoPresenter( pendingIntent.getIntentSender(), REQUEST_CODE_UNKNOWN_KEY, null, 0, 0, 0); } } catch (IntentSender.SendIntentException e) { Timber.e(e, "SendIntentException"); } } public void onClickShowCryptoKey() { try { PendingIntent pendingIntent = cryptoResultAnnotation.getOpenPgpSigningKeyIntentIfAny(); if (pendingIntent != null) { messageCryptoMvpView.startPendingIntentForCryptoPresenter( pendingIntent.getIntentSender(), null, null, 0, 0, 0); } } catch (IntentSender.SendIntentException e) { Timber.e(e, "SendIntentException"); } } public void onClickRetryCryptoOperation() { messageCryptoMvpView.restartMessageCryptoProcessing(); } public void onClickShowMessageOverrideWarning() { overrideCryptoWarning = true; messageCryptoMvpView.redisplayMessage(); } public void onClickShowCryptoWarningDetails() { try { PendingIntent pendingIntent = cryptoResultAnnotation.getOpenPgpInsecureWarningPendingIntent(); if (pendingIntent != null) { messageCryptoMvpView.startPendingIntentForCryptoPresenter( pendingIntent.getIntentSender(), REQUEST_CODE_SECURITY_WARNING, null, 0, 0, 0); } } catch (IntentSender.SendIntentException e) { Timber.e(e, "SendIntentException"); } } public Parcelable getDecryptionResultForReply() { if (cryptoResultAnnotation != null && cryptoResultAnnotation.isOpenPgpResult()) { return cryptoResultAnnotation.getOpenPgpDecryptionResult(); } return null; } @Nullable private static Drawable getOpenPgpApiProviderIcon(Context context) { try { String openPgpProvider = K9.getOpenPgpProvider(); if (K9.NO_OPENPGP_PROVIDER.equals(openPgpProvider)) { return null; } return context.getPackageManager().getApplicationIcon(openPgpProvider); } catch (NameNotFoundException e) { return null; } } public void onClickConfigureProvider() { reloadOnResumeWithoutRecreateFlag = true; messageCryptoMvpView.showCryptoConfigDialog(); } public interface MessageCryptoMvpView { void redisplayMessage(); void restartMessageCryptoProcessing(); void startPendingIntentForCryptoPresenter(IntentSender si, Integer requestCode, Intent fillIntent, int flagsMask, int flagValues, int extraFlags) throws IntentSender.SendIntentException; void showCryptoInfoDialog(MessageCryptoDisplayStatus displayStatus, boolean hasSecurityWarning); void showCryptoConfigDialog(); } }