forked from I2P_Developers/i2p.i2p
SusiMail: Recheck max size if server reports less than default
- More javadocs and cleanups
This commit is contained in:
@@ -94,17 +94,18 @@ class MailPart {
|
||||
|
||||
for( int i = 0; i < headerLines.length; i++ )
|
||||
{
|
||||
if( headerLines[i].toLowerCase(Locale.US).startsWith( "content-transfer-encoding: " ) ) {
|
||||
String hlc = headerLines[i].toLowerCase(Locale.US);
|
||||
if( hlc.startsWith( "content-transfer-encoding: " ) ) {
|
||||
x_encoding = getFirstAttribute( headerLines[i] ).toLowerCase(Locale.US);
|
||||
}
|
||||
else if( headerLines[i].toLowerCase(Locale.US).startsWith( "content-disposition: " ) ) {
|
||||
else if( hlc.startsWith( "content-disposition: " ) ) {
|
||||
x_disposition = getFirstAttribute( headerLines[i] ).toLowerCase(Locale.US);
|
||||
String str;
|
||||
str = getHeaderLineAttribute( headerLines[i], "filename" );
|
||||
if( str != null )
|
||||
x_name = str;
|
||||
}
|
||||
else if( headerLines[i].toLowerCase(Locale.US).startsWith( "content-type: " ) ) {
|
||||
else if( hlc.startsWith( "content-type: " ) ) {
|
||||
x_type = getFirstAttribute( headerLines[i] ).toLowerCase(Locale.US);
|
||||
/*
|
||||
* extract boundary, name and charset from content type
|
||||
@@ -124,10 +125,10 @@ class MailPart {
|
||||
if( str != null )
|
||||
x_charset = str.toUpperCase(Locale.US);
|
||||
}
|
||||
else if( headerLines[i].toLowerCase(Locale.US).startsWith( "content-description: " ) ) {
|
||||
else if( hlc.startsWith( "content-description: " ) ) {
|
||||
x_description = getFirstAttribute( headerLines[i] );
|
||||
}
|
||||
else if( headerLines[i].toLowerCase(Locale.US).startsWith( "mime-version: " ) ) {
|
||||
else if( hlc.startsWith( "mime-version: " ) ) {
|
||||
x_version = getFirstAttribute( headerLines[i] );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,16 +31,11 @@ import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* @author susi
|
||||
*/
|
||||
public class Base64 extends Encoding {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi23.util.Encoding#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return "base64";
|
||||
}
|
||||
@@ -166,9 +161,6 @@ public class Base64 extends Encoding {
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Base64#decode(String)
|
||||
*/
|
||||
public ReadBuffer decode(byte[] in, int offset, int length) throws DecodingException {
|
||||
byte out[] = new byte[length * 3 / 4 + 1 ];
|
||||
int written = 0;
|
||||
@@ -197,7 +189,7 @@ public class Base64 extends Encoding {
|
||||
length -= 4;
|
||||
}
|
||||
else {
|
||||
System.err.println( "" );
|
||||
//System.err.println( "" );
|
||||
throw new DecodingException( "Decoding base64 failed (trailing garbage)." );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,30 +25,32 @@ package i2p.susi.webmail.encoding;
|
||||
|
||||
import i2p.susi.util.ReadBuffer;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* Decode only. See encode().
|
||||
* @author susi
|
||||
*/
|
||||
public class EightBit extends Encoding {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return "8bit";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#encode(byte[])
|
||||
/**
|
||||
* TODO would be nice to implement this, as it is supported on the project server,
|
||||
* but content must be CRLF terminated with a max of 998 chars per line.
|
||||
* And you can't have leading dots either, we'd have to prevent or double-dot it.
|
||||
* That would be expensive to check, using either a double read or
|
||||
* pulling it all into memory.
|
||||
* So it's prohibitive for attachments. We could do it for the message body,
|
||||
* since it's in memory already, but that's not much of a win.
|
||||
* ref: https://stackoverflow.com/questions/29510178/how-to-handle-1000-character-lines-in-8bit-mime
|
||||
*
|
||||
* @throws EncodingException always
|
||||
*/
|
||||
public String encode(byte[] in) throws EncodingException {
|
||||
throw new EncodingException("unsupported");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#decode(byte[], int, int)
|
||||
*/
|
||||
public ReadBuffer decode(byte[] in, int offset, int length)
|
||||
throws DecodingException {
|
||||
return new ReadBuffer(in, offset, length);
|
||||
|
||||
@@ -42,7 +42,12 @@ public abstract class Encoding {
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Encode a byte array to a ASCII or ISO-8859-1 String
|
||||
* Encode a byte array to a ASCII or ISO-8859-1 String.
|
||||
* Output must be SMTP-safe: Line length of 998 or less,
|
||||
* using SMTP-safe characters,
|
||||
* followed by \r\n, and must not start with a '.'
|
||||
* unless escaped by a 2nd dot.
|
||||
* For some encodings, max line length is 76.
|
||||
*
|
||||
* @param in
|
||||
* @return Encoded string.
|
||||
@@ -51,7 +56,12 @@ public abstract class Encoding {
|
||||
public abstract String encode( byte in[] ) throws EncodingException;
|
||||
|
||||
/**
|
||||
* Encode a (UTF-8) String to a ASCII or ISO-8859-1 String
|
||||
* Encode a (UTF-8) String to a ASCII or ISO-8859-1 String.
|
||||
* Output must be SMTP-safe: Line length of 998 or less,
|
||||
* using SMTP-safe characters,
|
||||
* followed by \r\n, and must not start with a '.'
|
||||
* unless escaped by a 2nd dot.
|
||||
* For some encodings, max line length is 76.
|
||||
*
|
||||
* This implementation just converts the string to a byte array
|
||||
* and then calls encode(byte[]).
|
||||
@@ -67,6 +77,13 @@ public abstract class Encoding {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an input stream of bytes to a ASCII or ISO-8859-1 String.
|
||||
* Output must be SMTP-safe: Line length of 998 or less,
|
||||
* using SMTP-safe characters,
|
||||
* followed by \r\n, and must not start with a '.'
|
||||
* unless escaped by a 2nd dot.
|
||||
* For some encodings, max line length is 76.
|
||||
*
|
||||
* This implementation just reads the whole stream into memory
|
||||
* and then calls encode(byte[]).
|
||||
* Subclasses should implement a more memory-efficient method
|
||||
|
||||
@@ -30,23 +30,14 @@ import i2p.susi.util.ReadBuffer;
|
||||
*/
|
||||
public class HTML extends Encoding {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return "HTML";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#encode(byte[])
|
||||
*/
|
||||
public String encode(byte[] in) throws EncodingException {
|
||||
throw new EncodingException("unsupported");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#encode(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String encode(String str) throws EncodingException
|
||||
{
|
||||
@@ -56,9 +47,6 @@ public class HTML extends Encoding {
|
||||
.replaceAll( "\r{0,1}\n", "<br>\r\n" );
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#decode(byte[], int, int)
|
||||
*/
|
||||
public ReadBuffer decode(byte[] in, int offset, int length)
|
||||
throws DecodingException {
|
||||
throw new DecodingException("unsupported");
|
||||
|
||||
@@ -44,17 +44,13 @@ import net.i2p.data.DataHelper;
|
||||
*/
|
||||
public class HeaderLine extends Encoding {
|
||||
public static final String NAME = "HEADERLINE";
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#getName()
|
||||
*/
|
||||
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
private static final int BUFSIZE = 2;
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#encode(byte[])
|
||||
*/
|
||||
|
||||
public String encode( byte in[] ) throws EncodingException {
|
||||
StringBuilder out = new StringBuilder();
|
||||
int l = 0, buffered = 0, tmp[] = new int[BUFSIZE];
|
||||
@@ -148,9 +144,6 @@ public class HeaderLine extends Encoding {
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#decode(java.lang.String)
|
||||
*/
|
||||
public ReadBuffer decode( byte in[], int offset, int length ) throws DecodingException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
|
||||
int written = 0;
|
||||
|
||||
@@ -32,26 +32,18 @@ import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* ref: https://en.wikipedia.org/wiki/Quoted-printable
|
||||
* @author susi
|
||||
*/
|
||||
public class QuotedPrintable extends Encoding {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return "quoted-printable";
|
||||
}
|
||||
|
||||
private static int BUFSIZE = 2;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#encode(byte[])
|
||||
*/
|
||||
public String encode( byte in[] ) throws EncodingException {
|
||||
try {
|
||||
StringWriter strBuf = new StringWriter();
|
||||
@@ -142,9 +134,6 @@ public class QuotedPrintable extends Encoding {
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi.webmail.encoding.Encoding#decode(byte[], int, int)
|
||||
*/
|
||||
public ReadBuffer decode(byte[] in, int offset, int length) {
|
||||
byte[] out = new byte[length];
|
||||
int written = 0;
|
||||
|
||||
@@ -25,29 +25,25 @@ package i2p.susi.webmail.encoding;
|
||||
|
||||
import i2p.susi.util.ReadBuffer;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* Decode only.
|
||||
* @author susi
|
||||
*/
|
||||
public class SevenBit extends Encoding {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi23.mail.encoding.Encoding#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return "7bit";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi23.mail.encoding.Encoding#encode(byte[])
|
||||
/**
|
||||
* @throws EncodingException always
|
||||
*/
|
||||
public String encode(byte[] in) throws EncodingException {
|
||||
throw new EncodingException("unsupported");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see i2p.susi23.mail.encoding.Encoding#decode(byte[], int, int)
|
||||
/**
|
||||
* @throws DecodingException on illegal characters
|
||||
*/
|
||||
public ReadBuffer decode(byte[] in, int offset, int length)
|
||||
throws DecodingException {
|
||||
|
||||
@@ -64,7 +64,8 @@ public class SMTPClient {
|
||||
private Socket socket;
|
||||
public String error;
|
||||
private String lastResponse;
|
||||
private boolean supportsPipelining;
|
||||
private boolean supportsPipelining, eightBitMime;
|
||||
private long maxSize = DEFAULT_MAX_SIZE;
|
||||
|
||||
private static final Encoding base64;
|
||||
|
||||
@@ -258,12 +259,44 @@ public class SMTPClient {
|
||||
socket.setSoTimeout(60*1000);
|
||||
Result r = getFullResult();
|
||||
if (r.result == 250) {
|
||||
supportsPipelining = r.recv.contains("PIPELINING");
|
||||
String[] caps = DataHelper.split(r.recv, "\r");
|
||||
for (String c : caps) {
|
||||
if (c.equals("PIPELINING")) {
|
||||
supportsPipelining = true;
|
||||
Debug.debug(Debug.DEBUG, "Server supports pipelining");
|
||||
} else if (c.startsWith("SIZE ")) {
|
||||
try {
|
||||
maxSize = Long.parseLong(c.substring(5));
|
||||
Debug.debug(Debug.DEBUG, "Server max size: " + maxSize);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
} else if (c.equals("8BITMIME")) {
|
||||
// unused, see encoding/EightBit.java
|
||||
eightBitMime = true;
|
||||
Debug.debug(Debug.DEBUG, "Server supports 8bitmime");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error += _t("Server refused connection") + " (" + r + ")\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok && maxSize < DEFAULT_MAX_SIZE) {
|
||||
Debug.debug(Debug.DEBUG, "Rechecking with new max size");
|
||||
// recalculate whether we'll fit
|
||||
// copied from WebMail
|
||||
long total = body.length();
|
||||
if (attachments != null && !attachments.isEmpty()) {
|
||||
for(Attachment a : attachments) {
|
||||
total += a.getSize();
|
||||
}
|
||||
}
|
||||
long binaryMax = (long) ((maxSize * 57.0d / 78) - 32*1024);
|
||||
if (total > binaryMax) {
|
||||
ok = false;
|
||||
error += _t("Email is too large, max is {0}",
|
||||
DataHelper.formatSize2(binaryMax, false) + 'B') + '\n';
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
// RFC 4954 says AUTH must be the last but let's assume
|
||||
// that includes the user/pass on following lines
|
||||
|
||||
Reference in New Issue
Block a user