From a7898fa2eb493260e4bc105ff91608a4fd322c1b Mon Sep 17 00:00:00 2001 From: Joe Steele Date: Tue, 11 Mar 2014 19:06:00 -0400 Subject: [PATCH] Fix issue 6269: IMAP LOGIN failure Some IMAP servers are broken and don't correctly handle string literals with the LOGIN command. This switches to using quoted strings instead. This is what Thunderbird does. --- src/com/fsck/k9/mail/store/ImapStore.java | 40 ++++++++++------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index ca6c5966b..f4986d05f 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -46,6 +46,7 @@ import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; @@ -127,7 +128,6 @@ public class ImapStore extends Store { private static final String CAPABILITY_AUTH_CRAM_MD5 = "AUTH=CRAM-MD5"; private static final String CAPABILITY_AUTH_PLAIN = "AUTH=PLAIN"; private static final String CAPABILITY_LOGINDISABLED = "LOGINDISABLED"; - private static final String CAPABILITY_LITERAL_PLUS = "LITERAL+"; private static final String COMMAND_IDLE = "IDLE"; private static final String CAPABILITY_NAMESPACE = "NAMESPACE"; private static final String COMMAND_NAMESPACE = "NAMESPACE"; @@ -2655,29 +2655,23 @@ public class ImapStore extends Store { } protected void login() throws IOException, MessagingException { - boolean hasLiteralPlus = hasCapability(CAPABILITY_LITERAL_PLUS); - String tag; - byte[] username = mSettings.getUsername().getBytes(); - byte[] password = mSettings.getPassword().getBytes(); - tag = sendCommand(String.format(Locale.US, "LOGIN {%d%s}", - username.length, hasLiteralPlus ? "+" : ""), true); - if (!hasLiteralPlus) { - readContinuationResponse(tag); - } - mOut.write(username); - mOut.write(String.format(Locale.US, " {%d%s}\r\n", password.length, - hasLiteralPlus ? "+" : "").getBytes()); - if (!hasLiteralPlus) { - mOut.flush(); - readContinuationResponse(tag); - } - mOut.write(password); - mOut.write('\r'); - mOut.write('\n'); - mOut.flush(); + /* + * Use quoted strings which permit spaces and quotes. (Using IMAP + * string literals would be better, but some servers are broken + * and don't parse them correctly.) + */ + + // escape double-quotes and backslash characters with a backslash + Pattern p = Pattern.compile("[\\\\\"]"); + String replacement = "\\\\$0"; + String username = p.matcher(mSettings.getUsername()).replaceAll( + replacement); + String password = p.matcher(mSettings.getPassword()).replaceAll( + replacement); try { - receiveCapabilities(readStatusResponse(tag, "LOGIN", null)); - } catch (MessagingException e) { + receiveCapabilities(executeSimpleCommand( + String.format("LOGIN \"%s\" \"%s\"", username, password), true)); + } catch (ImapException e) { throw new AuthenticationFailedException(e.getMessage()); } }