From a6ad98e9da93c354b0d270470f2c2ac7b3c68ab6 Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Sat, 4 Mar 2017 23:09:06 +0000 Subject: [PATCH 1/9] SMTPTransport - Improve multi-line response handling, remove deprecated API and implement RFC 2034 --- .../fsck/k9/mail/transport/SmtpTransport.java | 302 ++++++++++++------ .../k9/mail/transport/SmtpTransportTest.java | 42 ++- 2 files changed, 240 insertions(+), 104 deletions(-) diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java index 80fa274ee..d64a8ecad 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java @@ -49,12 +49,27 @@ import com.fsck.k9.mail.oauth.XOAuth2ChallengeParser; import com.fsck.k9.mail.ssl.TrustedSocketFactory; import com.fsck.k9.mail.store.StoreConfig; import javax.net.ssl.SSLException; +import org.apache.commons.io.IOUtils; import static com.fsck.k9.mail.CertificateValidationException.Reason.MissingCapability; import static com.fsck.k9.mail.K9MailLib.DEBUG_PROTOCOL_SMTP; import static com.fsck.k9.mail.K9MailLib.LOG_TAG; public class SmtpTransport extends Transport { + + public static String join(List strings, String separator) { + if (strings == null) { + return ""; + } + StringBuilder builtString = new StringBuilder(); + for (int i = 0; i < strings.size(); i++) { + builtString.append(strings.get(i)); + if (i + 1 < strings.size()) + builtString.append(separator); + } + return builtString.toString(); + } + public static final int SMTP_CONTINUE_REQUEST = 334; public static final int SMTP_AUTHENTICATION_FAILURE_ERROR_CODE = 535; @@ -211,6 +226,7 @@ public class SmtpTransport extends Transport { private PeekableInputStream mIn; private OutputStream mOut; private boolean m8bitEncodingAllowed; + private boolean mEnhancedStatusCodesProvided; private int mLargestAcceptableMessage; private boolean retryXoauthWithNewToken; @@ -269,7 +285,7 @@ public class SmtpTransport extends Transport { mOut = new BufferedOutputStream(mSocket.getOutputStream(), 1024); // Eat the banner - executeSimpleCommand(null); + executeSimpleCommand(null, false); InetAddress localAddress = mSocket.getLocalAddress(); String localHost = getCanonicalHostName(localAddress); @@ -293,11 +309,11 @@ public class SmtpTransport extends Transport { Map extensions = sendHello(localHost); m8bitEncodingAllowed = extensions.containsKey("8BITMIME"); - + mEnhancedStatusCodesProvided = extensions.containsKey("ENHANCEDSTATUSCODES"); if (mConnectionSecurity == ConnectionSecurity.STARTTLS_REQUIRED) { if (extensions.containsKey("STARTTLS")) { - executeSimpleCommand("STARTTLS"); + executeSimpleCommand("STARTTLS", false); mSocket = mTrustedSocketFactory.createSocket( mSocket, @@ -488,10 +504,10 @@ public class SmtpTransport extends Transport { * @throws MessagingException * In case of a malformed response. */ - private Map sendHello(String host) throws IOException, MessagingException { + private Map sendHello(String host) throws IOException, MessagingException { Map extensions = new HashMap(); try { - List results = executeSimpleCommand("EHLO " + host); + List results = executeSimpleCommand("EHLO " + host, false).results; // Remove the EHLO greeting response results.remove(0); for (String result : results) { @@ -504,7 +520,7 @@ public class SmtpTransport extends Transport { } try { - executeSimpleCommand("HELO " + host); + executeSimpleCommand("HELO " + host, false); } catch (NegativeSmtpReplyException e2) { Log.w(LOG_TAG, "Server doesn't support the HELO command. Continuing anyway."); } @@ -564,11 +580,11 @@ public class SmtpTransport extends Transport { Address[] from = message.getFrom(); try { executeSimpleCommand("MAIL FROM:" + "<" + from[0].getAddress() + ">" - + (m8bitEncodingAllowed ? " BODY=8BITMIME" : "")); + + (m8bitEncodingAllowed ? " BODY=8BITMIME" : ""), false); for (String address : addresses) { - executeSimpleCommand("RCPT TO:" + "<" + address + ">"); + executeSimpleCommand("RCPT TO:" + "<" + address + ">", false); } - executeSimpleCommand("DATA"); + executeSimpleCommand("DATA", false); EOLConvertingOutputStream msgOut = new EOLConvertingOutputStream( new LineWrapOutputStream(new SmtpDataStuffing(mOut), 1000)); @@ -577,7 +593,7 @@ public class SmtpTransport extends Transport { msgOut.endWithCrLfAndFlush(); entireMessageSent = true; // After the "\r\n." is attempted, we may have sent the message - executeSimpleCommand("."); + executeSimpleCommand(".", false); } catch (NegativeSmtpReplyException e) { throw e; } catch (Exception e) { @@ -594,25 +610,13 @@ public class SmtpTransport extends Transport { @Override public void close() { try { - executeSimpleCommand("QUIT"); - } catch (Exception e) { - - } - try { - mIn.close(); - } catch (Exception e) { - - } - try { - mOut.close(); - } catch (Exception e) { - - } - try { - mSocket.close(); + executeSimpleCommand("QUIT", false); } catch (Exception e) { } + IOUtils.closeQuietly(mIn); + IOUtils.closeQuietly(mOut); + IOUtils.closeQuietly(mSocket); mIn = null; mOut = null; mSocket = null; @@ -660,74 +664,19 @@ public class SmtpTransport extends Transport { mOut.flush(); } - private void checkLine(String line) throws MessagingException { - int length = line.length(); - if (length < 1) { - throw new MessagingException("SMTP response is 0 length"); - } - - char c = line.charAt(0); - if ((c == '4') || (c == '5')) { - int replyCode = -1; - String message = line; - if (length >= 3) { - try { - replyCode = Integer.parseInt(line.substring(0, 3)); - } catch (NumberFormatException e) { /* ignore */ } - - if (length > 4) { - message = line.substring(4); - } else { - message = ""; - } - } - - throw new NegativeSmtpReplyException(replyCode, message); - } - - } - @Deprecated - private List executeSimpleCommand(String command) throws IOException, MessagingException { - return executeSimpleCommand(command, false); - } - - /** - * TODO: All responses should be checked to confirm that they start with a valid - * reply code, and that the reply code is appropriate for the command being executed. - * That means it should either be a 2xx code (generally) or a 3xx code in special cases - * (e.g., DATA & AUTH LOGIN commands). Reply codes should be made available as part of - * the returned object. - * - * This should be done using the non-deprecated API below. - */ - @Deprecated - private List executeSimpleCommand(String command, boolean sensitive) - throws IOException, MessagingException { - List results = new ArrayList<>(); - if (command != null) { - writeLine(command, sensitive); - } - - String line = readCommandResponseLine(results); - - // Check if the reply code indicates an error. - checkLine(line); - - return results; - } - private static class CommandResponse { private final int replyCode; - private final String message; + private final List results; - public CommandResponse(int replyCode, String message) { + public CommandResponse(int replyCode, List results) { this.replyCode = replyCode; - this.message = message; + this.results = results; } } - private CommandResponse executeSimpleCommandWithResponse(String command, boolean sensitive) throws IOException, MessagingException { + private CommandResponse executeSimpleCommand(String command, boolean sensitive) + throws IOException, MessagingException { List results = new ArrayList<>(); if (command != null) { writeLine(command, sensitive); @@ -741,25 +690,42 @@ public class SmtpTransport extends Transport { } int replyCode = -1; - String message = line; if (length >= 3) { try { replyCode = Integer.parseInt(line.substring(0, 3)); } catch (NumberFormatException e) { /* ignore */ } - - if (length > 4) { - message = line.substring(4); - } else { - message = ""; - } } char c = line.charAt(0); if ((c == '4') || (c == '5')) { - throw new NegativeSmtpReplyException(replyCode, message); + if (mEnhancedStatusCodesProvided) { + throw buildEnhancedNegativeSmtpReplyException(replyCode, results); + } else { + throw new NegativeSmtpReplyException(replyCode, join(results, " ")); + } } - return new CommandResponse(replyCode, message); + return new CommandResponse(replyCode, results); + } + + private MessagingException buildEnhancedNegativeSmtpReplyException(int replyCode, List results) { + SmtpEnhancedStatusCodeClass escClass = null; + SmtpEnhancedStatusCodeSubject escSubject = null; + SmtpEnhancedStatusCodeDetail escDetail = null; + + String message = ""; + for (String resultLine: results) { + message += resultLine.split(" ", 2)[1] + " "; + } + if (results.size() > 0) { + String[] esc = results.get(0).split(" ", 2)[0].split("\\."); + + escClass = SmtpEnhancedStatusCodeClass.parse(esc[0]); + escSubject = SmtpEnhancedStatusCodeSubject.parse(esc[1]); + escDetail = SmtpEnhancedStatusCodeDetail.parse(escSubject, esc[2]); + } + + return new EnhancedNegativeSmtpReplyException(replyCode, escClass, escSubject, escDetail, message.trim()); } @@ -805,7 +771,7 @@ public class SmtpTransport extends Transport { private void saslAuthLogin(String username, String password) throws MessagingException, AuthenticationFailedException, IOException { try { - executeSimpleCommand("AUTH LOGIN"); + executeSimpleCommand("AUTH LOGIN", false); executeSimpleCommand(Base64.encode(username), true); executeSimpleCommand(Base64.encode(password), true); } catch (NegativeSmtpReplyException exception) { @@ -838,7 +804,7 @@ public class SmtpTransport extends Transport { private void saslAuthCramMD5(String username, String password) throws MessagingException, AuthenticationFailedException, IOException { - List respList = executeSimpleCommand("AUTH CRAM-MD5"); + List respList = executeSimpleCommand("AUTH CRAM-MD5", false).results; if (respList.size() != 1) { throw new MessagingException("Unable to negotiate CRAM-MD5"); } @@ -911,13 +877,13 @@ public class SmtpTransport extends Transport { private void attemptXoauth2(String username) throws MessagingException, IOException { String token = oauthTokenProvider.getToken(username, OAuth2TokenProvider.OAUTH2_TIMEOUT); String authString = Authentication.computeXoauth(username, token); - CommandResponse response = executeSimpleCommandWithResponse("AUTH XOAUTH2 " + authString, true); + CommandResponse response = executeSimpleCommand("AUTH XOAUTH2 " + authString, true); if (response.replyCode == SMTP_CONTINUE_REQUEST) { - retryXoauthWithNewToken = XOAuth2ChallengeParser.shouldRetry(response.message, mHost); + retryXoauthWithNewToken = XOAuth2ChallengeParser.shouldRetry(join(response.results, ""), mHost); //Per Google spec, respond to challenge with empty response - executeSimpleCommandWithResponse("", false); + executeSimpleCommand("", false); } } @@ -942,7 +908,9 @@ public class SmtpTransport extends Transport { private final String mReplyText; public NegativeSmtpReplyException(int replyCode, String replyText) { - super("Negative SMTP reply: " + replyCode + " " + replyText, isPermanentSmtpError(replyCode)); + super((replyText != null && !replyText.isEmpty()) ? + replyText : ("Negative SMTP reply: " + replyCode), + isPermanentSmtpError(replyCode)); mReplyCode = replyCode; mReplyText = replyText; } @@ -959,4 +927,136 @@ public class SmtpTransport extends Transport { return mReplyText; } } + + static class EnhancedNegativeSmtpReplyException extends NegativeSmtpReplyException { + + private final SmtpEnhancedStatusCodeClass escClass; + private final SmtpEnhancedStatusCodeSubject escSubject; + private final SmtpEnhancedStatusCodeDetail escDetail; + + public EnhancedNegativeSmtpReplyException(int replyCode, SmtpEnhancedStatusCodeClass escClass, + SmtpEnhancedStatusCodeSubject escSubject, SmtpEnhancedStatusCodeDetail escDetail, String replyText) { + super(replyCode, replyText); + this.escClass = escClass; + this.escSubject = escSubject; + this.escDetail = escDetail; + } + } + + enum SmtpEnhancedStatusCodeClass { + Success(2), PersistentTransientFailure(4), PermanentFailure(5); + + private final int codeClass; + + public static SmtpEnhancedStatusCodeClass parse(String s) { + int value = Integer.parseInt(s); + for (SmtpEnhancedStatusCodeClass classEnum: SmtpEnhancedStatusCodeClass.values()) { + if (classEnum.codeClass == value) { + return classEnum; + } + } + return null; + } + + SmtpEnhancedStatusCodeClass(int codeClass) { + this.codeClass = codeClass; + } + } + + enum SmtpEnhancedStatusCodeSubject { + Undefined(0), Addressing(1), Mailbox(2), MailSystem(3), NetworkRouting(4), + MailDeliveryProtocol(5), MessageContentOrMedia(6), SecurityOrPolicyStatus(7); + + private final int codeSubject; + + public static SmtpEnhancedStatusCodeSubject parse(String s) { + int value = Integer.parseInt(s); + for (SmtpEnhancedStatusCodeSubject classEnum: SmtpEnhancedStatusCodeSubject.values()) { + if (classEnum.codeSubject == value) { + return classEnum; + } + } + return null; + } + + SmtpEnhancedStatusCodeSubject(int codeSubject) { + this.codeSubject = codeSubject; + } + } + + enum SmtpEnhancedStatusCodeDetail { + Undefined(SmtpEnhancedStatusCodeSubject.Undefined, 0), + OtherAddressStatus(SmtpEnhancedStatusCodeSubject.Addressing, 0), + BadDestinationMailboxAddress(SmtpEnhancedStatusCodeSubject.Addressing, 1), + BadDestinationSystemAddress(SmtpEnhancedStatusCodeSubject.Addressing, 2), + BadDestinationMailboxAddressSyntax(SmtpEnhancedStatusCodeSubject.Addressing, 3), + DestinationMailboxAddressAmbiguous(SmtpEnhancedStatusCodeSubject.Addressing, 4), + DestinationAddressValid(SmtpEnhancedStatusCodeSubject.Addressing, 5), + DestinationMailboxMoved(SmtpEnhancedStatusCodeSubject.Addressing, 6), + BadSenderMailboxSyntax(SmtpEnhancedStatusCodeSubject.Addressing, 7), + BadSenderSystemAddress(SmtpEnhancedStatusCodeSubject.Addressing, 8), + + OtherMailboxStatus(SmtpEnhancedStatusCodeSubject.Mailbox,0), + MailboxDisabled(SmtpEnhancedStatusCodeSubject.Mailbox,1), + MailboxFull(SmtpEnhancedStatusCodeSubject.Mailbox,2), + MessageLengthExceeded(SmtpEnhancedStatusCodeSubject.Mailbox,3), + MailingListExpansionProblem(SmtpEnhancedStatusCodeSubject.Mailbox,4), + + OtherMailSystemStatus(SmtpEnhancedStatusCodeSubject.MailSystem,0), + MailSystemFull(SmtpEnhancedStatusCodeSubject.MailSystem,1), + SystemNotAcceptingMessages(SmtpEnhancedStatusCodeSubject.MailSystem,2), + SystemIncapableOfFeature(SmtpEnhancedStatusCodeSubject.MailSystem,3), + MessageTooBig(SmtpEnhancedStatusCodeSubject.MailSystem,4), + SystemIncorrectlyConfigured(SmtpEnhancedStatusCodeSubject.MailSystem,5), + + OtherNetworkRouting(SmtpEnhancedStatusCodeSubject.NetworkRouting,0), + NoAnswerFromHost(SmtpEnhancedStatusCodeSubject.NetworkRouting,1), + BadConnection(SmtpEnhancedStatusCodeSubject.NetworkRouting,2), + DirectoryServerFailure(SmtpEnhancedStatusCodeSubject.NetworkRouting,3), + UnableToRoute(SmtpEnhancedStatusCodeSubject.NetworkRouting,4), + MailSystemCongestion(SmtpEnhancedStatusCodeSubject.NetworkRouting,5), + RoutingLoopDetected(SmtpEnhancedStatusCodeSubject.NetworkRouting,6), + DeliveryTimeExpired(SmtpEnhancedStatusCodeSubject.NetworkRouting,7), + + OtherMailDeliveryProtocol(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,0), + InvalidCommand(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,1), + SyntaxError(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,2), + TooManyRecipients(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,3), + InvalidCommandArguments(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,4), + WrongProtocolVersion(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,5), + + OtherMessageContentOrMedia(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,0), + MediaNotSupported(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,1), + ConversionRequiredAndProhibited(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,2), + ConversionRequiredButUnsupported(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,3), + ConversionWithLossPerformed(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,4), + ConversionFailed(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,5), + + OtherSecurityOrPolicyStatus(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 0), + DeliveryNotAuthorized(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 1), + MailingListExpansionProhibited(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 2), + SecurityConversionRequired(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 3), + SecurityFeaturesUnsupported(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 4), + CryptographicFailure(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 5), + CryptographicAlgorithmUnsupported(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 6), + MessageIntegrityFailure(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 7); + + private final SmtpEnhancedStatusCodeSubject subject; + private final int detail; + + SmtpEnhancedStatusCodeDetail(SmtpEnhancedStatusCodeSubject subject, int detail) { + this.subject = subject; + this.detail = detail; + } + + public static SmtpEnhancedStatusCodeDetail parse(SmtpEnhancedStatusCodeSubject subject, String s) { + int value = Integer.parseInt(s); + for (SmtpEnhancedStatusCodeDetail detailEnum: SmtpEnhancedStatusCodeDetail.values()) { + if (detailEnum.subject == subject && detailEnum.detail == value) { + return detailEnum; + } + } + return null; + } + } } diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java index bfc8cec31..7e312df5d 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java @@ -227,7 +227,8 @@ public class SmtpTransportTest { fail("Exception expected"); } catch (AuthenticationFailedException e) { assertEquals( - "Negative SMTP reply: 535 5.7.1 http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68", + "5.7.1 Username and Password not accepted. Learn more at " + + "5.7.1 http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68", e.getMessage()); } @@ -343,7 +344,8 @@ public class SmtpTransportTest { fail("Exception expected"); } catch (AuthenticationFailedException e) { assertEquals( - "Negative SMTP reply: 535 5.7.1 http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68", + "5.7.1 Username and Password not accepted. Learn more at " + + "5.7.1 http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68", e.getMessage()); } @@ -374,7 +376,6 @@ public class SmtpTransportTest { server.verifyInteractionCompleted(); } - @Test public void open_withoutXoauth2Extension_shouldThrow() throws Exception { MockSmtpServer server = new MockSmtpServer(); @@ -497,6 +498,41 @@ public class SmtpTransportTest { server.verifyInteractionCompleted(); } + @Test + public void open_withSupportWithEnhancedStatusCodesOnAuthFailure_shouldThrowEncodedMessage() + throws Exception { + MockSmtpServer server = new MockSmtpServer(); + server.output("220 localhost Simple Mail Transfer Service Ready"); + server.expect("EHLO localhost"); + server.output("250-localhost Hello client.localhost"); + server.output("250-ENHANCEDSTATUSCODES"); + server.output("250 AUTH XOAUTH2"); + server.expect("AUTH XOAUTH2 dXNlcj11c2VyAWF1dGg9QmVhcmVyIG9sZFRva2VuAQE="); + server.output("334 "+ XOAuth2ChallengeParserTest.STATUS_401_RESPONSE); + server.expect(""); + server.output("535-5.7.1 Username and Password not accepted. Learn more at"); + server.output("535 5.7.1 http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68"); + server.expect("QUIT"); + server.output("221 BYE"); + SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.XOAUTH2, ConnectionSecurity.NONE); + + try { + transport.open(); + fail("Exception expected"); + } catch (AuthenticationFailedException e) { + assertEquals( + "Username and Password not accepted. Learn more at http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68", + e.getMessage()); + } + + InOrder inOrder = inOrder(oAuth2TokenProvider); + inOrder.verify(oAuth2TokenProvider).getToken(eq(USERNAME), anyInt()); + inOrder.verify(oAuth2TokenProvider).invalidateToken(USERNAME); + server.verifyConnectionClosed(); + server.verifyInteractionCompleted(); + + } + @Test public void sendMessage_withoutAddressToSendTo_shouldNotOpenConnection() throws Exception { MimeMessage message = new MimeMessage(); From 2e38bba70ac4678b1c25da9e8861a9677e207419 Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Sat, 4 Mar 2017 15:34:37 +0000 Subject: [PATCH 2/9] Add test for case sensitivity of extensions --- .../k9/mail/transport/SmtpTransportTest.java | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java index 7e312df5d..9059a45a6 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java @@ -508,7 +508,7 @@ public class SmtpTransportTest { server.output("250-ENHANCEDSTATUSCODES"); server.output("250 AUTH XOAUTH2"); server.expect("AUTH XOAUTH2 dXNlcj11c2VyAWF1dGg9QmVhcmVyIG9sZFRva2VuAQE="); - server.output("334 "+ XOAuth2ChallengeParserTest.STATUS_401_RESPONSE); + server.output("334 " + XOAuth2ChallengeParserTest.STATUS_401_RESPONSE); server.expect(""); server.output("535-5.7.1 Username and Password not accepted. Learn more at"); server.output("535 5.7.1 http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68"); @@ -530,7 +530,29 @@ public class SmtpTransportTest { inOrder.verify(oAuth2TokenProvider).invalidateToken(USERNAME); server.verifyConnectionClosed(); server.verifyInteractionCompleted(); + } + @Test + public void open_withManyExtensions_shouldParseAll() throws Exception { + MockSmtpServer server = new MockSmtpServer(); + server.output("220 smtp.gmail.com ESMTP x25sm19117693wrx.27 - gsmtp"); + server.expect("EHLO localhost"); + server.output("250-smtp.gmail.com at your service, [86.147.34.216]"); + server.output("250-SIZE 35882577"); + server.output("250-8BITMIME"); + server.output("250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH"); + server.output("250-ENHANCEDSTATUSCODES"); + server.output("250-PIPELINING"); + server.output("250-CHUNKING"); + server.output("250 SMTPUTF8"); + server.expect("AUTH XOAUTH2 dXNlcj11c2VyAWF1dGg9QmVhcmVyIG9sZFRva2VuAQE="); + server.output("235 2.7.0 Authentication successful"); + SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.XOAUTH2, ConnectionSecurity.NONE); + + transport.open(); + + server.verifyConnectionStillOpen(); + server.verifyInteractionCompleted(); } @Test @@ -592,6 +614,30 @@ public class SmtpTransportTest { server.verifyInteractionCompleted(); } + @Test + public void sendMessage_with8BitEncodingExtensionNotCaseSensitive() throws Exception { + Message message = getDefaultMessage(); + MockSmtpServer server = createServerAndSetupForPlainAuthentication("8bitmime"); + server.expect("MAIL FROM: BODY=8BITMIME"); + server.output("250 OK"); + server.expect("RCPT TO:"); + server.output("250 OK"); + server.expect("DATA"); + server.output("354 End data with ."); + server.expect("[message data]"); + server.expect("."); + server.output("250 OK: queued as 12345"); + server.expect("QUIT"); + server.output("221 BYE"); + server.closeConnection(); + SmtpTransport transport = startServerAndCreateSmtpTransport(server); + + transport.sendMessage(message); + + server.verifyConnectionClosed(); + server.verifyInteractionCompleted(); + } + @Test public void sendMessage_withMessageTooLarge_shouldThrow() throws Exception { Message message = getDefaultMessageBuilder() From 34588c1d9d477bd47a5da487f4232fa2cf89c280 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 14 Mar 2017 04:13:50 +0100 Subject: [PATCH 3/9] Nicer API for sending SMTP commands --- .../fsck/k9/mail/transport/SmtpTransport.java | 62 ++++++++++++------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java index d64a8ecad..224e3429a 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java @@ -285,7 +285,7 @@ public class SmtpTransport extends Transport { mOut = new BufferedOutputStream(mSocket.getOutputStream(), 1024); // Eat the banner - executeSimpleCommand(null, false); + executeCommand(null); InetAddress localAddress = mSocket.getLocalAddress(); String localHost = getCanonicalHostName(localAddress); @@ -313,7 +313,7 @@ public class SmtpTransport extends Transport { if (mConnectionSecurity == ConnectionSecurity.STARTTLS_REQUIRED) { if (extensions.containsKey("STARTTLS")) { - executeSimpleCommand("STARTTLS", false); + executeCommand("STARTTLS"); mSocket = mTrustedSocketFactory.createSocket( mSocket, @@ -507,7 +507,7 @@ public class SmtpTransport extends Transport { private Map sendHello(String host) throws IOException, MessagingException { Map extensions = new HashMap(); try { - List results = executeSimpleCommand("EHLO " + host, false).results; + List results = executeCommand("EHLO %s", host).results; // Remove the EHLO greeting response results.remove(0); for (String result : results) { @@ -520,7 +520,7 @@ public class SmtpTransport extends Transport { } try { - executeSimpleCommand("HELO " + host, false); + executeCommand("HELO %s", host); } catch (NegativeSmtpReplyException e2) { 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; Address[] from = message.getFrom(); try { - executeSimpleCommand("MAIL FROM:" + "<" + from[0].getAddress() + ">" - + (m8bitEncodingAllowed ? " BODY=8BITMIME" : ""), false); - for (String address : addresses) { - executeSimpleCommand("RCPT TO:" + "<" + address + ">", false); + String fromAddress = from[0].getAddress(); + if (m8bitEncodingAllowed) { + executeCommand("MAIL FROM:<%s> BODY=8BITMIME", fromAddress); + } else { + executeCommand("MAIL FROM:<%s>", fromAddress); } - executeSimpleCommand("DATA", false); + + for (String address : addresses) { + executeCommand("RCPT TO:<%s>", address); + } + + executeCommand("DATA"); EOLConvertingOutputStream msgOut = new EOLConvertingOutputStream( new LineWrapOutputStream(new SmtpDataStuffing(mOut), 1000)); @@ -593,7 +599,7 @@ public class SmtpTransport extends Transport { msgOut.endWithCrLfAndFlush(); entireMessageSent = true; // After the "\r\n." is attempted, we may have sent the message - executeSimpleCommand(".", false); + executeCommand("."); } catch (NegativeSmtpReplyException e) { throw e; } catch (Exception e) { @@ -610,7 +616,7 @@ public class SmtpTransport extends Transport { @Override public void close() { try { - executeSimpleCommand("QUIT", false); + executeCommand("QUIT"); } 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 { List results = new ArrayList<>(); - if (command != null) { + if (format != null) { + String command = String.format(Locale.ROOT, format, args); writeLine(command, sensitive); } @@ -771,9 +787,9 @@ public class SmtpTransport extends Transport { private void saslAuthLogin(String username, String password) throws MessagingException, AuthenticationFailedException, IOException { try { - executeSimpleCommand("AUTH LOGIN", false); - executeSimpleCommand(Base64.encode(username), true); - executeSimpleCommand(Base64.encode(password), true); + executeCommand("AUTH LOGIN"); + executeSensitiveCommand(Base64.encode(username)); + executeSensitiveCommand(Base64.encode(password)); } catch (NegativeSmtpReplyException exception) { if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) { // Authentication credentials invalid @@ -789,7 +805,7 @@ public class SmtpTransport extends Transport { AuthenticationFailedException, IOException { String data = Base64.encode("\000" + username + "\000" + password); try { - executeSimpleCommand("AUTH PLAIN " + data, true); + executeSensitiveCommand("AUTH PLAIN %s", data); } catch (NegativeSmtpReplyException exception) { if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) { // Authentication credentials invalid @@ -804,7 +820,7 @@ public class SmtpTransport extends Transport { private void saslAuthCramMD5(String username, String password) throws MessagingException, AuthenticationFailedException, IOException { - List respList = executeSimpleCommand("AUTH CRAM-MD5", false).results; + List respList = executeCommand("AUTH CRAM-MD5").results; if (respList.size() != 1) { throw new MessagingException("Unable to negotiate CRAM-MD5"); } @@ -813,7 +829,7 @@ public class SmtpTransport extends Transport { String b64CRAMString = Authentication.computeCramMd5(mUsername, mPassword, b64Nonce); try { - executeSimpleCommand(b64CRAMString, true); + executeSensitiveCommand(b64CRAMString); } catch (NegativeSmtpReplyException exception) { if (exception.getReplyCode() == SMTP_AUTHENTICATION_FAILURE_ERROR_CODE) { // Authentication credentials invalid @@ -877,20 +893,18 @@ public class SmtpTransport extends Transport { private void attemptXoauth2(String username) throws MessagingException, IOException { String token = oauthTokenProvider.getToken(username, OAuth2TokenProvider.OAUTH2_TIMEOUT); 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) { retryXoauthWithNewToken = XOAuth2ChallengeParser.shouldRetry(join(response.results, ""), mHost); //Per Google spec, respond to challenge with empty response - executeSimpleCommand("", false); + executeCommand(""); } } private void saslAuthExternal(String username) throws MessagingException, IOException { - executeSimpleCommand( - String.format("AUTH EXTERNAL %s", - Base64.encode(username)), false); + executeCommand("AUTH EXTERNAL %s", Base64.encode(username)); } @VisibleForTesting From f927eadbdb14a8dad734dc1edfa098441b6a5977 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 14 Mar 2017 04:49:38 +0100 Subject: [PATCH 4/9] Remove custom join method --- .../fsck/k9/mail/transport/SmtpTransport.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java index 224e3429a..c962614f4 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java @@ -56,20 +56,6 @@ import static com.fsck.k9.mail.K9MailLib.DEBUG_PROTOCOL_SMTP; import static com.fsck.k9.mail.K9MailLib.LOG_TAG; public class SmtpTransport extends Transport { - - public static String join(List strings, String separator) { - if (strings == null) { - return ""; - } - StringBuilder builtString = new StringBuilder(); - for (int i = 0; i < strings.size(); i++) { - builtString.append(strings.get(i)); - if (i + 1 < strings.size()) - builtString.append(separator); - } - return builtString.toString(); - } - public static final int SMTP_CONTINUE_REQUEST = 334; public static final int SMTP_AUTHENTICATION_FAILURE_ERROR_CODE = 535; @@ -717,7 +703,8 @@ public class SmtpTransport extends Transport { if (mEnhancedStatusCodesProvided) { throw buildEnhancedNegativeSmtpReplyException(replyCode, results); } else { - throw new NegativeSmtpReplyException(replyCode, join(results, " ")); + String replyText = TextUtils.join(" ", results); + throw new NegativeSmtpReplyException(replyCode, replyText); } } @@ -896,7 +883,8 @@ public class SmtpTransport extends Transport { CommandResponse response = executeSensitiveCommand("AUTH XOAUTH2 %s", authString); if (response.replyCode == SMTP_CONTINUE_REQUEST) { - retryXoauthWithNewToken = XOAuth2ChallengeParser.shouldRetry(join(response.results, ""), mHost); + String replyText = TextUtils.join("", response.results); + retryXoauthWithNewToken = XOAuth2ChallengeParser.shouldRetry(replyText, mHost); //Per Google spec, respond to challenge with empty response executeCommand(""); From 0b22cd5b8fd5110c220fe1e4f3e0909ea87a0c9d Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 14 Mar 2017 04:54:26 +0100 Subject: [PATCH 5/9] Move SmtpTransport to separate package --- .../src/main/java/com/fsck/k9/mail/Transport.java | 7 +------ .../src/main/java/com/fsck/k9/mail/TransportProvider.java | 2 +- .../fsck/k9/mail/transport/{ => smtp}/SmtpTransport.java | 2 +- .../k9/mail/transport/{ => smtp}/SmtpTransportTest.java | 4 ++-- .../k9/mail/transport/{ => smtp}/SmtpTransportUriTest.java | 3 ++- 5 files changed, 7 insertions(+), 11 deletions(-) rename k9mail-library/src/main/java/com/fsck/k9/mail/transport/{ => smtp}/SmtpTransport.java (99%) rename k9mail-library/src/test/java/com/fsck/k9/mail/transport/{ => smtp}/SmtpTransportTest.java (99%) rename k9mail-library/src/test/java/com/fsck/k9/mail/transport/{ => smtp}/SmtpTransportUriTest.java (98%) diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/Transport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/Transport.java index 6b38ec557..daae1f78d 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/Transport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/Transport.java @@ -1,13 +1,8 @@ package com.fsck.k9.mail; -import android.content.Context; - -import com.fsck.k9.mail.oauth.OAuth2TokenProvider; -import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory; -import com.fsck.k9.mail.store.StoreConfig; import com.fsck.k9.mail.ServerSettings.Type; -import com.fsck.k9.mail.transport.SmtpTransport; +import com.fsck.k9.mail.transport.smtp.SmtpTransport; import com.fsck.k9.mail.transport.WebDavTransport; import java.io.UnsupportedEncodingException; diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/TransportProvider.java b/k9mail-library/src/main/java/com/fsck/k9/mail/TransportProvider.java index 6e70a650a..989296243 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/TransportProvider.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/TransportProvider.java @@ -6,7 +6,7 @@ import android.content.Context; import com.fsck.k9.mail.oauth.OAuth2TokenProvider; import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory; import com.fsck.k9.mail.store.StoreConfig; -import com.fsck.k9.mail.transport.SmtpTransport; +import com.fsck.k9.mail.transport.smtp.SmtpTransport; import com.fsck.k9.mail.transport.WebDavTransport; public class TransportProvider { diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java similarity index 99% rename from k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java rename to k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java index c962614f4..21c9ea013 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java @@ -1,5 +1,5 @@ -package com.fsck.k9.mail.transport; +package com.fsck.k9.mail.transport.smtp; import java.io.BufferedInputStream; diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java similarity index 99% rename from k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java rename to k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java index 9059a45a6..783812eae 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java @@ -1,4 +1,4 @@ -package com.fsck.k9.mail.transport; +package com.fsck.k9.mail.transport.smtp; import java.io.IOException; @@ -22,11 +22,11 @@ import com.fsck.k9.mail.oauth.OAuth2TokenProvider; import com.fsck.k9.mail.ssl.TrustedSocketFactory; import com.fsck.k9.mail.store.StoreConfig; import com.fsck.k9.mail.transport.mockServer.MockSmtpServer; +import com.fsck.k9.mail.transport.smtp.SmtpTransport; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; -import org.robolectric.annotation.Config; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportUriTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportUriTest.java similarity index 98% rename from k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportUriTest.java rename to k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportUriTest.java index 128edab0b..ecfe17e56 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportUriTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportUriTest.java @@ -1,4 +1,4 @@ -package com.fsck.k9.mail.transport; +package com.fsck.k9.mail.transport.smtp; import android.annotation.SuppressLint; @@ -6,6 +6,7 @@ import com.fsck.k9.mail.AuthType; import com.fsck.k9.mail.ConnectionSecurity; import com.fsck.k9.mail.ServerSettings; +import com.fsck.k9.mail.transport.smtp.SmtpTransport; import org.junit.Test; import static org.junit.Assert.assertEquals; From 7f7a8902a9ae2cfa2c8ffa062aef3ff2754e4f61 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 14 Mar 2017 05:00:15 +0100 Subject: [PATCH 6/9] Extract classes --- .../EnhancedNegativeSmtpReplyException.java | 17 ++ .../smtp/NegativeSmtpReplyException.java | 35 ++++ .../smtp/SmtpEnhancedStatusCodeClass.java | 22 +++ .../smtp/SmtpEnhancedStatusCodeDetail.java | 78 +++++++++ .../smtp/SmtpEnhancedStatusCodeSubject.java | 23 +++ .../k9/mail/transport/smtp/SmtpTransport.java | 162 ------------------ .../transport/smtp/SmtpTransportTest.java | 3 +- 7 files changed, 176 insertions(+), 164 deletions(-) create mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/EnhancedNegativeSmtpReplyException.java create mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/NegativeSmtpReplyException.java create mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeClass.java create mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeDetail.java create mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeSubject.java diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/EnhancedNegativeSmtpReplyException.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/EnhancedNegativeSmtpReplyException.java new file mode 100644 index 000000000..ca0ce8ef1 --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/EnhancedNegativeSmtpReplyException.java @@ -0,0 +1,17 @@ +package com.fsck.k9.mail.transport.smtp; + + +class EnhancedNegativeSmtpReplyException extends NegativeSmtpReplyException { + + private final SmtpEnhancedStatusCodeClass escClass; + private final SmtpEnhancedStatusCodeSubject escSubject; + private final SmtpEnhancedStatusCodeDetail escDetail; + + public EnhancedNegativeSmtpReplyException(int replyCode, SmtpEnhancedStatusCodeClass escClass, + SmtpEnhancedStatusCodeSubject escSubject, SmtpEnhancedStatusCodeDetail escDetail, String replyText) { + super(replyCode, replyText); + this.escClass = escClass; + this.escSubject = escSubject; + this.escDetail = escDetail; + } +} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/NegativeSmtpReplyException.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/NegativeSmtpReplyException.java new file mode 100644 index 000000000..8cf16a312 --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/NegativeSmtpReplyException.java @@ -0,0 +1,35 @@ +package com.fsck.k9.mail.transport.smtp; + + +import com.fsck.k9.mail.MessagingException; + + +/** + * Exception that is thrown when the server sends a negative reply (reply codes 4xx or 5xx). + */ +class NegativeSmtpReplyException extends MessagingException { + private static final long serialVersionUID = 8696043577357897135L; + + private final int mReplyCode; + private final String mReplyText; + + public NegativeSmtpReplyException(int replyCode, String replyText) { + super((replyText != null && !replyText.isEmpty()) ? + replyText : ("Negative SMTP reply: " + replyCode), + isPermanentSmtpError(replyCode)); + mReplyCode = replyCode; + mReplyText = replyText; + } + + private static boolean isPermanentSmtpError(int replyCode) { + return replyCode >= 500 && replyCode <= 599; + } + + public int getReplyCode() { + return mReplyCode; + } + + public String getReplyText() { + return mReplyText; + } +} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeClass.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeClass.java new file mode 100644 index 000000000..da33a8fe8 --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeClass.java @@ -0,0 +1,22 @@ +package com.fsck.k9.mail.transport.smtp; + + +enum SmtpEnhancedStatusCodeClass { + Success(2), PersistentTransientFailure(4), PermanentFailure(5); + + private final int codeClass; + + public static SmtpEnhancedStatusCodeClass parse(String s) { + int value = Integer.parseInt(s); + for (SmtpEnhancedStatusCodeClass classEnum: SmtpEnhancedStatusCodeClass.values()) { + if (classEnum.codeClass == value) { + return classEnum; + } + } + return null; + } + + SmtpEnhancedStatusCodeClass(int codeClass) { + this.codeClass = codeClass; + } +} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeDetail.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeDetail.java new file mode 100644 index 000000000..0b2117aeb --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeDetail.java @@ -0,0 +1,78 @@ +package com.fsck.k9.mail.transport.smtp; + + +enum SmtpEnhancedStatusCodeDetail { + Undefined(SmtpEnhancedStatusCodeSubject.Undefined, 0), + OtherAddressStatus(SmtpEnhancedStatusCodeSubject.Addressing, 0), + BadDestinationMailboxAddress(SmtpEnhancedStatusCodeSubject.Addressing, 1), + BadDestinationSystemAddress(SmtpEnhancedStatusCodeSubject.Addressing, 2), + BadDestinationMailboxAddressSyntax(SmtpEnhancedStatusCodeSubject.Addressing, 3), + DestinationMailboxAddressAmbiguous(SmtpEnhancedStatusCodeSubject.Addressing, 4), + DestinationAddressValid(SmtpEnhancedStatusCodeSubject.Addressing, 5), + DestinationMailboxMoved(SmtpEnhancedStatusCodeSubject.Addressing, 6), + BadSenderMailboxSyntax(SmtpEnhancedStatusCodeSubject.Addressing, 7), + BadSenderSystemAddress(SmtpEnhancedStatusCodeSubject.Addressing, 8), + + OtherMailboxStatus(SmtpEnhancedStatusCodeSubject.Mailbox,0), + MailboxDisabled(SmtpEnhancedStatusCodeSubject.Mailbox,1), + MailboxFull(SmtpEnhancedStatusCodeSubject.Mailbox,2), + MessageLengthExceeded(SmtpEnhancedStatusCodeSubject.Mailbox,3), + MailingListExpansionProblem(SmtpEnhancedStatusCodeSubject.Mailbox,4), + + OtherMailSystemStatus(SmtpEnhancedStatusCodeSubject.MailSystem,0), + MailSystemFull(SmtpEnhancedStatusCodeSubject.MailSystem,1), + SystemNotAcceptingMessages(SmtpEnhancedStatusCodeSubject.MailSystem,2), + SystemIncapableOfFeature(SmtpEnhancedStatusCodeSubject.MailSystem,3), + MessageTooBig(SmtpEnhancedStatusCodeSubject.MailSystem,4), + SystemIncorrectlyConfigured(SmtpEnhancedStatusCodeSubject.MailSystem,5), + + OtherNetworkRouting(SmtpEnhancedStatusCodeSubject.NetworkRouting,0), + NoAnswerFromHost(SmtpEnhancedStatusCodeSubject.NetworkRouting,1), + BadConnection(SmtpEnhancedStatusCodeSubject.NetworkRouting,2), + DirectoryServerFailure(SmtpEnhancedStatusCodeSubject.NetworkRouting,3), + UnableToRoute(SmtpEnhancedStatusCodeSubject.NetworkRouting,4), + MailSystemCongestion(SmtpEnhancedStatusCodeSubject.NetworkRouting,5), + RoutingLoopDetected(SmtpEnhancedStatusCodeSubject.NetworkRouting,6), + DeliveryTimeExpired(SmtpEnhancedStatusCodeSubject.NetworkRouting,7), + + OtherMailDeliveryProtocol(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,0), + InvalidCommand(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,1), + SyntaxError(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,2), + TooManyRecipients(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,3), + InvalidCommandArguments(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,4), + WrongProtocolVersion(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,5), + + OtherMessageContentOrMedia(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,0), + MediaNotSupported(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,1), + ConversionRequiredAndProhibited(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,2), + ConversionRequiredButUnsupported(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,3), + ConversionWithLossPerformed(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,4), + ConversionFailed(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,5), + + OtherSecurityOrPolicyStatus(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 0), + DeliveryNotAuthorized(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 1), + MailingListExpansionProhibited(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 2), + SecurityConversionRequired(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 3), + SecurityFeaturesUnsupported(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 4), + CryptographicFailure(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 5), + CryptographicAlgorithmUnsupported(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 6), + MessageIntegrityFailure(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 7); + + private final SmtpEnhancedStatusCodeSubject subject; + private final int detail; + + SmtpEnhancedStatusCodeDetail(SmtpEnhancedStatusCodeSubject subject, int detail) { + this.subject = subject; + this.detail = detail; + } + + public static SmtpEnhancedStatusCodeDetail parse(SmtpEnhancedStatusCodeSubject subject, String s) { + int value = Integer.parseInt(s); + for (SmtpEnhancedStatusCodeDetail detailEnum: SmtpEnhancedStatusCodeDetail.values()) { + if (detailEnum.subject == subject && detailEnum.detail == value) { + return detailEnum; + } + } + return null; + } +} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeSubject.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeSubject.java new file mode 100644 index 000000000..e12f2c29e --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeSubject.java @@ -0,0 +1,23 @@ +package com.fsck.k9.mail.transport.smtp; + + +enum SmtpEnhancedStatusCodeSubject { + Undefined(0), Addressing(1), Mailbox(2), MailSystem(3), NetworkRouting(4), + MailDeliveryProtocol(5), MessageContentOrMedia(6), SecurityOrPolicyStatus(7); + + private final int codeSubject; + + public static SmtpEnhancedStatusCodeSubject parse(String s) { + int value = Integer.parseInt(s); + for (SmtpEnhancedStatusCodeSubject classEnum: SmtpEnhancedStatusCodeSubject.values()) { + if (classEnum.codeSubject == value) { + return classEnum; + } + } + return null; + } + + SmtpEnhancedStatusCodeSubject(int codeSubject) { + this.codeSubject = codeSubject; + } +} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java index 21c9ea013..bf61de13c 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java @@ -899,166 +899,4 @@ public class SmtpTransport extends Transport { protected String getCanonicalHostName(InetAddress localAddress) { return localAddress.getCanonicalHostName(); } - - /** - * Exception that is thrown when the server sends a negative reply (reply codes 4xx or 5xx). - */ - static class NegativeSmtpReplyException extends MessagingException { - private static final long serialVersionUID = 8696043577357897135L; - - private final int mReplyCode; - private final String mReplyText; - - public NegativeSmtpReplyException(int replyCode, String replyText) { - super((replyText != null && !replyText.isEmpty()) ? - replyText : ("Negative SMTP reply: " + replyCode), - isPermanentSmtpError(replyCode)); - mReplyCode = replyCode; - mReplyText = replyText; - } - - private static boolean isPermanentSmtpError(int replyCode) { - return replyCode >= 500 && replyCode <= 599; - } - - public int getReplyCode() { - return mReplyCode; - } - - public String getReplyText() { - return mReplyText; - } - } - - static class EnhancedNegativeSmtpReplyException extends NegativeSmtpReplyException { - - private final SmtpEnhancedStatusCodeClass escClass; - private final SmtpEnhancedStatusCodeSubject escSubject; - private final SmtpEnhancedStatusCodeDetail escDetail; - - public EnhancedNegativeSmtpReplyException(int replyCode, SmtpEnhancedStatusCodeClass escClass, - SmtpEnhancedStatusCodeSubject escSubject, SmtpEnhancedStatusCodeDetail escDetail, String replyText) { - super(replyCode, replyText); - this.escClass = escClass; - this.escSubject = escSubject; - this.escDetail = escDetail; - } - } - - enum SmtpEnhancedStatusCodeClass { - Success(2), PersistentTransientFailure(4), PermanentFailure(5); - - private final int codeClass; - - public static SmtpEnhancedStatusCodeClass parse(String s) { - int value = Integer.parseInt(s); - for (SmtpEnhancedStatusCodeClass classEnum: SmtpEnhancedStatusCodeClass.values()) { - if (classEnum.codeClass == value) { - return classEnum; - } - } - return null; - } - - SmtpEnhancedStatusCodeClass(int codeClass) { - this.codeClass = codeClass; - } - } - - enum SmtpEnhancedStatusCodeSubject { - Undefined(0), Addressing(1), Mailbox(2), MailSystem(3), NetworkRouting(4), - MailDeliveryProtocol(5), MessageContentOrMedia(6), SecurityOrPolicyStatus(7); - - private final int codeSubject; - - public static SmtpEnhancedStatusCodeSubject parse(String s) { - int value = Integer.parseInt(s); - for (SmtpEnhancedStatusCodeSubject classEnum: SmtpEnhancedStatusCodeSubject.values()) { - if (classEnum.codeSubject == value) { - return classEnum; - } - } - return null; - } - - SmtpEnhancedStatusCodeSubject(int codeSubject) { - this.codeSubject = codeSubject; - } - } - - enum SmtpEnhancedStatusCodeDetail { - Undefined(SmtpEnhancedStatusCodeSubject.Undefined, 0), - OtherAddressStatus(SmtpEnhancedStatusCodeSubject.Addressing, 0), - BadDestinationMailboxAddress(SmtpEnhancedStatusCodeSubject.Addressing, 1), - BadDestinationSystemAddress(SmtpEnhancedStatusCodeSubject.Addressing, 2), - BadDestinationMailboxAddressSyntax(SmtpEnhancedStatusCodeSubject.Addressing, 3), - DestinationMailboxAddressAmbiguous(SmtpEnhancedStatusCodeSubject.Addressing, 4), - DestinationAddressValid(SmtpEnhancedStatusCodeSubject.Addressing, 5), - DestinationMailboxMoved(SmtpEnhancedStatusCodeSubject.Addressing, 6), - BadSenderMailboxSyntax(SmtpEnhancedStatusCodeSubject.Addressing, 7), - BadSenderSystemAddress(SmtpEnhancedStatusCodeSubject.Addressing, 8), - - OtherMailboxStatus(SmtpEnhancedStatusCodeSubject.Mailbox,0), - MailboxDisabled(SmtpEnhancedStatusCodeSubject.Mailbox,1), - MailboxFull(SmtpEnhancedStatusCodeSubject.Mailbox,2), - MessageLengthExceeded(SmtpEnhancedStatusCodeSubject.Mailbox,3), - MailingListExpansionProblem(SmtpEnhancedStatusCodeSubject.Mailbox,4), - - OtherMailSystemStatus(SmtpEnhancedStatusCodeSubject.MailSystem,0), - MailSystemFull(SmtpEnhancedStatusCodeSubject.MailSystem,1), - SystemNotAcceptingMessages(SmtpEnhancedStatusCodeSubject.MailSystem,2), - SystemIncapableOfFeature(SmtpEnhancedStatusCodeSubject.MailSystem,3), - MessageTooBig(SmtpEnhancedStatusCodeSubject.MailSystem,4), - SystemIncorrectlyConfigured(SmtpEnhancedStatusCodeSubject.MailSystem,5), - - OtherNetworkRouting(SmtpEnhancedStatusCodeSubject.NetworkRouting,0), - NoAnswerFromHost(SmtpEnhancedStatusCodeSubject.NetworkRouting,1), - BadConnection(SmtpEnhancedStatusCodeSubject.NetworkRouting,2), - DirectoryServerFailure(SmtpEnhancedStatusCodeSubject.NetworkRouting,3), - UnableToRoute(SmtpEnhancedStatusCodeSubject.NetworkRouting,4), - MailSystemCongestion(SmtpEnhancedStatusCodeSubject.NetworkRouting,5), - RoutingLoopDetected(SmtpEnhancedStatusCodeSubject.NetworkRouting,6), - DeliveryTimeExpired(SmtpEnhancedStatusCodeSubject.NetworkRouting,7), - - OtherMailDeliveryProtocol(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,0), - InvalidCommand(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,1), - SyntaxError(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,2), - TooManyRecipients(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,3), - InvalidCommandArguments(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,4), - WrongProtocolVersion(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,5), - - OtherMessageContentOrMedia(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,0), - MediaNotSupported(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,1), - ConversionRequiredAndProhibited(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,2), - ConversionRequiredButUnsupported(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,3), - ConversionWithLossPerformed(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,4), - ConversionFailed(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,5), - - OtherSecurityOrPolicyStatus(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 0), - DeliveryNotAuthorized(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 1), - MailingListExpansionProhibited(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 2), - SecurityConversionRequired(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 3), - SecurityFeaturesUnsupported(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 4), - CryptographicFailure(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 5), - CryptographicAlgorithmUnsupported(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 6), - MessageIntegrityFailure(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 7); - - private final SmtpEnhancedStatusCodeSubject subject; - private final int detail; - - SmtpEnhancedStatusCodeDetail(SmtpEnhancedStatusCodeSubject subject, int detail) { - this.subject = subject; - this.detail = detail; - } - - public static SmtpEnhancedStatusCodeDetail parse(SmtpEnhancedStatusCodeSubject subject, String s) { - int value = Integer.parseInt(s); - for (SmtpEnhancedStatusCodeDetail detailEnum: SmtpEnhancedStatusCodeDetail.values()) { - if (detailEnum.subject == subject && detailEnum.detail == value) { - return detailEnum; - } - } - return null; - } - } } diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java index 783812eae..ed26ae9d4 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java @@ -22,7 +22,6 @@ import com.fsck.k9.mail.oauth.OAuth2TokenProvider; import com.fsck.k9.mail.ssl.TrustedSocketFactory; import com.fsck.k9.mail.store.StoreConfig; import com.fsck.k9.mail.transport.mockServer.MockSmtpServer; -import com.fsck.k9.mail.transport.smtp.SmtpTransport; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -680,7 +679,7 @@ public class SmtpTransportTest { try { transport.sendMessage(message); fail("Expected exception"); - } catch (SmtpTransport.NegativeSmtpReplyException e) { + } catch (NegativeSmtpReplyException e) { assertEquals(421, e.getReplyCode()); assertEquals("4.7.0 Temporary system problem", e.getReplyText()); } From 188720d7ff69ea808f62bcc83026614801a84b2c Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 14 Mar 2017 06:34:32 +0100 Subject: [PATCH 7/9] Code cleanup --- .../EnhancedNegativeSmtpReplyException.java | 17 ++-- .../smtp/NegativeSmtpReplyException.java | 24 +++--- .../smtp/SmtpEnhancedStatusCodeClass.java | 22 ----- .../smtp/SmtpEnhancedStatusCodeDetail.java | 78 ------------------ .../smtp/SmtpEnhancedStatusCodeSubject.java | 23 ------ .../k9/mail/transport/smtp/SmtpTransport.java | 19 ++--- .../mail/transport/smtp/StatusCodeClass.java | 26 ++++++ .../mail/transport/smtp/StatusCodeDetail.java | 80 +++++++++++++++++++ .../transport/smtp/StatusCodeSubject.java | 31 +++++++ 9 files changed, 171 insertions(+), 149 deletions(-) delete mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeClass.java delete mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeDetail.java delete mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeSubject.java create mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeClass.java create mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeDetail.java create mode 100644 k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeSubject.java diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/EnhancedNegativeSmtpReplyException.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/EnhancedNegativeSmtpReplyException.java index ca0ce8ef1..7be1e11f7 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/EnhancedNegativeSmtpReplyException.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/EnhancedNegativeSmtpReplyException.java @@ -2,16 +2,17 @@ package com.fsck.k9.mail.transport.smtp; class EnhancedNegativeSmtpReplyException extends NegativeSmtpReplyException { + private final StatusCodeClass statusCodeClass; + private final StatusCodeSubject statusCodeSubject; + private final StatusCodeDetail statusCodeDetail; - private final SmtpEnhancedStatusCodeClass escClass; - private final SmtpEnhancedStatusCodeSubject escSubject; - private final SmtpEnhancedStatusCodeDetail escDetail; - public EnhancedNegativeSmtpReplyException(int replyCode, SmtpEnhancedStatusCodeClass escClass, - SmtpEnhancedStatusCodeSubject escSubject, SmtpEnhancedStatusCodeDetail escDetail, String replyText) { + EnhancedNegativeSmtpReplyException(int replyCode, StatusCodeClass statusCodeClass, + StatusCodeSubject statusCodeSubject, StatusCodeDetail statusCodeDetail, + String replyText) { super(replyCode, replyText); - this.escClass = escClass; - this.escSubject = escSubject; - this.escDetail = escDetail; + this.statusCodeClass = statusCodeClass; + this.statusCodeSubject = statusCodeSubject; + this.statusCodeDetail = statusCodeDetail; } } diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/NegativeSmtpReplyException.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/NegativeSmtpReplyException.java index 8cf16a312..4a822030f 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/NegativeSmtpReplyException.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/NegativeSmtpReplyException.java @@ -1,6 +1,8 @@ package com.fsck.k9.mail.transport.smtp; +import android.text.TextUtils; + import com.fsck.k9.mail.MessagingException; @@ -10,15 +12,19 @@ import com.fsck.k9.mail.MessagingException; class NegativeSmtpReplyException extends MessagingException { private static final long serialVersionUID = 8696043577357897135L; - private final int mReplyCode; - private final String mReplyText; + + private final int replyCode; + private final String replyText; + public NegativeSmtpReplyException(int replyCode, String replyText) { - super((replyText != null && !replyText.isEmpty()) ? - replyText : ("Negative SMTP reply: " + replyCode), - isPermanentSmtpError(replyCode)); - mReplyCode = replyCode; - mReplyText = replyText; + super(buildErrorMessage(replyCode, replyText), isPermanentSmtpError(replyCode)); + this.replyCode = replyCode; + this.replyText = replyText; + } + + private static String buildErrorMessage(int replyCode, String replyText) { + return TextUtils.isEmpty(replyText) ? "Negative SMTP reply: " + replyCode : replyText; } private static boolean isPermanentSmtpError(int replyCode) { @@ -26,10 +32,10 @@ class NegativeSmtpReplyException extends MessagingException { } public int getReplyCode() { - return mReplyCode; + return replyCode; } public String getReplyText() { - return mReplyText; + return replyText; } } diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeClass.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeClass.java deleted file mode 100644 index da33a8fe8..000000000 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeClass.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.fsck.k9.mail.transport.smtp; - - -enum SmtpEnhancedStatusCodeClass { - Success(2), PersistentTransientFailure(4), PermanentFailure(5); - - private final int codeClass; - - public static SmtpEnhancedStatusCodeClass parse(String s) { - int value = Integer.parseInt(s); - for (SmtpEnhancedStatusCodeClass classEnum: SmtpEnhancedStatusCodeClass.values()) { - if (classEnum.codeClass == value) { - return classEnum; - } - } - return null; - } - - SmtpEnhancedStatusCodeClass(int codeClass) { - this.codeClass = codeClass; - } -} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeDetail.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeDetail.java deleted file mode 100644 index 0b2117aeb..000000000 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeDetail.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.fsck.k9.mail.transport.smtp; - - -enum SmtpEnhancedStatusCodeDetail { - Undefined(SmtpEnhancedStatusCodeSubject.Undefined, 0), - OtherAddressStatus(SmtpEnhancedStatusCodeSubject.Addressing, 0), - BadDestinationMailboxAddress(SmtpEnhancedStatusCodeSubject.Addressing, 1), - BadDestinationSystemAddress(SmtpEnhancedStatusCodeSubject.Addressing, 2), - BadDestinationMailboxAddressSyntax(SmtpEnhancedStatusCodeSubject.Addressing, 3), - DestinationMailboxAddressAmbiguous(SmtpEnhancedStatusCodeSubject.Addressing, 4), - DestinationAddressValid(SmtpEnhancedStatusCodeSubject.Addressing, 5), - DestinationMailboxMoved(SmtpEnhancedStatusCodeSubject.Addressing, 6), - BadSenderMailboxSyntax(SmtpEnhancedStatusCodeSubject.Addressing, 7), - BadSenderSystemAddress(SmtpEnhancedStatusCodeSubject.Addressing, 8), - - OtherMailboxStatus(SmtpEnhancedStatusCodeSubject.Mailbox,0), - MailboxDisabled(SmtpEnhancedStatusCodeSubject.Mailbox,1), - MailboxFull(SmtpEnhancedStatusCodeSubject.Mailbox,2), - MessageLengthExceeded(SmtpEnhancedStatusCodeSubject.Mailbox,3), - MailingListExpansionProblem(SmtpEnhancedStatusCodeSubject.Mailbox,4), - - OtherMailSystemStatus(SmtpEnhancedStatusCodeSubject.MailSystem,0), - MailSystemFull(SmtpEnhancedStatusCodeSubject.MailSystem,1), - SystemNotAcceptingMessages(SmtpEnhancedStatusCodeSubject.MailSystem,2), - SystemIncapableOfFeature(SmtpEnhancedStatusCodeSubject.MailSystem,3), - MessageTooBig(SmtpEnhancedStatusCodeSubject.MailSystem,4), - SystemIncorrectlyConfigured(SmtpEnhancedStatusCodeSubject.MailSystem,5), - - OtherNetworkRouting(SmtpEnhancedStatusCodeSubject.NetworkRouting,0), - NoAnswerFromHost(SmtpEnhancedStatusCodeSubject.NetworkRouting,1), - BadConnection(SmtpEnhancedStatusCodeSubject.NetworkRouting,2), - DirectoryServerFailure(SmtpEnhancedStatusCodeSubject.NetworkRouting,3), - UnableToRoute(SmtpEnhancedStatusCodeSubject.NetworkRouting,4), - MailSystemCongestion(SmtpEnhancedStatusCodeSubject.NetworkRouting,5), - RoutingLoopDetected(SmtpEnhancedStatusCodeSubject.NetworkRouting,6), - DeliveryTimeExpired(SmtpEnhancedStatusCodeSubject.NetworkRouting,7), - - OtherMailDeliveryProtocol(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,0), - InvalidCommand(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,1), - SyntaxError(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,2), - TooManyRecipients(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,3), - InvalidCommandArguments(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,4), - WrongProtocolVersion(SmtpEnhancedStatusCodeSubject.MailDeliveryProtocol,5), - - OtherMessageContentOrMedia(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,0), - MediaNotSupported(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,1), - ConversionRequiredAndProhibited(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,2), - ConversionRequiredButUnsupported(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,3), - ConversionWithLossPerformed(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,4), - ConversionFailed(SmtpEnhancedStatusCodeSubject.MessageContentOrMedia,5), - - OtherSecurityOrPolicyStatus(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 0), - DeliveryNotAuthorized(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 1), - MailingListExpansionProhibited(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 2), - SecurityConversionRequired(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 3), - SecurityFeaturesUnsupported(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 4), - CryptographicFailure(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 5), - CryptographicAlgorithmUnsupported(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 6), - MessageIntegrityFailure(SmtpEnhancedStatusCodeSubject.SecurityOrPolicyStatus, 7); - - private final SmtpEnhancedStatusCodeSubject subject; - private final int detail; - - SmtpEnhancedStatusCodeDetail(SmtpEnhancedStatusCodeSubject subject, int detail) { - this.subject = subject; - this.detail = detail; - } - - public static SmtpEnhancedStatusCodeDetail parse(SmtpEnhancedStatusCodeSubject subject, String s) { - int value = Integer.parseInt(s); - for (SmtpEnhancedStatusCodeDetail detailEnum: SmtpEnhancedStatusCodeDetail.values()) { - if (detailEnum.subject == subject && detailEnum.detail == value) { - return detailEnum; - } - } - return null; - } -} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeSubject.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeSubject.java deleted file mode 100644 index e12f2c29e..000000000 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpEnhancedStatusCodeSubject.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.fsck.k9.mail.transport.smtp; - - -enum SmtpEnhancedStatusCodeSubject { - Undefined(0), Addressing(1), Mailbox(2), MailSystem(3), NetworkRouting(4), - MailDeliveryProtocol(5), MessageContentOrMedia(6), SecurityOrPolicyStatus(7); - - private final int codeSubject; - - public static SmtpEnhancedStatusCodeSubject parse(String s) { - int value = Integer.parseInt(s); - for (SmtpEnhancedStatusCodeSubject classEnum: SmtpEnhancedStatusCodeSubject.values()) { - if (classEnum.codeSubject == value) { - return classEnum; - } - } - return null; - } - - SmtpEnhancedStatusCodeSubject(int codeSubject) { - this.codeSubject = codeSubject; - } -} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java index bf61de13c..e6e6e2d86 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java @@ -712,23 +712,24 @@ public class SmtpTransport extends Transport { } private MessagingException buildEnhancedNegativeSmtpReplyException(int replyCode, List results) { - SmtpEnhancedStatusCodeClass escClass = null; - SmtpEnhancedStatusCodeSubject escSubject = null; - SmtpEnhancedStatusCodeDetail escDetail = null; + StatusCodeClass statusCodeClass = null; + StatusCodeSubject statusCodeSubject = null; + StatusCodeDetail statusCodeDetail = null; String message = ""; - for (String resultLine: results) { + for (String resultLine : results) { message += resultLine.split(" ", 2)[1] + " "; } if (results.size() > 0) { - String[] esc = results.get(0).split(" ", 2)[0].split("\\."); + String[] statusCodeParts = results.get(0).split(" ", 2)[0].split("\\."); - escClass = SmtpEnhancedStatusCodeClass.parse(esc[0]); - escSubject = SmtpEnhancedStatusCodeSubject.parse(esc[1]); - escDetail = SmtpEnhancedStatusCodeDetail.parse(escSubject, esc[2]); + statusCodeClass = StatusCodeClass.parse(statusCodeParts[0]); + statusCodeSubject = StatusCodeSubject.parse(statusCodeParts[1]); + statusCodeDetail = StatusCodeDetail.parse(statusCodeSubject, statusCodeParts[2]); } - return new EnhancedNegativeSmtpReplyException(replyCode, escClass, escSubject, escDetail, message.trim()); + return new EnhancedNegativeSmtpReplyException(replyCode, statusCodeClass, statusCodeSubject, statusCodeDetail, + message.trim()); } diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeClass.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeClass.java new file mode 100644 index 000000000..f56f28942 --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeClass.java @@ -0,0 +1,26 @@ +package com.fsck.k9.mail.transport.smtp; + + +enum StatusCodeClass { + SUCCESS(2), + PERSISTENT_TRANSIENT_FAILURE(4), + PERMANENT_FAILURE(5); + + + private final int codeClass; + + + static StatusCodeClass parse(String statusCodeClassString) { + int value = Integer.parseInt(statusCodeClassString); + for (StatusCodeClass classEnum : StatusCodeClass.values()) { + if (classEnum.codeClass == value) { + return classEnum; + } + } + return null; + } + + StatusCodeClass(int codeClass) { + this.codeClass = codeClass; + } +} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeDetail.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeDetail.java new file mode 100644 index 000000000..92de6967e --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeDetail.java @@ -0,0 +1,80 @@ +package com.fsck.k9.mail.transport.smtp; + + +enum StatusCodeDetail { + UNDEFINED(StatusCodeSubject.UNDEFINED, 0), + OTHER_ADDRESS_STATUS(StatusCodeSubject.ADDRESSING, 0), + BAD_DESTINATION_MAILBOX_ADDRESS(StatusCodeSubject.ADDRESSING, 1), + BAD_DESTINATION_SYSTEM_ADDRESS(StatusCodeSubject.ADDRESSING, 2), + BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX(StatusCodeSubject.ADDRESSING, 3), + DESTINATION_MAILBOX_ADDRESS_AMBIGUOUS(StatusCodeSubject.ADDRESSING, 4), + DESTINATION_ADDRESS_VALID(StatusCodeSubject.ADDRESSING, 5), + DESTINATION_MAILBOX_MOVED(StatusCodeSubject.ADDRESSING, 6), + BAD_SENDER_MAILBOX_SYNTAX(StatusCodeSubject.ADDRESSING, 7), + BAD_SENDER_SYSTEM_ADDRESS(StatusCodeSubject.ADDRESSING, 8), + + OTHER_MAILBOX_STATUS(StatusCodeSubject.MAILBOX,0), + MAILBOX_DISABLED(StatusCodeSubject.MAILBOX,1), + MAILBOX_FULL(StatusCodeSubject.MAILBOX,2), + MESSAGE_LENGTH_EXCEEDED(StatusCodeSubject.MAILBOX,3), + MAILING_LIST_EXPANSION_PROBLEM(StatusCodeSubject.MAILBOX,4), + + OTHER_MAIL_SYSTEM_STATUS(StatusCodeSubject.MAIL_SYSTEM,0), + MAIL_SYSTEM_FULL(StatusCodeSubject.MAIL_SYSTEM,1), + SYSTEM_NOT_ACCEPTING_MESSAGES(StatusCodeSubject.MAIL_SYSTEM,2), + SYSTEM_INCAPABLE_OF_FEATURE(StatusCodeSubject.MAIL_SYSTEM,3), + MESSAGE_TOO_BIG(StatusCodeSubject.MAIL_SYSTEM,4), + SYSTEM_INCORRECTLY_CONFIGURED(StatusCodeSubject.MAIL_SYSTEM,5), + + OTHER_NETWORK_ROUTING(StatusCodeSubject.NETWORK_ROUTING,0), + NO_ANSWER_FROM_HOST(StatusCodeSubject.NETWORK_ROUTING,1), + BAD_CONNECTION(StatusCodeSubject.NETWORK_ROUTING,2), + DIRECTORY_SERVER_FAILURE(StatusCodeSubject.NETWORK_ROUTING,3), + UNABLE_TO_ROUTE(StatusCodeSubject.NETWORK_ROUTING,4), + MAIL_SYSTEM_CONGESTION(StatusCodeSubject.NETWORK_ROUTING,5), + ROUTING_LOOP_DETECTED(StatusCodeSubject.NETWORK_ROUTING,6), + DELIVERY_TIME_EXPIRED(StatusCodeSubject.NETWORK_ROUTING,7), + + OTHER_MAIL_DELIVERY_PROTOCOL(StatusCodeSubject.MAIL_DELIVERY_PROTOCOL,0), + INVALID_COMMAND(StatusCodeSubject.MAIL_DELIVERY_PROTOCOL,1), + SYNTAX_ERROR(StatusCodeSubject.MAIL_DELIVERY_PROTOCOL,2), + TOO_MANY_RECIPIENTS(StatusCodeSubject.MAIL_DELIVERY_PROTOCOL,3), + INVALID_COMMAND_ARGUMENTS(StatusCodeSubject.MAIL_DELIVERY_PROTOCOL,4), + WRONG_PROTOCOL_VERSION(StatusCodeSubject.MAIL_DELIVERY_PROTOCOL,5), + + OTHER_MESSAGE_CONTENT_OR_MEDIA(StatusCodeSubject.MESSAGE_CONTENT_OR_MEDIA,0), + MEDIA_NOT_SUPPORTED(StatusCodeSubject.MESSAGE_CONTENT_OR_MEDIA,1), + CONVERSION_REQUIRED_AND_PROHIBITED(StatusCodeSubject.MESSAGE_CONTENT_OR_MEDIA,2), + CONVERSION_REQUIRED_BUT_UNSUPPORTED(StatusCodeSubject.MESSAGE_CONTENT_OR_MEDIA,3), + CONVERSION_WITH_LOSS_PERFORMED(StatusCodeSubject.MESSAGE_CONTENT_OR_MEDIA,4), + CONVERSION_FAILED(StatusCodeSubject.MESSAGE_CONTENT_OR_MEDIA,5), + + OTHER_SECURITY_OR_POLICY_STATUS(StatusCodeSubject.SECURITY_OR_POLICY_STATUS, 0), + DELIVERY_NOT_AUTHORIZED(StatusCodeSubject.SECURITY_OR_POLICY_STATUS, 1), + MAILING_LIST_EXPANSION_PROHIBITED(StatusCodeSubject.SECURITY_OR_POLICY_STATUS, 2), + SECURITY_CONVERSION_REQUIRED(StatusCodeSubject.SECURITY_OR_POLICY_STATUS, 3), + SECURITY_FEATURES_UNSUPPORTED(StatusCodeSubject.SECURITY_OR_POLICY_STATUS, 4), + CRYPTOGRAPHIC_FAILURE(StatusCodeSubject.SECURITY_OR_POLICY_STATUS, 5), + CRYPTOGRAPHIC_ALGORITHM_UNSUPPORTED(StatusCodeSubject.SECURITY_OR_POLICY_STATUS, 6), + MESSAGE_INTEGRITY_FAILURE(StatusCodeSubject.SECURITY_OR_POLICY_STATUS, 7); + + + private final StatusCodeSubject subject; + private final int detail; + + + public static StatusCodeDetail parse(StatusCodeSubject statusCodeSubject, String statusCodeDetailString) { + int value = Integer.parseInt(statusCodeDetailString); + for (StatusCodeDetail detailEnum : StatusCodeDetail.values()) { + if (detailEnum.subject == statusCodeSubject && detailEnum.detail == value) { + return detailEnum; + } + } + return null; + } + + StatusCodeDetail(StatusCodeSubject subject, int detail) { + this.subject = subject; + this.detail = detail; + } +} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeSubject.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeSubject.java new file mode 100644 index 000000000..ff004f306 --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/StatusCodeSubject.java @@ -0,0 +1,31 @@ +package com.fsck.k9.mail.transport.smtp; + + +enum StatusCodeSubject { + UNDEFINED(0), + ADDRESSING(1), + MAILBOX(2), + MAIL_SYSTEM(3), + NETWORK_ROUTING(4), + MAIL_DELIVERY_PROTOCOL(5), + MESSAGE_CONTENT_OR_MEDIA(6), + SECURITY_OR_POLICY_STATUS(7); + + + private final int codeSubject; + + + static StatusCodeSubject parse(String statusCodeSubjectString) { + int value = Integer.parseInt(statusCodeSubjectString); + for (StatusCodeSubject classEnum : StatusCodeSubject.values()) { + if (classEnum.codeSubject == value) { + return classEnum; + } + } + return null; + } + + StatusCodeSubject(int codeSubject) { + this.codeSubject = codeSubject; + } +} From 481823c7d8d35bf14165af2907713b38ea52c0d8 Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Tue, 14 Mar 2017 17:06:08 +0000 Subject: [PATCH 8/9] Refactor variable name --- .../java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java index e6e6e2d86..8e1292747 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java @@ -698,8 +698,8 @@ public class SmtpTransport extends Transport { } catch (NumberFormatException e) { /* ignore */ } } - char c = line.charAt(0); - if ((c == '4') || (c == '5')) { + char replyCodeCategory = line.charAt(0); + if ((replyCodeCategory == '4') || (replyCodeCategory == '5')) { if (mEnhancedStatusCodesProvided) { throw buildEnhancedNegativeSmtpReplyException(replyCode, results); } else { From 71a6cd3d9eb02fcb82d806d9c0b38d7fd1000a7f Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Tue, 14 Mar 2017 17:19:44 +0000 Subject: [PATCH 9/9] Add extra variable for clarity --- .../java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java index 8e1292747..5d3635e00 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java @@ -699,7 +699,8 @@ public class SmtpTransport extends Transport { } char replyCodeCategory = line.charAt(0); - if ((replyCodeCategory == '4') || (replyCodeCategory == '5')) { + boolean isReplyCodeErrorCategory = (replyCodeCategory == '4') || (replyCodeCategory == '5'); + if (isReplyCodeErrorCategory) { if (mEnhancedStatusCodesProvided) { throw buildEnhancedNegativeSmtpReplyException(replyCode, results); } else {