Put the logic that decides which message format to use in one place

This change is in preparation for the future rich text editing
functionality.
This commit is contained in:
cketti 2012-05-20 22:44:32 +02:00
parent 71b3b2916e
commit e88633cf78
1 changed files with 243 additions and 95 deletions

View File

@ -1,19 +1,6 @@
package com.fsck.k9.activity;
import java.io.File;
import java.io.Serializable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.text.*;
import android.webkit.WebViewClient;
import com.fsck.k9.helper.HtmlConverter;
import com.fsck.k9.helper.StringUtils;
import com.fsck.k9.mail.*;
import com.fsck.k9.view.MessageWebView;
import org.apache.james.mime4j.codec.EncoderUtil;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
@ -30,6 +17,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.provider.OpenableColumns;
import android.text.TextWatcher;
import android.text.util.Rfc822Tokenizer;
import android.util.Log;
import android.util.TypedValue;
@ -42,25 +30,22 @@ import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.view.Window;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.AutoCompleteTextView.Validator;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.MultiAutoCompleteTextView;
import android.widget.TextView;
import android.widget.Toast;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.SimpleHtmlSerializer;
import org.htmlcleaner.TagNode;
import com.fsck.k9.Account;
import com.fsck.k9.Account.QuoteStyle;
import com.fsck.k9.Account.MessageFormat;
import com.fsck.k9.Account.QuoteStyle;
import com.fsck.k9.EmailAddressAdapter;
import com.fsck.k9.EmailAddressValidator;
import com.fsck.k9.FontSizes;
@ -74,8 +59,17 @@ import com.fsck.k9.crypto.CryptoProvider;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.helper.ContactItem;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.HtmlConverter;
import com.fsck.k9.helper.StringUtils;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Body;
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.mail.Multipart;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.internet.MimeBodyPart;
import com.fsck.k9.mail.internet.MimeHeader;
import com.fsck.k9.mail.internet.MimeMessage;
@ -84,6 +78,24 @@ import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.internet.TextBody;
import com.fsck.k9.mail.store.LocalStore;
import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBody;
import com.fsck.k9.view.MessageWebView;
import org.apache.james.mime4j.codec.EncoderUtil;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.SimpleHtmlSerializer;
import org.htmlcleaner.TagNode;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MessageCompose extends K9Activity implements OnClickListener, OnFocusChangeListener {
private static final int DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE = 1;
@ -123,9 +135,12 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private static final String STATE_PGP_DATA = "pgpData";
private static final String STATE_IN_REPLY_TO = "com.fsck.k9.activity.MessageCompose.inReplyTo";
private static final String STATE_REFERENCES = "com.fsck.k9.activity.MessageCompose.references";
private static final String STATE_KEY_MESSAGE_FORMAT = "com.fsck.k9.activity.MessageCompose.messageFormat";
private static final String STATE_KEY_READ_RECEIPT = "com.fsck.k9.activity.MessageCompose.messageReadReceipt";
private static final String STATE_KEY_DRAFT_NEEDS_SAVING = "com.fsck.k9.activity.MessageCompose.mDraftNeedsSaving";
private static final String STATE_KEY_FORCE_PLAIN_TEXT =
"com.fsck.k9.activity.MessageCompose.forcePlainText";
private static final String STATE_KEY_QUOTED_TEXT_FORMAT =
"com.fsck.k9.activity.MessageCompose.quotedTextFormat";
private static final int MSG_PROGRESS_ON = 1;
private static final int MSG_PROGRESS_OFF = 2;
@ -176,6 +191,21 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private MessageReference mMessageReference;
private Message mSourceMessage;
/**
* "Original" message body
*
* <p>
* The contents of this string will be used instead of the body of a referenced message when
* replying to or forwarding a message.<br>
* Right now this is only used when replying to a signed or encrypted message. It then contains
* the stripped/decrypted body of that message.
* </p>
* <p><strong>Note:</strong>
* When this field is not {@code null} we assume that the message we are composing right now
* should be encrypted.
* </p>
*/
private String mSourceMessageBody;
/**
@ -208,6 +238,17 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private QuotedTextMode mQuotedTextMode = QuotedTextMode.NONE;
/**
* Contains the format of the quoted text (text vs. HTML).
*/
private SimpleMessageFormat mQuotedTextFormat;
/**
* When this it {@code true} the message format setting is ignored and we're always sending
* a text/plain message.
*/
private boolean mForcePlainText = false;
private Button mChooseIdentityButton;
private LinearLayout mCcWrapper;
private LinearLayout mBccWrapper;
@ -243,7 +284,22 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private String mInReplyTo;
private boolean mSourceProcessed = false;
private MessageFormat mMessageFormat;
enum SimpleMessageFormat {
TEXT,
HTML
}
/**
* The currently used message format.
*
* <p>
* <strong>Note:</strong>
* Don't modify this field directly. Use {@link #updateMessageFormat()}.
* </p>
*/
private SimpleMessageFormat mMessageFormat;
private QuoteStyle mQuoteStyle;
private boolean mDraftNeedsSaving = false;
@ -638,17 +694,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mSignatureView.setVisibility(View.GONE);
}
mMessageFormat = mAccount.getMessageFormat();
if (mMessageFormat == MessageFormat.AUTO) {
if (mAction == Action.COMPOSE) {
mMessageFormat = MessageFormat.TEXT;
} else if (mSourceMessageBody != null) {
// mSourceMessageBody is set to something when replying to and forwarding decrypted
// messages, so we set the format to plain text.
mMessageFormat = MessageFormat.TEXT;
}
}
mReadReceipt = mAccount.isMessageReadReceiptAlways();
mQuoteStyle = mAccount.getQuoteStyle();
@ -710,6 +755,13 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mCryptoSignatureUserId = (TextView)findViewById(R.id.userId);
mCryptoSignatureUserIdRest = (TextView)findViewById(R.id.userIdRest);
mEncryptCheckbox = (CheckBox)findViewById(R.id.cb_encrypt);
mEncryptCheckbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
updateMessageFormat();
}
});
if (mSourceMessageBody != null) {
// mSourceMessageBody is set to something when replying to and forwarding decrypted
// messages, so the sender probably wants the message to be encrypted.
@ -764,6 +816,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mMessageContentView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
mQuotedText.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
mSignatureView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
updateMessageFormat();
}
/**
@ -922,7 +976,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mCryptoSignatureUserId.setVisibility(View.INVISIBLE);
mCryptoSignatureUserIdRest.setVisibility(View.INVISIBLE);
} else {
mMessageFormat = MessageFormat.TEXT;
// if a signature key is selected, then the checkbox itself has no text
mCryptoSignatureCheckbox.setText("");
mCryptoSignatureCheckbox.setChecked(true);
@ -945,6 +998,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
}
}
updateMessageFormat();
}
@Override
@ -994,9 +1049,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
outState.putString(STATE_IN_REPLY_TO, mInReplyTo);
outState.putString(STATE_REFERENCES, mReferences);
outState.putSerializable(STATE_KEY_HTML_QUOTE, mQuotedHtmlContent);
outState.putSerializable(STATE_KEY_MESSAGE_FORMAT, mMessageFormat);
outState.putBoolean(STATE_KEY_READ_RECEIPT, mReadReceipt);
outState.putBoolean(STATE_KEY_DRAFT_NEEDS_SAVING, mDraftNeedsSaving);
outState.putBoolean(STATE_KEY_FORCE_PLAIN_TEXT, mForcePlainText);
outState.putSerializable(STATE_KEY_QUOTED_TEXT_FORMAT, mQuotedTextFormat);
}
@Override
@ -1009,21 +1065,22 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
addAttachment(uri);
}
mMessageFormat = (MessageFormat) savedInstanceState
.getSerializable(STATE_KEY_MESSAGE_FORMAT);
mReadReceipt = savedInstanceState
.getBoolean(STATE_KEY_READ_RECEIPT);
mCcWrapper.setVisibility(savedInstanceState.getBoolean(STATE_KEY_CC_SHOWN) ? View.VISIBLE
: View.GONE);
mBccWrapper.setVisibility(savedInstanceState
.getBoolean(STATE_KEY_BCC_SHOWN) ? View.VISIBLE : View.GONE);
showOrHideQuotedText((QuotedTextMode)savedInstanceState.getSerializable(STATE_KEY_QUOTED_TEXT_MODE));
if (mQuotedTextMode != QuotedTextMode.NONE && mMessageFormat == MessageFormat.HTML) {
mQuotedHtmlContent = (InsertableHtmlContent) savedInstanceState.getSerializable(STATE_KEY_HTML_QUOTE);
if (mQuotedHtmlContent != null && mQuotedHtmlContent.getQuotedContent() != null) {
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
}
showOrHideQuotedText(
(QuotedTextMode) savedInstanceState.getSerializable(STATE_KEY_QUOTED_TEXT_MODE));
mQuotedHtmlContent =
(InsertableHtmlContent) savedInstanceState.getSerializable(STATE_KEY_HTML_QUOTE);
if (mQuotedHtmlContent != null && mQuotedHtmlContent.getQuotedContent() != null) {
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
}
mDraftId = savedInstanceState.getLong(STATE_KEY_DRAFT_ID);
mIdentity = (Identity)savedInstanceState.getSerializable(STATE_IDENTITY);
mIdentityChanged = savedInstanceState.getBoolean(STATE_IDENTITY_CHANGED);
@ -1031,12 +1088,16 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mInReplyTo = savedInstanceState.getString(STATE_IN_REPLY_TO);
mReferences = savedInstanceState.getString(STATE_REFERENCES);
mDraftNeedsSaving = savedInstanceState.getBoolean(STATE_KEY_DRAFT_NEEDS_SAVING);
mForcePlainText = savedInstanceState.getBoolean(STATE_KEY_FORCE_PLAIN_TEXT);
mQuotedTextFormat = (SimpleMessageFormat) savedInstanceState.getSerializable(
STATE_KEY_QUOTED_TEXT_FORMAT);
initializeCrypto();
updateFrom();
updateSignature();
updateEncryptLayout();
updateMessageFormat();
}
private void updateTitle() {
@ -1109,7 +1170,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
* @return {@link TextBody} instance that contains the entered text and possibly the quoted
* original message.
*/
private TextBody buildText(boolean isDraft, MessageFormat messageFormat) {
private TextBody buildText(boolean isDraft, SimpleMessageFormat messageFormat) {
// The length of the formatted version of the user-supplied text/reply
int composedMessageLength;
@ -1135,7 +1196,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
String text = mMessageContentView.getText().toString();
// Handle HTML separate from the rest of the text content
if (messageFormat == MessageFormat.HTML) {
if (messageFormat == SimpleMessageFormat.HTML) {
// Do we have to modify an existing message to include our reply?
if (includeQuotedText && mQuotedHtmlContent != null) {
@ -1293,14 +1354,14 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
final boolean hasAttachments = mAttachments.getChildCount() > 0;
if (mMessageFormat == MessageFormat.HTML) {
if (mMessageFormat == SimpleMessageFormat.HTML) {
// HTML message (with alternative text part)
// This is the compiled MIME part for an HTML message.
MimeMultipart composedMimeMessage = new MimeMultipart();
composedMimeMessage.setSubType("alternative"); // Let the receiver select either the text or the HTML part.
composedMimeMessage.addBodyPart(new MimeBodyPart(body, "text/html"));
bodyPlain = buildText(isDraft, MessageFormat.TEXT);
bodyPlain = buildText(isDraft, SimpleMessageFormat.TEXT);
composedMimeMessage.addBodyPart(new MimeBodyPart(bodyPlain, "text/plain"));
if (hasAttachments) {
@ -1316,7 +1377,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
// If no attachments, our multipart/alternative part is the only one we need.
message.setBody(composedMimeMessage);
}
} else {
} else if (mMessageFormat == SimpleMessageFormat.TEXT) {
// Text-only message.
if (hasAttachments) {
MimeMultipart mp = new MimeMultipart();
@ -1647,7 +1708,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
final CryptoProvider crypto = mAccount.getCryptoProvider();
if (mEncryptCheckbox.isChecked() && !mPgpData.hasEncryptionKeys()) {
mMessageFormat = MessageFormat.TEXT;
// key selection before encryption
StringBuilder emails = new StringBuilder();
for (Address address : getRecipientAddresses()) {
@ -1969,6 +2029,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mDraftNeedsSaving = true;
updateFrom();
updateSignature();
updateMessageFormat();
}
private void updateFrom() {
@ -1998,14 +2059,16 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
break;
case R.id.quoted_text_show:
showOrHideQuotedText(QuotedTextMode.SHOW);
updateMessageFormat();
mDraftNeedsSaving = true;
break;
case R.id.quoted_text_delete:
showOrHideQuotedText(QuotedTextMode.HIDE);
updateMessageFormat();
mDraftNeedsSaving = true;
break;
case R.id.quoted_text_edit:
mMessageFormat = MessageFormat.TEXT;
mForcePlainText = true;
if (mMessageReference != null) { // shouldn't happen...
// TODO - Should we check if mSourceMessageBody is already present and bypass the MessagingController call?
MessagingController.getInstance(getApplication()).addListener(mListener);
@ -2021,37 +2084,43 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
}
/*
* Show or Hide the quoted text according to mQuotedTextMode.
/**
* Show or hide the quoted text.
*
* @param mode
* The value to set {@link #mQuotedTextMode} to.
*/
private void showOrHideQuotedText(QuotedTextMode mode) {
mQuotedTextMode = mode;
if (mQuotedTextMode == QuotedTextMode.NONE) {
mQuotedTextShow.setVisibility(View.GONE);
mQuotedTextBar.setVisibility(View.GONE);
mQuotedText.setVisibility(View.GONE);
mQuotedHTML.setVisibility(View.GONE);
mQuotedTextEdit.setVisibility(View.GONE);
} else if (mQuotedTextMode == QuotedTextMode.SHOW) {
mQuotedTextShow.setVisibility(View.GONE);
mQuotedTextBar.setVisibility(View.VISIBLE);
if (mMessageFormat == MessageFormat.HTML) {
switch (mode) {
case NONE:
case HIDE: {
if (mode == QuotedTextMode.NONE) {
mQuotedTextShow.setVisibility(View.GONE);
} else {
mQuotedTextShow.setVisibility(View.VISIBLE);
}
mQuotedTextBar.setVisibility(View.GONE);
mQuotedText.setVisibility(View.GONE);
mQuotedHTML.setVisibility(View.VISIBLE);
mQuotedTextEdit.setVisibility(View.VISIBLE);
} else {
mQuotedText.setVisibility(View.VISIBLE);
mQuotedHTML.setVisibility(View.GONE);
mQuotedTextEdit.setVisibility(View.GONE);
break;
}
} else if (mQuotedTextMode == QuotedTextMode.HIDE) {
mQuotedTextShow.setVisibility(View.VISIBLE);
mQuotedTextBar.setVisibility(View.GONE);
case SHOW: {
mQuotedTextShow.setVisibility(View.GONE);
mQuotedTextBar.setVisibility(View.VISIBLE);
mQuotedText.setVisibility(View.GONE);
mQuotedHTML.setVisibility(View.GONE);
mQuotedTextEdit.setVisibility(View.GONE);
if (mQuotedTextFormat == SimpleMessageFormat.HTML) {
mQuotedText.setVisibility(View.GONE);
mQuotedHTML.setVisibility(View.VISIBLE);
mQuotedTextEdit.setVisibility(View.VISIBLE);
} else {
mQuotedText.setVisibility(View.VISIBLE);
mQuotedHTML.setVisibility(View.GONE);
mQuotedTextEdit.setVisibility(View.GONE);
}
break;
}
}
}
@ -2319,6 +2388,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mSourceMessageProcessed = true;
mDraftNeedsSaving = false;
}
updateMessageFormat();
}
private void processMessageToReplyTo(Message message) throws MessagingException {
@ -2573,27 +2644,44 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
? QuoteStyle.valueOf(k9identity.get(IdentityField.QUOTE_STYLE))
: mAccount.getQuoteStyle();
QuotedTextMode quotedMode;
try {
quotedMode = QuotedTextMode.valueOf(showQuotedTextMode);
} catch (Exception e) {
quotedMode = QuotedTextMode.NONE;
}
// Always respect the user's current composition format preference, even if the
// draft was saved in a different format.
// TODO - The current implementation doesn't allow a user in HTML mode to edit a draft that wasn't saved with K9mail.
String messageFormat = k9identity.get(IdentityField.MESSAGE_FORMAT);
String messageFormatString = k9identity.get(IdentityField.MESSAGE_FORMAT);
MessageFormat messageFormat = null;
if (messageFormatString != null) {
try {
messageFormat = MessageFormat.valueOf(messageFormatString);
} catch (Exception e) { /* do nothing */ }
}
if (messageFormat == null) {
// This message probably wasn't created by us. The exception is legacy
// drafts created before the advent of HTML composition. In those cases,
// we'll display the whole message (including the quoted part) in the
// composition window. If that's the case, try and convert it to text to
// match the behavior in text mode.
mMessageContentView.setText(getBodyTextFromMessage(message, MessageFormat.TEXT));
mMessageFormat = MessageFormat.TEXT;
showOrHideQuotedText(QuotedTextMode.valueOf(showQuotedTextMode));
mMessageContentView.setText(getBodyTextFromMessage(message, SimpleMessageFormat.TEXT));
mForcePlainText = true;
showOrHideQuotedText(quotedMode);
return;
}
mMessageFormat = MessageFormat.valueOf(messageFormat);
if (mMessageFormat == MessageFormat.HTML) {
if (messageFormat == MessageFormat.HTML) {
Part part = MimeUtility.findFirstPartByMimeType(message, "text/html");
if (part != null) { // Shouldn't happen if we were the one who saved it.
mQuotedTextFormat = SimpleMessageFormat.HTML;
String text = MimeUtility.getTextFromPart(part);
if (K9.DEBUG) {
Log.d(K9.LOG_TAG, "Loading message with offset " + bodyOffset + ", length " + bodyLength + ". Text length is " + text.length() + ".");
@ -2623,7 +2711,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
if (bodyPlainOffset != null && bodyPlainLength != null) {
processSourceMessageText(message, bodyPlainOffset, bodyPlainLength, false);
}
} else if (mMessageFormat == MessageFormat.TEXT) {
} else if (messageFormat == MessageFormat.TEXT) {
mQuotedTextFormat = SimpleMessageFormat.TEXT;
processSourceMessageText(message, bodyOffset, bodyLength, true);
} else {
Log.e(K9.LOG_TAG, "Unhandled message format.");
@ -2636,7 +2725,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
Log.e(K9.LOG_TAG, "Could not set cursor position in MessageCompose; ignoring.", e);
}
showOrHideQuotedText(QuotedTextMode.valueOf(showQuotedTextMode));
showOrHideQuotedText(quotedMode);
}
/*
@ -2699,20 +2788,29 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
* @throws MessagingException
*/
private void populateUIWithQuotedMessage(boolean showQuotedText) throws MessagingException {
if (mMessageFormat == MessageFormat.AUTO) {
mMessageFormat = MimeUtility.findFirstPartByMimeType(mSourceMessage, "text/html") == null
? MessageFormat.TEXT
: MessageFormat.HTML;
MessageFormat origMessageFormat = mAccount.getMessageFormat();
if (mForcePlainText || origMessageFormat == MessageFormat.TEXT) {
// Use plain text for the quoted message
mQuotedTextFormat = SimpleMessageFormat.TEXT;
} else if (origMessageFormat == MessageFormat.AUTO) {
// Figure out which message format to use for the quoted text by looking if the source
// message contains a text/html part. If it does, we use that.
mQuotedTextFormat =
(MimeUtility.findFirstPartByMimeType(mSourceMessage, "text/html") == null) ?
SimpleMessageFormat.TEXT : SimpleMessageFormat.HTML;
} else {
mQuotedTextFormat = SimpleMessageFormat.HTML;
}
// TODO -- I am assuming that mSourceMessageBody will always be a text part. Is this a safe assumption?
// Handle the original message in the reply
// If we already have mSourceMessageBody, use that. It's pre-populated if we've got crypto going on.
String content = mSourceMessageBody != null
? mSourceMessageBody
: getBodyTextFromMessage(mSourceMessage, mMessageFormat);
if (mMessageFormat == MessageFormat.HTML) {
String content = (mSourceMessageBody != null) ?
mSourceMessageBody :
getBodyTextFromMessage(mSourceMessage, mQuotedTextFormat);
if (mQuotedTextFormat == SimpleMessageFormat.HTML) {
// Strip signature.
// closing tags such as </div>, </span>, </table>, </pre> will be cut off.
if (mAccount.isStripSignature() &&
@ -2786,20 +2884,25 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
Log.e(K9.LOG_TAG, "Problem cleaning quoted message.", ioe);
}
}
// Add the HTML reply header to the top of the content.
mQuotedHtmlContent = quoteOriginalHtmlMessage(mSourceMessage, content, mQuoteStyle);
// Load the message with the reply header.
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
mQuotedText.setText(quoteOriginalTextMessage(mSourceMessage,
getBodyTextFromMessage(mSourceMessage, MessageFormat.TEXT), mQuoteStyle));
} else if (mMessageFormat == MessageFormat.TEXT) {
// TODO: Also strip the signature from the text/plain part
mQuotedText.setText(quoteOriginalTextMessage(mSourceMessage,
getBodyTextFromMessage(mSourceMessage, SimpleMessageFormat.TEXT), mQuoteStyle));
} else if (mQuotedTextFormat == SimpleMessageFormat.TEXT) {
if (mAccount.isStripSignature() &&
(mAction == Action.REPLY || mAction == Action.REPLY_ALL)) {
if (DASH_SIGNATURE_PLAIN.matcher(content).find()) {
content = DASH_SIGNATURE_PLAIN.matcher(content).replaceFirst("\r\n");
}
}
mQuotedText.setText(quoteOriginalTextMessage(mSourceMessage, content, mQuoteStyle));
}
@ -2818,9 +2921,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
* @return Text in desired format.
* @throws MessagingException
*/
private String getBodyTextFromMessage(final Message message, final MessageFormat format) throws MessagingException {
private String getBodyTextFromMessage(final Message message, final SimpleMessageFormat format)
throws MessagingException {
Part part;
if (format == MessageFormat.HTML) {
if (format == SimpleMessageFormat.HTML) {
// HTML takes precedence, then text.
part = MimeUtility.findFirstPartByMimeType(message, "text/html");
if (part != null) {
@ -2835,7 +2939,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
Log.d(K9.LOG_TAG, "getBodyTextFromMessage: HTML requested, text found.");
return HtmlConverter.textToHtml(MimeUtility.getTextFromPart(part), true);
}
} else if (format == MessageFormat.TEXT) {
} else if (format == SimpleMessageFormat.TEXT) {
// Text takes precedence, then html.
part = MimeUtility.findFirstPartByMimeType(message, "text/plain");
if (part != null) {
@ -3025,6 +3129,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
showOrHideQuotedText(QuotedTextMode.HIDE);
Log.e(K9.LOG_TAG, "Could not re-process source message; deleting quoted text to be safe.", e);
}
updateMessageFormat();
} else {
processSourceMessage(message);
mSourceProcessed = true;
@ -3436,4 +3541,47 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private static String getIdentityDescription(Identity identity) {
return String.format("%s <%s>", identity.getName(), identity.getEmail());
}
private void setMessageFormat(SimpleMessageFormat format) {
// This method will later be used to enable/disable the rich text editing mode.
mMessageFormat = format;
}
private void updateMessageFormat() {
MessageFormat origMessageFormat = mAccount.getMessageFormat();
SimpleMessageFormat messageFormat;
if (origMessageFormat == MessageFormat.TEXT) {
// The user wants to send text/plain messages. We don't override that choice under
// any circumstances.
messageFormat = SimpleMessageFormat.TEXT;
} else if (mForcePlainText && includeQuotedText()) {
// Right now we send a text/plain-only message when the quoted text was edited, no
// matter what the user selected for the message format.
messageFormat = SimpleMessageFormat.TEXT;
} else if (mEncryptCheckbox.isChecked() || mCryptoSignatureCheckbox.isChecked()) {
// Right now we only support PGP inline which doesn't play well with HTML. So force
// plain text in those cases.
messageFormat = SimpleMessageFormat.TEXT;
} else if (origMessageFormat == MessageFormat.AUTO) {
if (mAction == Action.COMPOSE || mQuotedTextFormat == SimpleMessageFormat.TEXT ||
!includeQuotedText()) {
// If the message format is set to "AUTO" we use text/plain whenever possible. That
// is, when composing new messages and replying to or forwarding text/plain
// messages.
messageFormat = SimpleMessageFormat.TEXT;
} else {
messageFormat = SimpleMessageFormat.HTML;
}
} else {
// In all other cases use HTML
messageFormat = SimpleMessageFormat.HTML;
}
setMessageFormat(messageFormat);
}
private boolean includeQuotedText() {
return (mQuotedTextMode == QuotedTextMode.SHOW);
}
}