Merge pull request #1390
Fix reply to all, and some refactorings for initFromReplyTo
This commit is contained in:
commit
1eb0ef4a6b
12 changed files with 418 additions and 201 deletions
|
@ -90,7 +90,7 @@ public abstract class Message implements Part, CompositeBody {
|
|||
|
||||
public abstract void setSentDate(Date sentDate, boolean hideTimeZone) throws MessagingException;
|
||||
|
||||
public abstract Address[] getRecipients(RecipientType type) throws MessagingException;
|
||||
public abstract Address[] getRecipients(RecipientType type);
|
||||
|
||||
public abstract void setRecipients(RecipientType type, Address[] addresses)
|
||||
throws MessagingException;
|
||||
|
|
|
@ -197,25 +197,29 @@ public class MimeMessage extends Message {
|
|||
* found the method returns an empty array.
|
||||
*/
|
||||
@Override
|
||||
public Address[] getRecipients(RecipientType type) throws MessagingException {
|
||||
if (type == RecipientType.TO) {
|
||||
if (mTo == null) {
|
||||
mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To")));
|
||||
public Address[] getRecipients(RecipientType type) {
|
||||
switch (type) {
|
||||
case TO: {
|
||||
if (mTo == null) {
|
||||
mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To")));
|
||||
}
|
||||
return mTo;
|
||||
}
|
||||
return mTo;
|
||||
} else if (type == RecipientType.CC) {
|
||||
if (mCc == null) {
|
||||
mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC")));
|
||||
case CC: {
|
||||
if (mCc == null) {
|
||||
mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC")));
|
||||
}
|
||||
return mCc;
|
||||
}
|
||||
return mCc;
|
||||
} else if (type == RecipientType.BCC) {
|
||||
if (mBcc == null) {
|
||||
mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC")));
|
||||
case BCC: {
|
||||
if (mBcc == null) {
|
||||
mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC")));
|
||||
}
|
||||
return mBcc;
|
||||
}
|
||||
return mBcc;
|
||||
} else {
|
||||
throw new MessagingException("Unrecognized recipient type.");
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unrecognized recipient type.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -538,33 +538,24 @@ public class K9 extends Application {
|
|||
|
||||
MessagingController.getInstance(this).addListener(new MessagingListener() {
|
||||
private void broadcastIntent(String action, Account account, String folder, Message message) {
|
||||
try {
|
||||
Uri uri = Uri.parse("email://messages/" + account.getAccountNumber() + "/" + Uri.encode(folder) + "/" + Uri.encode(message.getUid()));
|
||||
Intent intent = new Intent(action, uri);
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_ACCOUNT, account.getDescription());
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_FOLDER, folder);
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_SENT_DATE, message.getSentDate());
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_FROM, Address.toString(message.getFrom()));
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_TO, Address.toString(message.getRecipients(Message.RecipientType.TO)));
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_CC, Address.toString(message.getRecipients(Message.RecipientType.CC)));
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_BCC, Address.toString(message.getRecipients(Message.RecipientType.BCC)));
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_SUBJECT, message.getSubject());
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_FROM_SELF, account.isAnIdentity(message.getFrom()));
|
||||
K9.this.sendBroadcast(intent);
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "Broadcasted: action=" + action
|
||||
+ " account=" + account.getDescription()
|
||||
+ " folder=" + folder
|
||||
+ " message uid=" + message.getUid()
|
||||
);
|
||||
|
||||
} catch (MessagingException e) {
|
||||
Log.w(K9.LOG_TAG, "Error: action=" + action
|
||||
Uri uri = Uri.parse("email://messages/" + account.getAccountNumber() + "/" + Uri.encode(folder) + "/" + Uri.encode(message.getUid()));
|
||||
Intent intent = new Intent(action, uri);
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_ACCOUNT, account.getDescription());
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_FOLDER, folder);
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_SENT_DATE, message.getSentDate());
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_FROM, Address.toString(message.getFrom()));
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_TO, Address.toString(message.getRecipients(Message.RecipientType.TO)));
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_CC, Address.toString(message.getRecipients(Message.RecipientType.CC)));
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_BCC, Address.toString(message.getRecipients(Message.RecipientType.BCC)));
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_SUBJECT, message.getSubject());
|
||||
intent.putExtra(K9.Intents.EmailReceived.EXTRA_FROM_SELF, account.isAnIdentity(message.getFrom()));
|
||||
K9.this.sendBroadcast(intent);
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "Broadcasted: action=" + action
|
||||
+ " account=" + account.getDescription()
|
||||
+ " folder=" + folder
|
||||
+ " message uid=" + message.getUid()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUnreadWidget() {
|
||||
|
|
|
@ -76,6 +76,7 @@ import com.fsck.k9.fragment.ProgressDialogFragment.CancelListener;
|
|||
import com.fsck.k9.helper.Contacts;
|
||||
import com.fsck.k9.helper.IdentityHelper;
|
||||
import com.fsck.k9.helper.MailTo;
|
||||
import com.fsck.k9.helper.ReplyToParser;
|
||||
import com.fsck.k9.helper.SimpleTextWatcher;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
|
@ -400,7 +401,8 @@ public class MessageCompose extends K9Activity implements OnClickListener,
|
|||
|
||||
RecipientMvpView recipientMvpView = new RecipientMvpView(this);
|
||||
ComposePgpInlineDecider composePgpInlineDecider = new ComposePgpInlineDecider();
|
||||
recipientPresenter = new RecipientPresenter(this, recipientMvpView, mAccount, composePgpInlineDecider);
|
||||
recipientPresenter = new RecipientPresenter(this, recipientMvpView, mAccount,
|
||||
composePgpInlineDecider, new ReplyToParser());
|
||||
|
||||
mSubjectView = (EditText) findViewById(R.id.subject);
|
||||
mSubjectView.getInputExtras(true).putBoolean("allowEmoji", true);
|
||||
|
@ -1598,7 +1600,8 @@ public class MessageCompose extends K9Activity implements OnClickListener,
|
|||
* If a reply-to was included with the message use that, otherwise use the from
|
||||
* or sender address.
|
||||
*/
|
||||
recipientPresenter.initFromReplyToMessage(message);
|
||||
boolean isReplyAll = mAction == Action.REPLY_ALL;
|
||||
recipientPresenter.initFromReplyToMessage(message, isReplyAll);
|
||||
|
||||
if (message.getMessageId() != null && message.getMessageId().length() > 0) {
|
||||
mInReplyTo = message.getMessageId();
|
||||
|
|
|
@ -27,15 +27,14 @@ import com.fsck.k9.activity.compose.ComposeCryptoStatus.SendErrorState;
|
|||
import com.fsck.k9.helper.Contacts;
|
||||
import com.fsck.k9.helper.MailTo;
|
||||
import com.fsck.k9.helper.ReplyToParser;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Message.RecipientType;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
import com.fsck.k9.message.PgpMessageBuilder;
|
||||
import com.fsck.k9.message.ComposePgpInlineDecider;
|
||||
import com.fsck.k9.message.PgpMessageBuilder;
|
||||
import com.fsck.k9.view.RecipientSelectView.Recipient;
|
||||
import org.openintents.openpgp.IOpenPgpService2;
|
||||
import org.openintents.openpgp.util.OpenPgpApi;
|
||||
|
@ -61,6 +60,7 @@ public class RecipientPresenter implements PermissionPingCallback {
|
|||
private final Context context;
|
||||
private final RecipientMvpView recipientMvpView;
|
||||
private final ComposePgpInlineDecider composePgpInlineDecider;
|
||||
private ReplyToParser replyToParser;
|
||||
private Account account;
|
||||
private String cryptoProvider;
|
||||
private Boolean hasContactPicker;
|
||||
|
@ -78,10 +78,11 @@ public class RecipientPresenter implements PermissionPingCallback {
|
|||
|
||||
|
||||
public RecipientPresenter(Context context, RecipientMvpView recipientMvpView, Account account,
|
||||
ComposePgpInlineDecider composePgpInlineDecider) {
|
||||
ComposePgpInlineDecider composePgpInlineDecider, ReplyToParser replyToParser) {
|
||||
this.recipientMvpView = recipientMvpView;
|
||||
this.context = context;
|
||||
this.composePgpInlineDecider = composePgpInlineDecider;
|
||||
this.replyToParser = replyToParser;
|
||||
|
||||
recipientMvpView.setPresenter(this);
|
||||
onSwitchAccount(account);
|
||||
|
@ -134,50 +135,17 @@ public class RecipientPresenter implements PermissionPingCallback {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void initFromReplyToMessage(Message message) {
|
||||
Address[] replyToAddresses = ReplyToParser.getRecipientsToReplyTo(message);
|
||||
|
||||
try {
|
||||
// if we're replying to a message we sent, we probably meant
|
||||
// to reply to the recipient of that message
|
||||
if (account.isAnIdentity(replyToAddresses)) {
|
||||
replyToAddresses = message.getRecipients(RecipientType.TO);
|
||||
}
|
||||
public void initFromReplyToMessage(Message message, boolean isReplyAll) {
|
||||
ReplyToAddresses replyToAddresses = isReplyAll ?
|
||||
replyToParser.getRecipientsToReplyAllTo(message, account) :
|
||||
replyToParser.getRecipientsToReplyTo(message, account);
|
||||
|
||||
addRecipientsFromAddresses(RecipientType.TO, replyToAddresses);
|
||||
addToAddresses(replyToAddresses.to);
|
||||
addCcAddresses(replyToAddresses.cc);
|
||||
|
||||
if (message.getReplyTo().length > 0) {
|
||||
for (Address address : message.getFrom()) {
|
||||
if (!account.isAnIdentity(address) && !Utility.arrayContains(replyToAddresses, address)) {
|
||||
addRecipientsFromAddresses(RecipientType.TO, address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Address address : message.getRecipients(RecipientType.TO)) {
|
||||
if (!account.isAnIdentity(address) && !Utility.arrayContains(replyToAddresses, address)) {
|
||||
addToAddresses(address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (message.getRecipients(RecipientType.CC).length > 0) {
|
||||
for (Address address : message.getRecipients(RecipientType.CC)) {
|
||||
if (!account.isAnIdentity(address) && !Utility.arrayContains(replyToAddresses, address)) {
|
||||
addCcAddresses(address);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
boolean shouldSendAsPgpInline = composePgpInlineDecider.shouldReplyInline(message);
|
||||
if (shouldSendAsPgpInline) {
|
||||
cryptoEnablePgpInline = true;
|
||||
}
|
||||
|
||||
} catch (MessagingException e) {
|
||||
// can't happen, we know the recipient types exist
|
||||
throw new AssertionError(e);
|
||||
boolean shouldSendAsPgpInline = composePgpInlineDecider.shouldReplyInline(message);
|
||||
if (shouldSendAsPgpInline) {
|
||||
cryptoEnablePgpInline = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,18 +196,13 @@ public class RecipientPresenter implements PermissionPingCallback {
|
|||
}
|
||||
|
||||
private void initRecipientsFromDraftMessage(LocalMessage message) {
|
||||
try {
|
||||
addToAddresses(message.getRecipients(RecipientType.TO));
|
||||
addToAddresses(message.getRecipients(RecipientType.TO));
|
||||
|
||||
Address[] ccRecipients = message.getRecipients(RecipientType.CC);
|
||||
addCcAddresses(ccRecipients);
|
||||
Address[] ccRecipients = message.getRecipients(RecipientType.CC);
|
||||
addCcAddresses(ccRecipients);
|
||||
|
||||
Address[] bccRecipients = message.getRecipients(RecipientType.BCC);
|
||||
addBccAddresses(bccRecipients);
|
||||
} catch (MessagingException e) {
|
||||
// can't happen, we know the recipient types exist
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
Address[] bccRecipients = message.getRecipients(RecipientType.BCC);
|
||||
addBccAddresses(bccRecipients);
|
||||
}
|
||||
|
||||
private void initPgpInlineFromDraftMessage(LocalMessage message) {
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
package com.fsck.k9.helper;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.Identity;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
|
||||
public class IdentityHelper {
|
||||
|
||||
|
@ -27,28 +24,24 @@ public class IdentityHelper {
|
|||
public static Identity getRecipientIdentityFromMessage(Account account, Message message) {
|
||||
Identity recipient = null;
|
||||
|
||||
try {
|
||||
for (Address address : message.getRecipients(Message.RecipientType.TO)) {
|
||||
Identity identity = account.findIdentity(address);
|
||||
if (identity != null) {
|
||||
recipient = identity;
|
||||
break;
|
||||
}
|
||||
for (Address address : message.getRecipients(Message.RecipientType.TO)) {
|
||||
Identity identity = account.findIdentity(address);
|
||||
if (identity != null) {
|
||||
recipient = identity;
|
||||
break;
|
||||
}
|
||||
if (recipient == null) {
|
||||
Address[] ccAddresses = message.getRecipients(Message.RecipientType.CC);
|
||||
if (ccAddresses.length > 0) {
|
||||
for (Address address : ccAddresses) {
|
||||
Identity identity = account.findIdentity(address);
|
||||
if (identity != null) {
|
||||
recipient = identity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (recipient == null) {
|
||||
Address[] ccAddresses = message.getRecipients(Message.RecipientType.CC);
|
||||
if (ccAddresses.length > 0) {
|
||||
for (Address address : ccAddresses) {
|
||||
Identity identity = account.findIdentity(address);
|
||||
if (identity != null) {
|
||||
recipient = identity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (MessagingException e) {
|
||||
Log.w(K9.LOG_TAG, "Error finding the identity this message was sent to", e);
|
||||
}
|
||||
|
||||
if (recipient == null) {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package com.fsck.k9.helper;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
|
@ -15,7 +15,6 @@ import com.fsck.k9.activity.FolderInfoHolder;
|
|||
import com.fsck.k9.activity.MessageInfoHolder;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Message.RecipientType;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
|
||||
|
@ -53,45 +52,42 @@ public class MessageHelper {
|
|||
final FolderInfoHolder folder,
|
||||
Account account) {
|
||||
final Contacts contactHelper = K9.showContactName() ? Contacts.getInstance(mContext) : null;
|
||||
try {
|
||||
target.message = message;
|
||||
target.compareArrival = message.getInternalDate();
|
||||
target.compareDate = message.getSentDate();
|
||||
if (target.compareDate == null) {
|
||||
target.compareDate = message.getInternalDate();
|
||||
}
|
||||
|
||||
target.folder = folder;
|
||||
|
||||
target.read = message.isSet(Flag.SEEN);
|
||||
target.answered = message.isSet(Flag.ANSWERED);
|
||||
target.forwarded = message.isSet(Flag.FORWARDED);
|
||||
target.flagged = message.isSet(Flag.FLAGGED);
|
||||
|
||||
Address[] addrs = message.getFrom();
|
||||
|
||||
if (addrs.length > 0 && account.isAnIdentity(addrs[0])) {
|
||||
CharSequence to = toFriendly(message.getRecipients(RecipientType.TO), contactHelper);
|
||||
target.compareCounterparty = to.toString();
|
||||
target.sender = new SpannableStringBuilder(mContext.getString(R.string.message_to_label)).append(to);
|
||||
} else {
|
||||
target.sender = toFriendly(addrs, contactHelper);
|
||||
target.compareCounterparty = target.sender.toString();
|
||||
}
|
||||
|
||||
if (addrs.length > 0) {
|
||||
target.senderAddress = addrs[0].getAddress();
|
||||
} else {
|
||||
// a reasonable fallback "whomever we were corresponding with
|
||||
target.senderAddress = target.compareCounterparty;
|
||||
}
|
||||
|
||||
target.uid = message.getUid();
|
||||
target.account = message.getFolder().getAccountUuid();
|
||||
target.uri = message.getUri();
|
||||
} catch (MessagingException me) {
|
||||
Log.w(K9.LOG_TAG, "Unable to load message info", me);
|
||||
target.message = message;
|
||||
target.compareArrival = message.getInternalDate();
|
||||
target.compareDate = message.getSentDate();
|
||||
if (target.compareDate == null) {
|
||||
target.compareDate = message.getInternalDate();
|
||||
}
|
||||
|
||||
target.folder = folder;
|
||||
|
||||
target.read = message.isSet(Flag.SEEN);
|
||||
target.answered = message.isSet(Flag.ANSWERED);
|
||||
target.forwarded = message.isSet(Flag.FORWARDED);
|
||||
target.flagged = message.isSet(Flag.FLAGGED);
|
||||
|
||||
Address[] addrs = message.getFrom();
|
||||
|
||||
if (addrs.length > 0 && account.isAnIdentity(addrs[0])) {
|
||||
CharSequence to = toFriendly(message.getRecipients(RecipientType.TO), contactHelper);
|
||||
target.compareCounterparty = to.toString();
|
||||
target.sender = new SpannableStringBuilder(mContext.getString(R.string.message_to_label)).append(to);
|
||||
} else {
|
||||
target.sender = toFriendly(addrs, contactHelper);
|
||||
target.compareCounterparty = target.sender.toString();
|
||||
}
|
||||
|
||||
if (addrs.length > 0) {
|
||||
target.senderAddress = addrs[0].getAddress();
|
||||
} else {
|
||||
// a reasonable fallback "whomever we were corresponding with
|
||||
target.senderAddress = target.compareCounterparty;
|
||||
}
|
||||
|
||||
target.uid = message.getUid();
|
||||
target.account = message.getFolder().getAccountUuid();
|
||||
target.uri = message.getUri();
|
||||
}
|
||||
|
||||
public CharSequence getDisplayName(Account account, Address[] fromAddrs, Address[] toAddrs) {
|
||||
|
|
|
@ -1,23 +1,91 @@
|
|||
package com.fsck.k9.helper;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Message.RecipientType;
|
||||
import com.fsck.k9.mail.internet.ListHeaders;
|
||||
|
||||
|
||||
public class ReplyToParser {
|
||||
public static Address[] getRecipientsToReplyTo(Message message) {
|
||||
|
||||
public ReplyToAddresses getRecipientsToReplyTo(Message message, Account account) {
|
||||
Address[] candidateAddress;
|
||||
|
||||
Address[] replyToAddresses = message.getReplyTo();
|
||||
if (replyToAddresses.length > 0) {
|
||||
return replyToAddresses;
|
||||
}
|
||||
|
||||
Address[] listPostAddresses = ListHeaders.getListPostAddresses(message);
|
||||
if (listPostAddresses.length > 0) {
|
||||
return listPostAddresses;
|
||||
Address[] fromAddresses = message.getFrom();
|
||||
|
||||
if (replyToAddresses.length > 0) {
|
||||
candidateAddress = replyToAddresses;
|
||||
} else if (listPostAddresses.length > 0) {
|
||||
candidateAddress = listPostAddresses;
|
||||
} else {
|
||||
candidateAddress = fromAddresses;
|
||||
}
|
||||
|
||||
return message.getFrom();
|
||||
boolean replyToAddressIsUserIdentity = account.isAnIdentity(candidateAddress);
|
||||
if (replyToAddressIsUserIdentity) {
|
||||
candidateAddress = message.getRecipients(RecipientType.TO);
|
||||
}
|
||||
|
||||
return new ReplyToAddresses(candidateAddress);
|
||||
}
|
||||
|
||||
public ReplyToAddresses getRecipientsToReplyAllTo(Message message, Account account) {
|
||||
List<Address> replyToAddresses = Arrays.asList(getRecipientsToReplyTo(message, account).to);
|
||||
|
||||
HashSet<Address> alreadyAddedAddresses = new HashSet<>(replyToAddresses);
|
||||
ArrayList<Address> toAddresses = new ArrayList<>(replyToAddresses);
|
||||
ArrayList<Address> ccAddresses = new ArrayList<>();
|
||||
|
||||
for (Address address : message.getFrom()) {
|
||||
if (!alreadyAddedAddresses.contains(address) && !account.isAnIdentity(address)) {
|
||||
toAddresses.add(address);
|
||||
alreadyAddedAddresses.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
for (Address address : message.getRecipients(RecipientType.TO)) {
|
||||
if (!alreadyAddedAddresses.contains(address) && !account.isAnIdentity(address)) {
|
||||
toAddresses.add(address);
|
||||
alreadyAddedAddresses.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
for (Address address : message.getRecipients(RecipientType.CC)) {
|
||||
if (!alreadyAddedAddresses.contains(address) && !account.isAnIdentity(address)) {
|
||||
ccAddresses.add(address);
|
||||
alreadyAddedAddresses.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
return new ReplyToAddresses(toAddresses, ccAddresses);
|
||||
}
|
||||
|
||||
public static class ReplyToAddresses {
|
||||
public final Address[] to;
|
||||
public final Address[] cc;
|
||||
|
||||
@VisibleForTesting
|
||||
public ReplyToAddresses(List<Address> toAddresses, List<Address> ccAddresses) {
|
||||
to = toAddresses.toArray(new Address[toAddresses.size()]);
|
||||
cc = ccAddresses.toArray(new Address[ccAddresses.size()]);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public ReplyToAddresses(Address[] toAddresses) {
|
||||
to = toAddresses;
|
||||
cc = new Address[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -106,29 +106,25 @@ class NotificationContentCreator {
|
|||
}
|
||||
|
||||
private String getMessageSender(Account account, Message message) {
|
||||
try {
|
||||
boolean isSelf = false;
|
||||
final Contacts contacts = K9.showContactName() ? Contacts.getInstance(context) : null;
|
||||
final Address[] fromAddresses = message.getFrom();
|
||||
boolean isSelf = false;
|
||||
final Contacts contacts = K9.showContactName() ? Contacts.getInstance(context) : null;
|
||||
final Address[] fromAddresses = message.getFrom();
|
||||
|
||||
if (fromAddresses != null) {
|
||||
isSelf = account.isAnIdentity(fromAddresses);
|
||||
if (!isSelf && fromAddresses.length > 0) {
|
||||
return MessageHelper.toFriendly(fromAddresses[0], contacts).toString();
|
||||
}
|
||||
if (fromAddresses != null) {
|
||||
isSelf = account.isAnIdentity(fromAddresses);
|
||||
if (!isSelf && fromAddresses.length > 0) {
|
||||
return MessageHelper.toFriendly(fromAddresses[0], contacts).toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (isSelf) {
|
||||
// show To: if the message was sent from me
|
||||
Address[] recipients = message.getRecipients(Message.RecipientType.TO);
|
||||
if (isSelf) {
|
||||
// show To: if the message was sent from me
|
||||
Address[] recipients = message.getRecipients(Message.RecipientType.TO);
|
||||
|
||||
if (recipients != null && recipients.length > 0) {
|
||||
return context.getString(R.string.message_to_fmt,
|
||||
MessageHelper.toFriendly(recipients[0], contacts).toString());
|
||||
}
|
||||
if (recipients != null && recipients.length > 0) {
|
||||
return context.getString(R.string.message_to_fmt,
|
||||
MessageHelper.toFriendly(recipients[0], contacts).toString());
|
||||
}
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "Unable to get sender information for notification.", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -193,11 +193,7 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
|
|||
}
|
||||
|
||||
private void onAddRecipientsToClipboard(Message.RecipientType recipientType) {
|
||||
try {
|
||||
onAddAddressesToClipboard(mMessage.getRecipients(recipientType));
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "Couldn't get recipients address", e);
|
||||
}
|
||||
onAddAddressesToClipboard(mMessage.getRecipients(recipientType));
|
||||
}
|
||||
|
||||
public void setOnFlagListener(OnClickListener listener) {
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
package com.fsck.k9.activity.compose;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.helper.ReplyToParser;
|
||||
import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Message.RecipientType;
|
||||
import com.fsck.k9.message.ComposePgpInlineDecider;
|
||||
import com.fsck.k9.view.RecipientSelectView.Recipient;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowApplication;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = "src/main/AndroidManifest.xml", sdk = 21)
|
||||
public class RecipientPresenterTest {
|
||||
public static final ReplyToAddresses TO_ADDRESSES = new ReplyToAddresses(Address.parse("to@example.org"));
|
||||
public static final List<Address> ALL_TO_ADDRESSES = Arrays.asList(Address.parse("allTo@example.org"));
|
||||
public static final List<Address> ALL_CC_ADDRESSES = Arrays.asList(Address.parse("allCc@example.org"));
|
||||
|
||||
|
||||
RecipientPresenter recipientPresenter;
|
||||
private ReplyToParser replyToParser;
|
||||
private ComposePgpInlineDecider composePgpInlineDecider;
|
||||
private Account account;
|
||||
private RecipientMvpView recipientMvpView;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Context context = ShadowApplication.getInstance().getApplicationContext();
|
||||
|
||||
recipientMvpView = mock(RecipientMvpView.class);
|
||||
account = mock(Account.class);
|
||||
composePgpInlineDecider = mock(ComposePgpInlineDecider.class);
|
||||
replyToParser = mock(ReplyToParser.class);
|
||||
|
||||
recipientPresenter = new RecipientPresenter(
|
||||
context, recipientMvpView, account, composePgpInlineDecider, replyToParser);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitFromReplyToMessage() throws Exception {
|
||||
Message message = mock(Message.class);
|
||||
when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
|
||||
|
||||
recipientPresenter.initFromReplyToMessage(message, false);
|
||||
|
||||
verify(recipientMvpView).addRecipients(eq(RecipientType.TO), any(Recipient[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitFromReplyToAllMessage() throws Exception {
|
||||
Message message = mock(Message.class);
|
||||
when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
|
||||
ReplyToAddresses replyToAddresses = new ReplyToAddresses(ALL_TO_ADDRESSES, ALL_CC_ADDRESSES);
|
||||
when(replyToParser.getRecipientsToReplyAllTo(message, account)).thenReturn(replyToAddresses);
|
||||
|
||||
recipientPresenter.initFromReplyToMessage(message, true);
|
||||
|
||||
verify(recipientMvpView).addRecipients(eq(RecipientType.TO), any(Recipient.class));
|
||||
verify(recipientMvpView).addRecipients(eq(RecipientType.CC), any(Recipient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initFromReplyToMessage_shouldCallComposePgpInlineDecider() throws Exception {
|
||||
Message message = mock(Message.class);
|
||||
when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
|
||||
|
||||
recipientPresenter.initFromReplyToMessage(message, false);
|
||||
|
||||
verify(composePgpInlineDecider).shouldReplyInline(message);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
package com.fsck.k9.helper;
|
||||
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Message.RecipientType;
|
||||
import com.fsck.k9.mail.internet.ListHeaders;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -11,25 +17,38 @@ import org.robolectric.RobolectricTestRunner;
|
|||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE, sdk = 21)
|
||||
public class ReplyToParserTest {
|
||||
private static final Address[] REPLY_TO_ADDRESSES = createAddressArray("replyTo@example.com");
|
||||
private static final Address[] LIST_POST_ADDRESSES = createAddressArray("listPost@example.com");
|
||||
private static final Address[] FROM_ADDRESSES = createAddressArray("from@example.com");
|
||||
private static final Address[] REPLY_TO_ADDRESSES = Address.parse("replyTo1@example.com, replyTo2@example.com");
|
||||
private static final Address[] LIST_POST_ADDRESSES = Address.parse("listPost@example.com");
|
||||
private static final Address[] FROM_ADDRESSES = Address.parse("from@example.com");
|
||||
private static final Address[] TO_ADDRESSES = Address.parse("to1@example.com, to2@example.com");
|
||||
private static final Address[] CC_ADDRESSES = Address.parse("cc1@example.com, cc2@example.com");
|
||||
private static final String[] LIST_POST_HEADER_VALUES = new String[] { "<mailto:listPost@example.com>" };
|
||||
public static final Address[] EMPTY_ADDRESSES = new Address[0];
|
||||
|
||||
|
||||
private ReplyToParser replyToParser;
|
||||
private Message message;
|
||||
private Account account;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
message = mock(Message.class);
|
||||
account = mock(Account.class);
|
||||
|
||||
replyToParser = new ReplyToParser();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -38,34 +57,131 @@ public class ReplyToParserTest {
|
|||
when(message.getHeader(ListHeaders.LIST_POST_HEADER)).thenReturn(LIST_POST_HEADER_VALUES);
|
||||
when(message.getFrom()).thenReturn(FROM_ADDRESSES);
|
||||
|
||||
Address[] result = ReplyToParser.getRecipientsToReplyTo(message);
|
||||
ReplyToAddresses result = replyToParser.getRecipientsToReplyTo(message, account);
|
||||
|
||||
assertArrayEquals(REPLY_TO_ADDRESSES, result);
|
||||
assertArrayEquals(REPLY_TO_ADDRESSES, result.to);
|
||||
assertArrayEquals(EMPTY_ADDRESSES, result.cc);
|
||||
verify(account).isAnIdentity(result.to);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecipientsToReplyTo_should_prefer_from_ifOtherIsIdentity() throws Exception {
|
||||
when(message.getReplyTo()).thenReturn(REPLY_TO_ADDRESSES);
|
||||
when(message.getHeader(ListHeaders.LIST_POST_HEADER)).thenReturn(LIST_POST_HEADER_VALUES);
|
||||
when(message.getFrom()).thenReturn(FROM_ADDRESSES);
|
||||
when(message.getRecipients(RecipientType.TO)).thenReturn(TO_ADDRESSES);
|
||||
when(account.isAnIdentity(any(Address[].class))).thenReturn(true);
|
||||
|
||||
ReplyToAddresses result = replyToParser.getRecipientsToReplyTo(message, account);
|
||||
|
||||
assertArrayEquals(TO_ADDRESSES, result.to);
|
||||
assertArrayEquals(EMPTY_ADDRESSES, result.cc);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecipientsToReplyTo_should_prefer_listPost_over_from_field() throws Exception {
|
||||
when(message.getReplyTo()).thenReturn(new Address[0]);
|
||||
when(message.getReplyTo()).thenReturn(EMPTY_ADDRESSES);
|
||||
when(message.getHeader(ListHeaders.LIST_POST_HEADER)).thenReturn(LIST_POST_HEADER_VALUES);
|
||||
when(message.getFrom()).thenReturn(FROM_ADDRESSES);
|
||||
|
||||
Address[] result = ReplyToParser.getRecipientsToReplyTo(message);
|
||||
ReplyToAddresses result = replyToParser.getRecipientsToReplyTo(message, account);
|
||||
|
||||
assertArrayEquals(LIST_POST_ADDRESSES, result);
|
||||
assertArrayEquals(LIST_POST_ADDRESSES, result.to);
|
||||
assertArrayEquals(EMPTY_ADDRESSES, result.cc);
|
||||
verify(account).isAnIdentity(result.to);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecipientsToReplyTo_should_return_from_otherwise() throws Exception {
|
||||
when(message.getReplyTo()).thenReturn(new Address[0]);
|
||||
when(message.getReplyTo()).thenReturn(EMPTY_ADDRESSES);
|
||||
when(message.getHeader(ListHeaders.LIST_POST_HEADER)).thenReturn(new String[0]);
|
||||
when(message.getFrom()).thenReturn(FROM_ADDRESSES);
|
||||
|
||||
Address[] result = ReplyToParser.getRecipientsToReplyTo(message);
|
||||
ReplyToAddresses result = replyToParser.getRecipientsToReplyTo(message, account);
|
||||
|
||||
assertArrayEquals(FROM_ADDRESSES, result);
|
||||
assertArrayEquals(FROM_ADDRESSES, result.to);
|
||||
assertArrayEquals(EMPTY_ADDRESSES, result.cc);
|
||||
verify(account).isAnIdentity(result.to);
|
||||
}
|
||||
|
||||
private static Address[] createAddressArray(String emailAddress) {
|
||||
return new Address[] { new Address(emailAddress) };
|
||||
@Test
|
||||
public void getRecipientsToReplyAllTo_should_returnFromAndToAndCcRecipients() throws Exception {
|
||||
when(message.getReplyTo()).thenReturn(EMPTY_ADDRESSES);
|
||||
when(message.getHeader(ListHeaders.LIST_POST_HEADER)).thenReturn(new String[0]);
|
||||
when(message.getFrom()).thenReturn(FROM_ADDRESSES);
|
||||
when(message.getRecipients(RecipientType.TO)).thenReturn(TO_ADDRESSES);
|
||||
when(message.getRecipients(RecipientType.CC)).thenReturn(CC_ADDRESSES);
|
||||
|
||||
ReplyToAddresses recipientsToReplyAllTo = replyToParser.getRecipientsToReplyAllTo(message, account);
|
||||
|
||||
assertArrayEquals(arrayConcatenate(FROM_ADDRESSES, TO_ADDRESSES, Address.class), recipientsToReplyAllTo.to);
|
||||
assertArrayEquals(CC_ADDRESSES, recipientsToReplyAllTo.cc);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecipientsToReplyAllTo_should_excludeIdentityAddresses() throws Exception {
|
||||
when(message.getReplyTo()).thenReturn(EMPTY_ADDRESSES);
|
||||
when(message.getHeader(ListHeaders.LIST_POST_HEADER)).thenReturn(new String[0]);
|
||||
when(message.getFrom()).thenReturn(EMPTY_ADDRESSES);
|
||||
|
||||
when(message.getRecipients(RecipientType.TO)).thenReturn(TO_ADDRESSES);
|
||||
when(message.getRecipients(RecipientType.CC)).thenReturn(CC_ADDRESSES);
|
||||
Address excludedCcAddress = CC_ADDRESSES[1];
|
||||
Address excludedToAddress = TO_ADDRESSES[0];
|
||||
when(account.isAnIdentity(eq(excludedToAddress))).thenReturn(true);
|
||||
when(account.isAnIdentity(eq(excludedCcAddress))).thenReturn(true);
|
||||
|
||||
|
||||
ReplyToAddresses recipientsToReplyAllTo = replyToParser.getRecipientsToReplyAllTo(message, account);
|
||||
|
||||
|
||||
assertArrayEquals(arrayExcept(TO_ADDRESSES, excludedToAddress), recipientsToReplyAllTo.to);
|
||||
assertArrayEquals(arrayExcept(CC_ADDRESSES, excludedCcAddress), recipientsToReplyAllTo.cc);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecipientsToReplyAllTo_should_excludeDuplicates() throws Exception {
|
||||
when(message.getReplyTo()).thenReturn(REPLY_TO_ADDRESSES);
|
||||
when(message.getFrom()).thenReturn(arrayConcatenate(FROM_ADDRESSES, REPLY_TO_ADDRESSES, Address.class));
|
||||
when(message.getRecipients(RecipientType.TO)).thenReturn(arrayConcatenate(FROM_ADDRESSES, TO_ADDRESSES, Address.class));
|
||||
when(message.getRecipients(RecipientType.CC)).thenReturn(arrayConcatenate(CC_ADDRESSES, TO_ADDRESSES, Address.class));
|
||||
when(message.getHeader(ListHeaders.LIST_POST_HEADER)).thenReturn(new String[0]);
|
||||
|
||||
ReplyToAddresses recipientsToReplyAllTo = replyToParser.getRecipientsToReplyAllTo(message, account);
|
||||
|
||||
assertArrayContainsAll(REPLY_TO_ADDRESSES, recipientsToReplyAllTo.to);
|
||||
assertArrayContainsAll(FROM_ADDRESSES, recipientsToReplyAllTo.to);
|
||||
assertArrayContainsAll(TO_ADDRESSES, recipientsToReplyAllTo.to);
|
||||
int totalExpectedAddresses = REPLY_TO_ADDRESSES.length + FROM_ADDRESSES.length + TO_ADDRESSES.length;
|
||||
assertEquals(totalExpectedAddresses, recipientsToReplyAllTo.to.length);
|
||||
assertArrayEquals(CC_ADDRESSES, recipientsToReplyAllTo.cc);
|
||||
}
|
||||
|
||||
public <T> void assertArrayContainsAll(T[] expecteds, T[] actual) {
|
||||
for (T expected : expecteds) {
|
||||
assertTrue("Element must be in array (" + expected + ")", Utility.arrayContains(actual, expected));
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T[] arrayConcatenate(T[] first, T[] second, Class<T> cls) {
|
||||
// noinspection unchecked
|
||||
T[] result = (T[]) Array.newInstance(cls, first.length + second.length);
|
||||
|
||||
System.arraycopy(first, 0, result, 0, first.length);
|
||||
System.arraycopy(second, 0, result, first.length, second.length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> T[] arrayExcept(T[] in, T except) {
|
||||
ArrayList<T> result = new ArrayList<>();
|
||||
for (T element : in) {
|
||||
if (!element.equals(except)) {
|
||||
result.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection unchecked, it's a hack but it works ♪
|
||||
return result.toArray((T[]) new Object[result.size()]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue