forked from I2P_Developers/i2p.i2p
SusiMail: Limit quoted-words to max line length
Change HeaderLine encoder to work on chars, not bytes, so multibyte chars aren't split across lines. Fix places where lines were one or two chars too long. More to do, as it isn't tokenizing.
This commit is contained in:
@ -39,6 +39,8 @@ import net.i2p.data.DataHelper;
|
|||||||
* Ref:
|
* Ref:
|
||||||
* http://en.wikipedia.org/wiki/MIME#Encoded-Word
|
* http://en.wikipedia.org/wiki/MIME#Encoded-Word
|
||||||
* http://tools.ietf.org/html/rfc2047
|
* http://tools.ietf.org/html/rfc2047
|
||||||
|
* https://jeffreystedfast.blogspot.com/2013/09/time-for-rant-on-mime-parsers.html
|
||||||
|
* https://jeffreystedfast.blogspot.com/2013/08/why-decoding-rfc2047-encoded-headers-is.html
|
||||||
*
|
*
|
||||||
* @author susi
|
* @author susi
|
||||||
*/
|
*/
|
||||||
@ -51,24 +53,36 @@ public class HeaderLine extends Encoding {
|
|||||||
|
|
||||||
private static final int BUFSIZE = 2;
|
private static final int BUFSIZE = 2;
|
||||||
|
|
||||||
public String encode( byte in[] ) throws EncodingException {
|
/**
|
||||||
|
* This will split multibyte chars across lines,
|
||||||
|
* see 4th ref above
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException always
|
||||||
|
*/
|
||||||
|
public String encode(byte in[]) throws EncodingException {
|
||||||
|
throw new UnsupportedOperationException("use encode(String)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String encode(String str) throws EncodingException {
|
||||||
StringBuilder out = new StringBuilder();
|
StringBuilder out = new StringBuilder();
|
||||||
int l = 0, buffered = 0, tmp[] = new int[BUFSIZE];
|
int l = 0, buffered = 0;
|
||||||
|
char tmp[] = new char[BUFSIZE];
|
||||||
boolean quoting = false;
|
boolean quoting = false;
|
||||||
boolean quote = false;
|
boolean quote = false;
|
||||||
boolean linebreak = false;
|
boolean linebreak = false;
|
||||||
StringBuilder quotedSequence = null;
|
StringBuilder quotedSequence = null;
|
||||||
int rest = in.length;
|
int rest = str.length();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while( true ) {
|
while( true ) {
|
||||||
while( rest > 0 && buffered < BUFSIZE ) {
|
while( rest > 0 && buffered < BUFSIZE ) {
|
||||||
tmp[buffered++] = in[index++];
|
tmp[buffered++] = str.charAt(index++);
|
||||||
rest--;
|
rest--;
|
||||||
}
|
}
|
||||||
if( rest == 0 && buffered == 0 )
|
if( rest == 0 && buffered == 0 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int c = tmp[0];
|
char c = tmp[0];
|
||||||
buffered--;
|
buffered--;
|
||||||
for( int j = 1; j < BUFSIZE; j++ )
|
for( int j = 1; j < BUFSIZE; j++ )
|
||||||
tmp[j-1] = tmp[j];
|
tmp[j-1] = tmp[j];
|
||||||
@ -92,23 +106,46 @@ public class HeaderLine extends Encoding {
|
|||||||
tmp[j-1] = tmp[j];
|
tmp[j-1] = tmp[j];
|
||||||
}
|
}
|
||||||
if( quote ) {
|
if( quote ) {
|
||||||
if( ! quoting ) {
|
// the encoded char
|
||||||
|
StringBuilder qc = new StringBuilder(16);
|
||||||
|
if (c <= 127) {
|
||||||
|
// single byte char
|
||||||
|
qc.append(HexTable.table[c]);
|
||||||
|
} else {
|
||||||
|
byte[] utf = DataHelper.getUTF8(String.valueOf(c));
|
||||||
|
for (int j = 0; j < utf.length; j++) {
|
||||||
|
int b = utf[j] & 0xff;
|
||||||
|
qc.append(HexTable.table[b]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (quoting) {
|
||||||
|
// would it be too long?
|
||||||
|
if (l + quotedSequence.length() + qc.length() + 2 >= 76) {
|
||||||
|
// close q-seq, wrap line, and start a new q-seq
|
||||||
|
out.append(quotedSequence);
|
||||||
|
out.append("?=\r\n\t");
|
||||||
|
l = 1;
|
||||||
|
quoting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!quoting) {
|
||||||
|
// close q-seq, wrap line, and start a new q-seq
|
||||||
quotedSequence = new StringBuilder(64);
|
quotedSequence = new StringBuilder(64);
|
||||||
quotedSequence.append("=?utf-8?Q?");
|
quotedSequence.append("=?utf-8?Q?");
|
||||||
quoting = true;
|
quoting = true;
|
||||||
}
|
}
|
||||||
quotedSequence.append(HexTable.table[ c < 0 ? 256 + c : c ]);
|
quotedSequence.append(qc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if( quoting ) {
|
if( quoting ) {
|
||||||
quotedSequence.append("?=");
|
quotedSequence.append("?=");
|
||||||
int sl = quotedSequence.length();
|
int sl = quotedSequence.length();
|
||||||
if( l + sl > 76 ) {
|
if( l + sl >= 76 ) {
|
||||||
/*
|
/*
|
||||||
* wrap line
|
* wrap line
|
||||||
*/
|
*/
|
||||||
out.append( "\r\n\t" );
|
out.append( "\r\n\t" );
|
||||||
l = 0;
|
l = 1;
|
||||||
}
|
}
|
||||||
out.append( quotedSequence );
|
out.append( quotedSequence );
|
||||||
l += sl;
|
l += sl;
|
||||||
@ -120,11 +157,11 @@ public class HeaderLine extends Encoding {
|
|||||||
l = 0;
|
l = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if( l > 76 ) {
|
if( l >= 76 ) {
|
||||||
out.append( "\r\n\t" );
|
out.append( "\r\n\t" );
|
||||||
l = 0;
|
l = 1;
|
||||||
}
|
}
|
||||||
out.append( (char)c );
|
out.append(c);
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,12 +169,12 @@ public class HeaderLine extends Encoding {
|
|||||||
if( quoting ) {
|
if( quoting ) {
|
||||||
quotedSequence.append("?=");
|
quotedSequence.append("?=");
|
||||||
int sl = quotedSequence.length();
|
int sl = quotedSequence.length();
|
||||||
if( l + sl > 76 ) {
|
if( l + sl >= 76 ) {
|
||||||
/*
|
/*
|
||||||
* wrap line
|
* wrap line
|
||||||
*/
|
*/
|
||||||
out.append( "\r\n\t" );
|
out.append( "\r\n\t" );
|
||||||
l = 0;
|
l = 1;
|
||||||
}
|
}
|
||||||
out.append( quotedSequence );
|
out.append( quotedSequence );
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user