diff --git a/k9mail/src/main/java/com/fsck/k9/activity/MessageList.java b/k9mail/src/main/java/com/fsck/k9/activity/MessageList.java index cdd4c0698..9e6cbeeec 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/MessageList.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/MessageList.java @@ -40,6 +40,7 @@ import com.fsck.k9.activity.setup.Prefs; import com.fsck.k9.crypto.PgpData; import com.fsck.k9.fragment.MessageListFragment; import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener; +import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations; import com.fsck.k9.ui.messageview.MessageViewFragment; import com.fsck.k9.ui.messageview.MessageViewFragment.MessageViewFragmentListener; import com.fsck.k9.mailstore.StorageManager; @@ -1400,18 +1401,18 @@ public class MessageList extends K9Activity implements MessageListFragmentListen } @Override - public void onReply(LocalMessage message, PgpData pgpData) { - MessageCompose.actionReply(this, message, false, pgpData.getDecryptedData()); + public void onReply(LocalMessage message, String quote) { + MessageCompose.actionReply(this, message, false, quote); } @Override - public void onReplyAll(LocalMessage message, PgpData pgpData) { - MessageCompose.actionReply(this, message, true, pgpData.getDecryptedData()); + public void onReplyAll(LocalMessage message, String quote) { + MessageCompose.actionReply(this, message, true, quote); } @Override - public void onForward(LocalMessage mMessage, PgpData mPgpData) { - MessageCompose.actionForward(this, mMessage, mPgpData.getDecryptedData()); + public void onForward(LocalMessage mMessage, String quote) { + MessageCompose.actionForward(this, mMessage, quote); } @Override diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/LocalMessageExtractor.java b/k9mail/src/main/java/com/fsck/k9/mailstore/LocalMessageExtractor.java index 1f2c0f108..f79fdd004 100644 --- a/k9mail/src/main/java/com/fsck/k9/mailstore/LocalMessageExtractor.java +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/LocalMessageExtractor.java @@ -475,7 +475,6 @@ public class LocalMessageExtractor { * not contain children of the former types. */ - ArrayList parts = new ArrayList(); if (!getCryptSubPieces(message, parts, annotations)) { parts.add(message); diff --git a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoHelper.java b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoHelper.java index 4448291a4..d976b8ee2 100644 --- a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoHelper.java +++ b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoHelper.java @@ -427,6 +427,10 @@ public class MessageCryptoHelper { return annotations.containsKey(part); } + public OpenPgpResultAnnotation getPrincipalResultForSender(String sender) { + return annotations.isEmpty() ? null : annotations.values().iterator().next(); + } + } } diff --git a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageView.java b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageView.java index 4b8c9ba64..ead2a2846 100644 --- a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageView.java +++ b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageView.java @@ -18,6 +18,7 @@ import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mailstore.MessageViewInfo; import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer; +import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations; import com.fsck.k9.view.MessageHeader; @@ -84,12 +85,17 @@ public class MessageView extends LinearLayout { return mHeaderContainer; } - public void setHeaders(final Message message, Account account) { + /** This method is called twice: Once before the message is loaded, + * showing all available information at the time and an indeterminate + * progress bar. Once loading of the message has finished, the + * information is updated by another call with the loading flag set + * to false. + */ + public void setHeaders(final Message message, Account account, MessageCryptoAnnotations annotations) { try { - mHeaderContainer.populate(message, account); + mHeaderContainer.populate(message, account, annotations == null, + annotations == null ? null : annotations.getPrincipalResultForSender(null)); mHeaderContainer.setVisibility(View.VISIBLE); - - } catch (Exception me) { Log.e(K9.LOG_TAG, "setHeaders - error", me); } diff --git a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java index 8cf60460c..6f9b0e14b 100644 --- a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java +++ b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java @@ -35,7 +35,6 @@ import com.fsck.k9.activity.ChooseFolder; import com.fsck.k9.activity.MessageReference; import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingListener; -import com.fsck.k9.crypto.PgpData; import com.fsck.k9.fragment.ConfirmationDialogFragment; import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener; import com.fsck.k9.fragment.ProgressDialogFragment; @@ -57,7 +56,6 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF private static final String ARG_REFERENCE = "reference"; private static final String STATE_MESSAGE_REFERENCE = "reference"; - private static final String STATE_PGP_DATA = "pgpData"; private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1; private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2; @@ -77,7 +75,6 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF } private MessageView mMessageView; - private PgpData mPgpData; private Account mAccount; private MessageReference mMessageReference; private LocalMessage mMessage; @@ -172,24 +169,22 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF MessageReference messageReference; if (savedInstanceState != null) { - mPgpData = (PgpData) savedInstanceState.get(STATE_PGP_DATA); messageReference = (MessageReference) savedInstanceState.get(STATE_MESSAGE_REFERENCE); } else { Bundle args = getArguments(); messageReference = args.getParcelable(ARG_REFERENCE); } - displayMessage(messageReference, (mPgpData == null)); + displayMessage(messageReference); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(STATE_MESSAGE_REFERENCE, mMessageReference); - outState.putSerializable(STATE_PGP_DATA, mPgpData); } - private void displayMessage(MessageReference ref, boolean resetPgpData) { + private void displayMessage(MessageReference ref) { mMessageReference = ref; if (K9.DEBUG) { Log.d(K9.LOG_TAG, "MessageView displaying message " + mMessageReference); @@ -199,11 +194,6 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF mAccount = Preferences.getPreferences(appContext).getAccount(mMessageReference.accountUuid); messageCryptoHelper = new MessageCryptoHelper(mContext, this, mAccount); - if (resetPgpData) { - // start with fresh, empty PGP data - mPgpData = new PgpData(); - } - // Clear previous message mMessageView.resetView(); mMessageView.resetHeaderView(); @@ -222,7 +212,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF } private void onLoadMessageFromDatabaseFinished(LocalMessage message) { - displayMessageHeader(message); + displayMessageHeader(message, null); if (message.isBodyMissing()) { startDownloadingMessageBody(message); @@ -262,6 +252,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF void startExtractingTextAndAttachments(MessageCryptoAnnotations annotations) { this.messageAnnotations = annotations; + displayMessageHeader(mMessage, messageAnnotations); getLoaderManager().initLoader(DECODE_MESSAGE_LOADER_ID, null, decodeMessageLoaderCallback); } @@ -279,8 +270,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF } } - private void displayMessageHeader(LocalMessage message) { - mMessageView.setHeaders(message, mAccount); + private void displayMessageHeader(LocalMessage message, MessageCryptoAnnotations annotations) { + mMessageView.setHeaders(message, mAccount, annotations); displayMessageSubject(getSubjectForMessage(message)); mFragmentListener.updateMenu(); } @@ -344,21 +335,22 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF mController.moveMessage(mAccount, srcFolder, messageToMove, dstFolder, null); } + // TODO useful citation public void onReply() { if (mMessage != null) { - mFragmentListener.onReply(mMessage, mPgpData); + mFragmentListener.onReply(mMessage, ""); } } public void onReplyAll() { if (mMessage != null) { - mFragmentListener.onReplyAll(mMessage, mPgpData); + mFragmentListener.onReplyAll(mMessage, ""); } } public void onForward() { if (mMessage != null) { - mFragmentListener.onForward(mMessage, mPgpData); + mFragmentListener.onForward(mMessage, ""); } } @@ -367,7 +359,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF boolean newState = !mMessage.isSet(Flag.FLAGGED); mController.setFlag(mAccount, mMessage.getFolder().getName(), Collections.singletonList(mMessage), Flag.FLAGGED, newState); - mMessageView.setHeaders(mMessage, mAccount); + mMessageView.setHeaders(mMessage, mAccount, messageAnnotations); } } @@ -479,7 +471,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF if (mMessage != null) { mController.setFlag(mAccount, mMessage.getFolder().getName(), Collections.singletonList(mMessage), Flag.SEEN, !mMessage.isSet(Flag.SEEN)); - mMessageView.setHeaders(mMessage, mAccount); + mMessageView.setHeaders(mMessage, mAccount, messageAnnotations); String subject = mMessage.getSubject(); displayMessageSubject(subject); mFragmentListener.updateMenu(); @@ -698,10 +690,10 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF } public interface MessageViewFragmentListener { - public void onForward(LocalMessage mMessage, PgpData mPgpData); + public void onForward(LocalMessage mMessage, String citation); public void disableDeleteAction(); - public void onReplyAll(LocalMessage mMessage, PgpData mPgpData); - public void onReply(LocalMessage mMessage, PgpData mPgpData); + public void onReplyAll(LocalMessage mMessage, String citation); + public void onReply(LocalMessage mMessage, String citation); public void displayMessageSubject(String title); public void setProgress(boolean b); public void showNextMessageOrReturn(); diff --git a/k9mail/src/main/java/com/fsck/k9/view/MessageHeader.java b/k9mail/src/main/java/com/fsck/k9/view/MessageHeader.java index a536676d7..d12c6d765 100644 --- a/k9mail/src/main/java/com/fsck/k9/view/MessageHeader.java +++ b/k9mail/src/main/java/com/fsck/k9/view/MessageHeader.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Set; import android.content.Context; +import android.graphics.PorterDuff; import android.graphics.Typeface; import android.os.Parcel; import android.os.Parcelable; @@ -20,7 +21,9 @@ import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.widget.CheckBox; +import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.ProgressBar; import android.widget.QuickContactBadge; import android.widget.TextView; import android.widget.Toast; @@ -38,6 +41,10 @@ import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.internet.MimeUtility; +import com.fsck.k9.mailstore.OpenPgpResultAnnotation; +import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations; +import org.openintents.openpgp.OpenPgpSignatureResult; + public class MessageHeader extends LinearLayout implements OnClickListener { private Context mContext; @@ -49,6 +56,9 @@ public class MessageHeader extends LinearLayout implements OnClickListener { private TextView mCcLabel; private TextView mSubjectView; + private ProgressBar mProgress; + private ImageView mPgpSignatureIcon; + private ImageView mPgpEncryptedIcon; private View mChip; private CheckBox mFlagged; private int defaultSubjectColor; @@ -89,6 +99,9 @@ public class MessageHeader extends LinearLayout implements OnClickListener { @Override protected void onFinishInflate() { + + mProgress = (ProgressBar) findViewById(R.id.progress); + mAnsweredIcon = findViewById(R.id.answered); mForwardedIcon = findViewById(R.id.forwarded); mFromView = (TextView) findViewById(R.id.from); @@ -97,6 +110,9 @@ public class MessageHeader extends LinearLayout implements OnClickListener { mCcView = (TextView) findViewById(R.id.cc); mCcLabel = (TextView) findViewById(R.id.cc_label); + mPgpSignatureIcon = (ImageView) findViewById(R.id.pgp_signature_icon); + mPgpEncryptedIcon= (ImageView) findViewById(R.id.pgp_encryption_icon); + mContactBadge = (QuickContactBadge) findViewById(R.id.contact_badge); mSubjectView = (TextView) findViewById(R.id.subject); @@ -213,7 +229,9 @@ public class MessageHeader extends LinearLayout implements OnClickListener { } - public void populate(final Message message, final Account account) throws MessagingException { + public void populate(final Message message, final Account account, + boolean loading, OpenPgpResultAnnotation pgpResult) + throws MessagingException { final Contacts contacts = K9.showContactName() ? mContacts : null; final CharSequence from = MessageHelper.toFriendly(message.getFrom(), contacts); final CharSequence to = MessageHelper.toFriendly(message.getRecipients(Message.RecipientType.TO), contacts); @@ -291,6 +309,29 @@ public class MessageHeader extends LinearLayout implements OnClickListener { mChip.setBackgroundColor(mAccount.getChipColor()); + // if this is null, it's still loading + if (loading) { + mProgress.setVisibility(View.VISIBLE); + mPgpSignatureIcon.setVisibility(View.GONE); + mPgpEncryptedIcon.setVisibility(View.GONE); + } else if (pgpResult == null) { + mProgress.setVisibility(View.GONE); + mPgpSignatureIcon.setVisibility(View.GONE); + mPgpEncryptedIcon.setVisibility(View.GONE); + + mPgpSignatureIcon.setImageResource(R.drawable.status_signature_unverified_cutout); + int color = R.color.openpgp_sidebar; + mPgpSignatureIcon.setColorFilter(mContext.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + + } else { + mProgress.setVisibility(View.GONE); + mPgpSignatureIcon.setVisibility(View.VISIBLE); + mPgpEncryptedIcon.setVisibility(View.VISIBLE); + + setPgpStatus(pgpResult); + } + setVisibility(View.VISIBLE); if (mSavedState != null) { @@ -303,6 +344,173 @@ public class MessageHeader extends LinearLayout implements OnClickListener { } } + private void setPgpStatus(OpenPgpResultAnnotation pgpResult) { + + OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult(); + + if (signatureResult == null) { + setStatusImage(mContext, mPgpSignatureIcon, STATE_NOT_SIGNED); + } else { + switch (signatureResult.getStatus()) { + case OpenPgpSignatureResult.SIGNATURE_ERROR: { + setStatusImage(mContext, mPgpSignatureIcon, STATE_INVALID); + + break; + } + case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: { + setStatusImage(mContext, mPgpSignatureIcon, STATE_VERIFIED); + + break; + } + case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: { + setStatusImage(mContext, mPgpSignatureIcon, STATE_UNKNOWN_KEY); + + break; + } + case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: { + setStatusImage(mContext, mPgpSignatureIcon, STATE_UNVERIFIED); + + break; + } + case OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED: { + setStatusImage(mContext, mPgpSignatureIcon, STATE_EXPIRED); + + break; + } + case OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED: { + setStatusImage(mContext, mPgpSignatureIcon, STATE_REVOKED); + + break; + } + } + + + } + } + + public static final int STATE_REVOKED = 1; + public static final int STATE_EXPIRED = 2; + public static final int STATE_VERIFIED = 3; + public static final int STATE_UNAVAILABLE = 4; + public static final int STATE_ENCRYPTED = 5; + public static final int STATE_NOT_ENCRYPTED = 6; + public static final int STATE_UNVERIFIED = 7; + public static final int STATE_UNKNOWN_KEY = 8; + public static final int STATE_INVALID = 9; + public static final int STATE_NOT_SIGNED = 10; + + public static void setStatusImage(Context context, ImageView statusIcon, int state) { + setStatusImage(context, statusIcon, null, state); + } + + public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText, + int state) { + switch (state) { + /** GREEN: everything is good **/ + case STATE_VERIFIED: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_verified_cutout)); + int color = R.color.openpgp_green; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + case STATE_ENCRYPTED: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_lock_closed)); + int color = R.color.openpgp_green; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + /** ORANGE: mostly bad... **/ + case STATE_UNVERIFIED: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout)); + int color = R.color.openpgp_orange; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + case STATE_UNKNOWN_KEY: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout)); + int color = R.color.openpgp_orange; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + /** RED: really bad... **/ + case STATE_REVOKED: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout)); + int color = R.color.openpgp_red; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + case STATE_EXPIRED: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_expired_cutout)); + int color = R.color.openpgp_red; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + case STATE_NOT_ENCRYPTED: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_lock_open)); + int color = R.color.openpgp_red; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + case STATE_NOT_SIGNED: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout)); + int color = R.color.openpgp_red; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + case STATE_INVALID: { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout)); + int color = R.color.openpgp_red; + statusIcon.setColorFilter(context.getResources().getColor(color), + PorterDuff.Mode.SRC_IN); + if (statusText != null) { + statusText.setTextColor(context.getResources().getColor(color)); + } + break; + } + } + } + public void onShowAdditionalHeaders() { int currentVisibility = mAdditionalHeadersView.getVisibility(); if (currentVisibility == View.VISIBLE) { diff --git a/k9mail/src/main/res/layout/message_view_header.xml b/k9mail/src/main/res/layout/message_view_header.xml index b7d07384a..47bcf1b24 100644 --- a/k9mail/src/main/res/layout/message_view_header.xml +++ b/k9mail/src/main/res/layout/message_view_header.xml @@ -39,47 +39,12 @@ android:layout_height="wrap_content" android:orientation="horizontal" > - - - - - - - - - - - - - - - + + + + + + android:textColor="?android:attr/textColorSecondary" + android:text="Jan 1st 2015" /> + + + + + + + + + + + +