Merge pull request #4980 from k9mail/remove_message_charset

Clean up creating messages
This commit is contained in:
cketti 2020-10-06 15:29:54 +02:00 committed by GitHub
commit b2e8e4b8b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 27 additions and 103 deletions

View file

@ -157,8 +157,6 @@ public abstract class Message implements Part, Body {
@Override @Override
public abstract void setEncoding(String encoding) throws MessagingException; public abstract void setEncoding(String encoding) throws MessagingException;
public abstract void setCharset(String charset) throws MessagingException;
public long calculateSize() { public long calculateSize() {
try { try {

View file

@ -7,9 +7,6 @@ import java.util.List;
import org.apache.james.mime4j.util.MimeUtil; import org.apache.james.mime4j.util.MimeUtil;
import com.fsck.k9.mail.internet.CharsetSupport;
import com.fsck.k9.mail.internet.TextBody;
public abstract class Multipart implements Body { public abstract class Multipart implements Body {
private Part mParent; private Part mParent;
@ -54,18 +51,6 @@ public abstract class Multipart implements Body {
/* Nothing else to do. Each subpart has its own separate encoding */ /* Nothing else to do. Each subpart has its own separate encoding */
} }
public void setCharset(String charset) throws MessagingException {
if (mParts.isEmpty())
return;
BodyPart part = mParts.get(0);
Body body = part.getBody();
if (body instanceof TextBody) {
CharsetSupport.setCharset(charset, part);
((TextBody)body).setCharset(charset);
}
}
public abstract byte[] getPreamble(); public abstract byte[] getPreamble();
public abstract byte[] getEpilogue(); public abstract byte[] getEpilogue();
} }

View file

@ -30,19 +30,6 @@ public class CharsetSupport {
}; };
public static void setCharset(String charset, Part part) {
part.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
part.getMimeType() + ";\r\n charset=" + getExternalCharset(charset));
}
static String getExternalCharset(String charset) {
if (JisSupport.isShiftJis(charset)) {
return SHIFT_JIS;
} else {
return charset;
}
}
static String fixupCharset(String charset, Message message) throws MessagingException { static String fixupCharset(String charset, Message message) throws MessagingException {
if (charset == null || "0".equals(charset)) if (charset == null || "0".equals(charset))
charset = "US-ASCII"; // No encoding, so use us-ascii, which is the standard. charset = "US-ASCII"; // No encoding, so use us-ascii, which is the standard.

View file

@ -12,9 +12,7 @@ import org.apache.james.mime4j.Charsets;
* as defined in <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC 2047</a> * as defined in <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC 2047</a>
* or display-names of an e-mail address, for example. * or display-names of an e-mail address, for example.
* *
* This class is copied from the org.apache.james.mime4j.decoder.EncoderUtil class. It's modified here in order to * This class is copied from the org.apache.james.mime4j.decoder.EncoderUtil class.
* encode emoji characters in the Subject headers. The method to decode emoji depends on the MimeMessage class because
* it has to be determined with the sender address.
*/ */
class EncoderUtil { class EncoderUtil {
private static final BitSet Q_RESTRICTED_CHARS = initChars("=_?\"#$%&'(),.:;<>@[\\]^`{|}~"); private static final BitSet Q_RESTRICTED_CHARS = initChars("=_?\"#$%&'(),.:;<>@[\\]^`{|}~");
@ -54,21 +52,15 @@ class EncoderUtil {
* *
* @param text * @param text
* text to encode. * text to encode.
* @param charset
* the Java charset that should be used to encode the specified
* string into a byte array. A suitable charset is detected
* automatically if this parameter is <code>null</code>.
* @return the encoded word (or sequence of encoded words if the given text * @return the encoded word (or sequence of encoded words if the given text
* does not fit in a single encoded word). * does not fit in a single encoded word).
*/ */
public static String encodeEncodedWord(String text, Charset charset) { public static String encodeEncodedWord(String text) {
if (text == null) if (text == null)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (charset == null) Charset charset = determineCharset(text);
charset = determineCharset(text); String mimeCharset = charset.name();
String mimeCharset = CharsetSupport.getExternalCharset(charset.name());
byte[] bytes = encode(text, charset); byte[] bytes = encode(text, charset);
@ -164,20 +156,14 @@ class EncoderUtil {
} }
private static Charset determineCharset(String text) { private static Charset determineCharset(String text) {
// it is an important property of iso-8859-1 that it directly maps
// unicode code points 0000 to 00ff to byte values 00 to ff.
boolean ascii = true;
final int len = text.length(); final int len = text.length();
for (int index = 0; index < len; index++) { for (int index = 0; index < len; index++) {
char ch = text.charAt(index); char ch = text.charAt(index);
if (ch > 0xff) { if (ch > 0x7f) {
return Charsets.UTF_8; return Charsets.UTF_8;
} }
if (ch > 0x7f) {
ascii = false;
} }
} return Charsets.US_ASCII;
return ascii ? Charsets.US_ASCII : Charsets.ISO_8859_1;
} }
private static Encoding determineEncoding(byte[] bytes) { private static Encoding determineEncoding(byte[] bytes) {

View file

@ -4,13 +4,11 @@ import com.fsck.k9.mail.internet.MimeHeader.Field.NameValueField
import com.fsck.k9.mail.internet.MimeHeader.Field.RawField import com.fsck.k9.mail.internet.MimeHeader.Field.RawField
import java.io.IOException import java.io.IOException
import java.io.OutputStream import java.io.OutputStream
import java.nio.charset.Charset
import java.util.ArrayList import java.util.ArrayList
import java.util.LinkedHashSet import java.util.LinkedHashSet
class MimeHeader { class MimeHeader {
private val fields: MutableList<Field> = ArrayList() private val fields: MutableList<Field> = ArrayList()
private var charset: String? = null
val headerNames: Set<String> val headerNames: Set<String>
get() = fields.mapTo(LinkedHashSet()) { it.name } get() = fields.mapTo(LinkedHashSet()) { it.name }
@ -76,8 +74,7 @@ class MimeHeader {
private fun Appendable.appendNameValueField(field: Field) { private fun Appendable.appendNameValueField(field: Field) {
val value = field.value val value = field.value
val encodedValue = if (hasToBeEncoded(value)) { val encodedValue = if (hasToBeEncoded(value)) {
val charset = this@MimeHeader.charset?.let { Charset.forName(it) } EncoderUtil.encodeEncodedWord(value)
EncoderUtil.encodeEncodedWord(value, charset)
} else { } else {
value value
} }
@ -92,10 +89,6 @@ class MimeHeader {
return text.any { !it.isVChar() && !it.isWspOrCrlf() } return text.any { !it.isVChar() && !it.isWspOrCrlf() }
} }
fun setCharset(charset: String?) {
this.charset = charset
}
companion object { companion object {
const val SUBJECT = "Subject" const val SUBJECT = "Subject"
const val HEADER_CONTENT_TYPE = "Content-Type" const val HEADER_CONTENT_TYPE = "Content-Type"

View file

@ -466,17 +466,6 @@ public class MimeMessage extends Message {
setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, encoding); setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, encoding);
} }
@Override
public void setCharset(String charset) throws MessagingException {
mHeader.setCharset(charset);
if (mBody instanceof Multipart) {
((Multipart)mBody).setCharset(charset);
} else if (mBody instanceof TextBody) {
CharsetSupport.setCharset(charset, this);
((TextBody)mBody).setCharset(charset);
}
}
private class MimeMessageBuilder implements ContentHandler { private class MimeMessageBuilder implements ContentHandler {
private final LinkedList<Object> stack = new LinkedList<>(); private final LinkedList<Object> stack = new LinkedList<>();
private final BodyFactory bodyFactory; private final BodyFactory bodyFactory;

View file

@ -6,7 +6,6 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -14,9 +13,10 @@ import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.filter.CountingOutputStream; import com.fsck.k9.mail.filter.CountingOutputStream;
import com.fsck.k9.mail.filter.SignSafeOutputStream; import com.fsck.k9.mail.filter.SignSafeOutputStream;
import org.apache.james.mime4j.Charsets;
import org.apache.james.mime4j.codec.QuotedPrintableOutputStream; import org.apache.james.mime4j.codec.QuotedPrintableOutputStream;
import org.apache.james.mime4j.util.MimeUtil; import org.apache.james.mime4j.util.MimeUtil;
import timber.log.Timber;
public class TextBody implements Body, SizeAware { public class TextBody implements Body, SizeAware {
@ -25,7 +25,6 @@ public class TextBody implements Body, SizeAware {
private final String text; private final String text;
private String encoding; private String encoding;
private String charset = "UTF-8";
// Length of the message composed (as opposed to quoted). I don't like the name of this variable and am open to // Length of the message composed (as opposed to quoted). I don't like the name of this variable and am open to
// suggestions as to what it should otherwise be. -achen 20101207 // suggestions as to what it should otherwise be. -achen 20101207
@Nullable @Nullable
@ -41,7 +40,7 @@ public class TextBody implements Body, SizeAware {
@Override @Override
public void writeTo(OutputStream out) throws IOException, MessagingException { public void writeTo(OutputStream out) throws IOException, MessagingException {
if (text != null) { if (text != null) {
byte[] bytes = text.getBytes(charset); byte[] bytes = text.getBytes(Charsets.UTF_8);
if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) { if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) {
writeSignSafeQuotedPrintable(out, bytes); writeSignSafeQuotedPrintable(out, bytes);
} else if (MimeUtil.ENC_8BIT.equalsIgnoreCase(encoding)) { } else if (MimeUtil.ENC_8BIT.equalsIgnoreCase(encoding)) {
@ -58,18 +57,13 @@ public class TextBody implements Body, SizeAware {
@Override @Override
public InputStream getInputStream() throws MessagingException { public InputStream getInputStream() throws MessagingException {
try {
byte[] b; byte[] b;
if (text != null) { if (text != null) {
b = text.getBytes(charset); b = text.getBytes(Charsets.UTF_8);
} else { } else {
b = EMPTY_BYTE_ARRAY; b = EMPTY_BYTE_ARRAY;
} }
return new ByteArrayInputStream(b); return new ByteArrayInputStream(b);
} catch (UnsupportedEncodingException uee) {
Timber.e(uee, "Unsupported charset: %s", charset);
return null;
}
} }
@Override @Override
@ -83,10 +77,6 @@ public class TextBody implements Body, SizeAware {
this.encoding = encoding; this.encoding = encoding;
} }
public void setCharset(String charset) {
this.charset = charset;
}
@Nullable @Nullable
public Integer getComposedMessageLength() { public Integer getComposedMessageLength() {
return composedMessageLength; return composedMessageLength;
@ -108,7 +98,7 @@ public class TextBody implements Body, SizeAware {
@Override @Override
public long getSize() { public long getSize() {
try { try {
byte[] bytes = text.getBytes(charset); byte[] bytes = text.getBytes(Charsets.UTF_8);
if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) { if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) {
return getLengthWhenQuotedPrintableEncoded(bytes); return getLengthWhenQuotedPrintableEncoded(bytes);

View file

@ -2,7 +2,6 @@ package com.fsck.k9.mail
import com.fsck.k9.mail.internet.BinaryTempFileBody import com.fsck.k9.mail.internet.BinaryTempFileBody
import com.fsck.k9.mail.internet.BinaryTempFileMessageBody import com.fsck.k9.mail.internet.BinaryTempFileMessageBody
import com.fsck.k9.mail.internet.CharsetSupport
import com.fsck.k9.mail.internet.MimeBodyPart import com.fsck.k9.mail.internet.MimeBodyPart
import com.fsck.k9.mail.internet.MimeHeader import com.fsck.k9.mail.internet.MimeHeader
import com.fsck.k9.mail.internet.MimeMessage import com.fsck.k9.mail.internet.MimeMessage
@ -78,9 +77,9 @@ class MessageTest {
Content-Transfer-Encoding: 7bit Content-Transfer-Encoding: 7bit
------Boundary103 ------Boundary103
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; Content-Type: text/plain;
charset=utf-8 charset=utf-8
Content-Transfer-Encoding: quoted-printable
Testing=2E Testing=2E
This is a text body with some greek characters=2E This is a text body with some greek characters=2E
@ -108,9 +107,9 @@ class MessageTest {
Content-Transfer-Encoding: 7bit Content-Transfer-Encoding: 7bit
------Boundary102 ------Boundary102
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; Content-Type: text/plain;
charset=utf-8 charset=utf-8
Content-Transfer-Encoding: quoted-printable
Testing=2E Testing=2E
This is a text body with some greek characters=2E This is a text body with some greek characters=2E
@ -138,9 +137,9 @@ class MessageTest {
Content-Transfer-Encoding: 7bit Content-Transfer-Encoding: 7bit
------Boundary101 ------Boundary101
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; Content-Type: text/plain;
charset=utf-8 charset=utf-8
Content-Transfer-Encoding: quoted-printable
Testing=2E Testing=2E
This is a text body with some greek characters=2E This is a text body with some greek characters=2E
@ -177,9 +176,9 @@ class MessageTest {
Content-Transfer-Encoding: 7bit Content-Transfer-Encoding: 7bit
------Boundary103 ------Boundary103
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; Content-Type: text/plain;
charset=utf-8 charset=utf-8
Content-Transfer-Encoding: quoted-printable
Testing=2E Testing=2E
This is a text body with some greek characters=2E This is a text body with some greek characters=2E
@ -207,9 +206,9 @@ class MessageTest {
Content-Transfer-Encoding: 7bit Content-Transfer-Encoding: 7bit
------Boundary102 ------Boundary102
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; Content-Type: text/plain;
charset=utf-8 charset=utf-8
Content-Transfer-Encoding: quoted-printable
Testing=2E Testing=2E
This is a text body with some greek characters=2E This is a text body with some greek characters=2E
@ -237,9 +236,9 @@ class MessageTest {
Content-Transfer-Encoding: 7bit Content-Transfer-Encoding: 7bit
------Boundary101 ------Boundary101
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; Content-Type: text/plain;
charset=utf-8 charset=utf-8
Content-Transfer-Encoding: quoted-printable
Testing=2E Testing=2E
This is a text body with some greek characters=2E This is a text body with some greek characters=2E
@ -315,13 +314,10 @@ class MessageTest {
End of test. End of test.
""".trimIndent().crlf() """.trimIndent().crlf()
).apply { )
setCharset("utf-8")
}
return MimeBodyPart().apply { return MimeBodyPart().apply {
MimeMessageHelper.setBody(this, textBody) MimeMessageHelper.setBody(this, textBody)
CharsetSupport.setCharset("utf-8", this)
} }
} }

View file

@ -6,12 +6,12 @@ import org.junit.Test
class EncoderUtilTest { class EncoderUtilTest {
@Test @Test
fun singleNonAsciiCharacter() { fun singleNonAsciiCharacter() {
assertInputEncodesToExpected("123456789Ä", "=?ISO-8859-1?Q?123456789=C4?=") assertInputEncodesToExpected("123456789Ä", "=?UTF-8?Q?123456789=C3=84?=")
} }
@Test @Test
fun onlyNonAsciiCharacters() { fun onlyNonAsciiCharacters() {
assertInputEncodesToExpected("ÄÖÜÄÖÜÄÖÜÄ", "=?ISO-8859-1?B?xNbcxNbcxNbcxA==?=") assertInputEncodesToExpected("ÄÖÜÄÖÜÄÖÜÄ", "=?UTF-8?B?w4TDlsOcw4TDlsOcw4TDlsOcw4Q=?=")
} }
@Test @Test
@ -27,7 +27,7 @@ class EncoderUtilTest {
} }
private fun assertInputEncodesToExpected(input: String, expected: String) { private fun assertInputEncodesToExpected(input: String, expected: String) {
val encodedText = EncoderUtil.encodeEncodedWord(input, null) val encodedText = EncoderUtil.encodeEncodedWord(input)
assertEquals(expected, encodedText) assertEquals(expected, encodedText)
} }
} }