Nicer API for sending SMTP commands
This commit is contained in:
parent
2e38bba70a
commit
34588c1d9d
1 changed files with 38 additions and 24 deletions
|
@ -285,7 +285,7 @@ public class SmtpTransport extends Transport {
|
||||||
mOut = new BufferedOutputStream(mSocket.getOutputStream(), 1024);
|
mOut = new BufferedOutputStream(mSocket.getOutputStream(), 1024);
|
||||||
|
|
||||||
// Eat the banner
|
// Eat the banner
|
||||||
executeSimpleCommand(null, false);
|
executeCommand(null);
|
||||||
|
|
||||||
InetAddress localAddress = mSocket.getLocalAddress();
|
InetAddress localAddress = mSocket.getLocalAddress();
|
||||||
String localHost = getCanonicalHostName(localAddress);
|
String localHost = getCanonicalHostName(localAddress);
|
||||||
|
@ -313,7 +313,7 @@ public class SmtpTransport extends Transport {
|
||||||
|
|
||||||
if (mConnectionSecurity == ConnectionSecurity.STARTTLS_REQUIRED) {
|
if (mConnectionSecurity == ConnectionSecurity.STARTTLS_REQUIRED) {
|
||||||
if (extensions.containsKey("STARTTLS")) {
|
if (extensions.containsKey("STARTTLS")) {
|
||||||
executeSimpleCommand("STARTTLS", false);
|
executeCommand("STARTTLS");
|
||||||
|
|
||||||
mSocket = mTrustedSocketFactory.createSocket(
|
mSocket = mTrustedSocketFactory.createSocket(
|
||||||
mSocket,
|
mSocket,
|
||||||
|
@ -507,7 +507,7 @@ public class SmtpTransport extends Transport {
|
||||||
private Map<String, String> sendHello(String host) throws IOException, MessagingException {
|
private Map<String, String> sendHello(String host) throws IOException, MessagingException {
|
||||||
Map<String, String> extensions = new HashMap<String, String>();
|
Map<String, String> extensions = new HashMap<String, String>();
|
||||||
try {
|
try {
|
||||||
List<String> results = executeSimpleCommand("EHLO " + host, false).results;
|
List<String> results = executeCommand("EHLO %s", host).results;
|
||||||
// Remove the EHLO greeting response
|
// Remove the EHLO greeting response
|
||||||
results.remove(0);
|
results.remove(0);
|
||||||
for (String result : results) {
|
for (String result : results) {
|
||||||
|
@ -520,7 +520,7 @@ public class SmtpTransport extends Transport {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
executeSimpleCommand("HELO " + host, false);
|
executeCommand("HELO %s", host);
|
||||||
} catch (NegativeSmtpReplyException e2) {
|
} catch (NegativeSmtpReplyException e2) {
|
||||||
Log.w(LOG_TAG, "Server doesn't support the HELO command. Continuing anyway.");
|
Log.w(LOG_TAG, "Server doesn't support the HELO command. Continuing anyway.");
|
||||||
}
|
}
|
||||||
|
@ -579,12 +579,18 @@ public class SmtpTransport extends Transport {
|
||||||
boolean entireMessageSent = false;
|
boolean entireMessageSent = false;
|
||||||
Address[] from = message.getFrom();
|
Address[] from = message.getFrom();
|
||||||
try {
|
try {
|
||||||
executeSimpleCommand("MAIL FROM:" + "<" + from[0].getAddress() + ">"
|
String fromAddress = from[0].getAddress();
|
||||||
+ (m8bitEncodingAllowed ? " BODY=8BITMIME" : ""), false);
|
if (m8bitEncodingAllowed) {
|
||||||
for (String address : addresses) {
|
executeCommand("MAIL FROM:<%s> BODY=8BITMIME", fromAddress);
|
||||||
executeSimpleCommand("RCPT TO:" + "<" + address + ">", false);
|
} else {
|
||||||
|
executeCommand("MAIL FROM:<%s>", fromAddress);
|
||||||
}
|
}
|
||||||
executeSimpleCommand("DATA", false);
|
|
||||||
|
for (String address : addresses) {
|
||||||
|
executeCommand("RCPT TO:<%s>", address);
|
||||||
|
}
|
||||||
|
|
||||||
|
executeCommand("DATA");
|
||||||
|
|
||||||
EOLConvertingOutputStream msgOut = new EOLConvertingOutputStream(
|
EOLConvertingOutputStream msgOut = new EOLConvertingOutputStream(
|
||||||
new LineWrapOutputStream(new SmtpDataStuffing(mOut), 1000));
|
new LineWrapOutputStream(new SmtpDataStuffing(mOut), 1000));
|
||||||
|
@ -593,7 +599,7 @@ public class SmtpTransport extends Transport {
|
||||||
msgOut.endWithCrLfAndFlush();
|
msgOut.endWithCrLfAndFlush();
|
||||||
|
|
||||||
entireMessageSent = true; // After the "\r\n." is attempted, we may have sent the message
|
entireMessageSent = true; // After the "\r\n." is attempted, we may have sent the message
|
||||||
executeSimpleCommand(".", false);
|
executeCommand(".");
|
||||||
} catch (NegativeSmtpReplyException e) {
|
} catch (NegativeSmtpReplyException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -610,7 +616,7 @@ public class SmtpTransport extends Transport {
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
executeSimpleCommand("QUIT", false);
|
executeCommand("QUIT");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -675,10 +681,20 @@ public class SmtpTransport extends Transport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandResponse executeSimpleCommand(String command, boolean sensitive)
|
private CommandResponse executeSensitiveCommand(String format, Object... args)
|
||||||
|
throws IOException, MessagingException {
|
||||||
|
return executeCommand(true, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandResponse executeCommand(String format, Object... args) throws IOException, MessagingException {
|
||||||
|
return executeCommand(false, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandResponse executeCommand(boolean sensitive, String format, Object... args)
|
||||||
throws IOException, MessagingException {
|
throws IOException, MessagingException {
|
||||||
List<String> results = new ArrayList<>();
|
List<String> results = new ArrayList<>();
|
||||||
if (command != null) {
|
if (format != null) {
|
||||||
|
String command = String.format(Locale.ROOT, format, args);
|
||||||
writeLine(command, sensitive);
|
writeLine(command, sensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,9 +787,9 @@ public class SmtpTransport extends Transport {
|
||||||
private void saslAuthLogin(String username, String password) throws MessagingException,
|
private void saslAuthLogin(String username, String password) throws MessagingException,
|
||||||
AuthenticationFailedException, IOException {
|
AuthenticationFailedException, IOException {
|
||||||
try {
|
try {
|
||||||
executeSimpleCommand("AUTH LOGIN", false);
|
executeCommand("AUTH LOGIN");
|
||||||
executeSimpleCommand(Base64.encode(username), true);
|
executeSensitiveCommand(Base64.encode(username));
|
||||||
executeSimpleCommand(Base64.encode(password), true);
|
executeSensitiveCommand(Base64.encode(password));
|
||||||
} catch (NegativeSmtpReplyException exception) {
|
} catch (NegativeSmtpReplyException exception) {
|
||||||
if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) {
|
if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) {
|
||||||
// Authentication credentials invalid
|
// Authentication credentials invalid
|
||||||
|
@ -789,7 +805,7 @@ public class SmtpTransport extends Transport {
|
||||||
AuthenticationFailedException, IOException {
|
AuthenticationFailedException, IOException {
|
||||||
String data = Base64.encode("\000" + username + "\000" + password);
|
String data = Base64.encode("\000" + username + "\000" + password);
|
||||||
try {
|
try {
|
||||||
executeSimpleCommand("AUTH PLAIN " + data, true);
|
executeSensitiveCommand("AUTH PLAIN %s", data);
|
||||||
} catch (NegativeSmtpReplyException exception) {
|
} catch (NegativeSmtpReplyException exception) {
|
||||||
if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) {
|
if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) {
|
||||||
// Authentication credentials invalid
|
// Authentication credentials invalid
|
||||||
|
@ -804,7 +820,7 @@ public class SmtpTransport extends Transport {
|
||||||
private void saslAuthCramMD5(String username, String password) throws MessagingException,
|
private void saslAuthCramMD5(String username, String password) throws MessagingException,
|
||||||
AuthenticationFailedException, IOException {
|
AuthenticationFailedException, IOException {
|
||||||
|
|
||||||
List<String> respList = executeSimpleCommand("AUTH CRAM-MD5", false).results;
|
List<String> respList = executeCommand("AUTH CRAM-MD5").results;
|
||||||
if (respList.size() != 1) {
|
if (respList.size() != 1) {
|
||||||
throw new MessagingException("Unable to negotiate CRAM-MD5");
|
throw new MessagingException("Unable to negotiate CRAM-MD5");
|
||||||
}
|
}
|
||||||
|
@ -813,7 +829,7 @@ public class SmtpTransport extends Transport {
|
||||||
String b64CRAMString = Authentication.computeCramMd5(mUsername, mPassword, b64Nonce);
|
String b64CRAMString = Authentication.computeCramMd5(mUsername, mPassword, b64Nonce);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
executeSimpleCommand(b64CRAMString, true);
|
executeSensitiveCommand(b64CRAMString);
|
||||||
} catch (NegativeSmtpReplyException exception) {
|
} catch (NegativeSmtpReplyException exception) {
|
||||||
if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) {
|
if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) {
|
||||||
// Authentication credentials invalid
|
// Authentication credentials invalid
|
||||||
|
@ -877,20 +893,18 @@ public class SmtpTransport extends Transport {
|
||||||
private void attemptXoauth2(String username) throws MessagingException, IOException {
|
private void attemptXoauth2(String username) throws MessagingException, IOException {
|
||||||
String token = oauthTokenProvider.getToken(username, OAuth2TokenProvider.OAUTH2_TIMEOUT);
|
String token = oauthTokenProvider.getToken(username, OAuth2TokenProvider.OAUTH2_TIMEOUT);
|
||||||
String authString = Authentication.computeXoauth(username, token);
|
String authString = Authentication.computeXoauth(username, token);
|
||||||
CommandResponse response = executeSimpleCommand("AUTH XOAUTH2 " + authString, true);
|
CommandResponse response = executeSensitiveCommand("AUTH XOAUTH2 %s", authString);
|
||||||
|
|
||||||
if (response.replyCode == SMTP_CONTINUE_REQUEST) {
|
if (response.replyCode == SMTP_CONTINUE_REQUEST) {
|
||||||
retryXoauthWithNewToken = XOAuth2ChallengeParser.shouldRetry(join(response.results, ""), mHost);
|
retryXoauthWithNewToken = XOAuth2ChallengeParser.shouldRetry(join(response.results, ""), mHost);
|
||||||
|
|
||||||
//Per Google spec, respond to challenge with empty response
|
//Per Google spec, respond to challenge with empty response
|
||||||
executeSimpleCommand("", false);
|
executeCommand("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saslAuthExternal(String username) throws MessagingException, IOException {
|
private void saslAuthExternal(String username) throws MessagingException, IOException {
|
||||||
executeSimpleCommand(
|
executeCommand("AUTH EXTERNAL %s", Base64.encode(username));
|
||||||
String.format("AUTH EXTERNAL %s",
|
|
||||||
Base64.encode(username)), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|
Loading…
Reference in a new issue