mirror of
https://github.com/moparisthebest/k-9
synced 2025-01-30 23:00:09 -05:00
Replaced base64 as default encoding for text bodies with quoted-printable. Please use issue 1176 for discussion.
This commit is contained in:
parent
14ee970b18
commit
c64c0a1c30
@ -87,11 +87,7 @@ public class MimeBodyPart extends BodyPart
|
||||
contentType += String.format(";\n name=\"%s\"", name);
|
||||
}
|
||||
setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType);
|
||||
//TODO: Use quoted-printable
|
||||
//using org.apache.commons.codec.net.QuotedPrintableCodec
|
||||
//when it will implement all rules (missing #3, $4 & #5) of the RFC
|
||||
//http://www.ietf.org/rfc/rfc1521.txt
|
||||
setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
|
||||
setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "quoted-printable");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +379,7 @@ public class MimeMessage extends Message
|
||||
{
|
||||
setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n charset=utf-8",
|
||||
getMimeType()));
|
||||
setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
|
||||
setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "quoted-printable");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
|
||||
package com.fsck.k9.mail.internet;
|
||||
|
||||
import com.fsck.k9.codec.binary.Base64;
|
||||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.james.mime4j.codec.QuotedPrintableOutputStream;
|
||||
|
||||
public class TextBody implements Body
|
||||
{
|
||||
private String mBody;
|
||||
@ -28,7 +29,9 @@ public class TextBody implements Body
|
||||
}
|
||||
else
|
||||
{
|
||||
out.write(Base64.encodeBase64Chunked(bytes));
|
||||
QuotedPrintableOutputStream qp = new QuotedPrintableOutputStream(out, false);
|
||||
qp.write(bytes);
|
||||
qp.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
269
src/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java
Normal file
269
src/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java
Normal file
@ -0,0 +1,269 @@
|
||||
/****************************************************************
|
||||
* Licensed to the Apache Software Foundation (ASF) under one *
|
||||
* or more contributor license agreements. See the NOTICE file *
|
||||
* distributed with this work for additional information *
|
||||
* regarding copyright ownership. The ASF licenses this file *
|
||||
* to you under the Apache License, Version 2.0 (the *
|
||||
* "License"); you may not use this file except in compliance *
|
||||
* with the License. You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, *
|
||||
* software distributed under the License is distributed on an *
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
|
||||
* KIND, either express or implied. See the License for the *
|
||||
* specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
****************************************************************/
|
||||
|
||||
package org.apache.james.mime4j.codec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
final class QuotedPrintableEncoder
|
||||
{
|
||||
private static final byte TAB = 0x09;
|
||||
private static final byte SPACE = 0x20;
|
||||
private static final byte EQUALS = 0x3D;
|
||||
private static final byte CR = 0x0D;
|
||||
private static final byte LF = 0x0A;
|
||||
private static final byte QUOTED_PRINTABLE_LAST_PLAIN = 0x7E;
|
||||
private static final int QUOTED_PRINTABLE_MAX_LINE_LENGTH = 76;
|
||||
private static final int QUOTED_PRINTABLE_OCTETS_PER_ESCAPE = 3;
|
||||
private static final byte[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
private final byte[] inBuffer;
|
||||
private final byte[] outBuffer;
|
||||
private final boolean binary;
|
||||
|
||||
private boolean pendingSpace;
|
||||
private boolean pendingTab;
|
||||
private boolean pendingCR;
|
||||
private int nextSoftBreak;
|
||||
private int outputIndex;
|
||||
private OutputStream out;
|
||||
|
||||
public QuotedPrintableEncoder(int bufferSize, boolean binary)
|
||||
{
|
||||
inBuffer = new byte[bufferSize];
|
||||
outBuffer = new byte[3 * bufferSize];
|
||||
outputIndex = 0;
|
||||
nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
|
||||
out = null;
|
||||
this.binary = binary;
|
||||
pendingSpace = false;
|
||||
pendingTab = false;
|
||||
pendingCR = false;
|
||||
}
|
||||
|
||||
void initEncoding(final OutputStream out)
|
||||
{
|
||||
this.out = out;
|
||||
pendingSpace = false;
|
||||
pendingTab = false;
|
||||
pendingCR = false;
|
||||
nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
|
||||
}
|
||||
|
||||
void encodeChunk(byte[] buffer, int off, int len) throws IOException
|
||||
{
|
||||
for (int inputIndex = off; inputIndex < len + off; inputIndex++)
|
||||
{
|
||||
encode(buffer[inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
void completeEncoding() throws IOException
|
||||
{
|
||||
writePending();
|
||||
flushOutput();
|
||||
}
|
||||
|
||||
public void encode(final InputStream in, final OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
initEncoding(out);
|
||||
int inputLength;
|
||||
while ((inputLength = in.read(inBuffer)) > -1)
|
||||
{
|
||||
encodeChunk(inBuffer, 0, inputLength);
|
||||
}
|
||||
completeEncoding();
|
||||
}
|
||||
|
||||
private void writePending() throws IOException
|
||||
{
|
||||
if (pendingSpace)
|
||||
{
|
||||
plain(SPACE);
|
||||
}
|
||||
else if (pendingTab)
|
||||
{
|
||||
plain(TAB);
|
||||
}
|
||||
else if (pendingCR)
|
||||
{
|
||||
plain(CR);
|
||||
}
|
||||
clearPending();
|
||||
}
|
||||
|
||||
private void clearPending() throws IOException
|
||||
{
|
||||
pendingSpace = false;
|
||||
pendingTab = false;
|
||||
pendingCR = false;
|
||||
}
|
||||
|
||||
private void encode(byte next) throws IOException
|
||||
{
|
||||
if (next == LF)
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
writePending();
|
||||
escape(next);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pendingCR)
|
||||
{
|
||||
// Expect either space or tab pending
|
||||
// but not both
|
||||
if (pendingSpace)
|
||||
{
|
||||
escape(SPACE);
|
||||
}
|
||||
else if (pendingTab)
|
||||
{
|
||||
escape(TAB);
|
||||
}
|
||||
lineBreak();
|
||||
clearPending();
|
||||
}
|
||||
else
|
||||
{
|
||||
writePending();
|
||||
plain(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (next == CR)
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
escape(next);
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingCR = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writePending();
|
||||
if (next == SPACE)
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
escape(next);
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingSpace = true;
|
||||
}
|
||||
}
|
||||
else if (next == TAB)
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
escape(next);
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingTab = true;
|
||||
}
|
||||
}
|
||||
else if (next < SPACE)
|
||||
{
|
||||
escape(next);
|
||||
}
|
||||
else if (next > QUOTED_PRINTABLE_LAST_PLAIN)
|
||||
{
|
||||
escape(next);
|
||||
}
|
||||
else if (next == EQUALS)
|
||||
{
|
||||
escape(next);
|
||||
}
|
||||
else
|
||||
{
|
||||
plain(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void plain(byte next) throws IOException
|
||||
{
|
||||
if (--nextSoftBreak <= 1)
|
||||
{
|
||||
softBreak();
|
||||
}
|
||||
write(next);
|
||||
}
|
||||
|
||||
private void escape(byte next) throws IOException
|
||||
{
|
||||
if (--nextSoftBreak <= QUOTED_PRINTABLE_OCTETS_PER_ESCAPE)
|
||||
{
|
||||
softBreak();
|
||||
}
|
||||
|
||||
int nextUnsigned = next & 0xff;
|
||||
|
||||
write(EQUALS);
|
||||
--nextSoftBreak;
|
||||
write(HEX_DIGITS[nextUnsigned >> 4]);
|
||||
--nextSoftBreak;
|
||||
write(HEX_DIGITS[nextUnsigned % 0x10]);
|
||||
}
|
||||
|
||||
private void write(byte next) throws IOException
|
||||
{
|
||||
outBuffer[outputIndex++] = next;
|
||||
if (outputIndex >= outBuffer.length)
|
||||
{
|
||||
flushOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private void softBreak() throws IOException
|
||||
{
|
||||
write(EQUALS);
|
||||
lineBreak();
|
||||
}
|
||||
|
||||
private void lineBreak() throws IOException
|
||||
{
|
||||
write(CR);
|
||||
write(LF);
|
||||
nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH;
|
||||
}
|
||||
|
||||
void flushOutput() throws IOException
|
||||
{
|
||||
if (outputIndex < outBuffer.length)
|
||||
{
|
||||
out.write(outBuffer, 0, outputIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.write(outBuffer);
|
||||
}
|
||||
outputIndex = 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/****************************************************************
|
||||
* Licensed to the Apache Software Foundation (ASF) under one *
|
||||
* or more contributor license agreements. See the NOTICE file *
|
||||
* distributed with this work for additional information *
|
||||
* regarding copyright ownership. The ASF licenses this file *
|
||||
* to you under the Apache License, Version 2.0 (the *
|
||||
* "License"); you may not use this file except in compliance *
|
||||
* with the License. You may obtain a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, *
|
||||
* software distributed under the License is distributed on an *
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
|
||||
* KIND, either express or implied. See the License for the *
|
||||
* specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
****************************************************************/
|
||||
|
||||
package org.apache.james.mime4j.codec;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Performs Quoted-Printable encoding on an underlying stream.
|
||||
*/
|
||||
public class QuotedPrintableOutputStream extends FilterOutputStream
|
||||
{
|
||||
|
||||
private static final int DEFAULT_ENCODING_BUFFER_SIZE = 1024;
|
||||
|
||||
private QuotedPrintableEncoder encoder;
|
||||
private boolean closed = false;
|
||||
|
||||
public QuotedPrintableOutputStream(OutputStream out, boolean binary)
|
||||
{
|
||||
super(out);
|
||||
encoder = new QuotedPrintableEncoder(DEFAULT_ENCODING_BUFFER_SIZE, binary);
|
||||
encoder.initEncoding(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
encoder.completeEncoding();
|
||||
// do not close the wrapped stream
|
||||
}
|
||||
finally
|
||||
{
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
encoder.flushOutput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException
|
||||
{
|
||||
this.write(new byte[] { (byte) b }, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
throw new IOException("QuotedPrintableOutputStream has been closed");
|
||||
}
|
||||
|
||||
encoder.encodeChunk(b, off, len);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user