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:
zzz
2017-12-23 18:49:48 +00:00
parent bf193b3218
commit 1e30efdb0d

View File

@ -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 );
} }