mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 03:32:16 -05:00
Refactor IMAP code + tests
This commit is contained in:
parent
6a1fee90ee
commit
0a6920c63e
@ -33,9 +33,7 @@ import java.net.SocketException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -84,41 +82,6 @@ class ImapConnection {
|
||||
return "conn" + hashCode();
|
||||
}
|
||||
|
||||
private List<ImapResponse> receiveCapabilities(List<ImapResponse> responses) {
|
||||
for (ImapResponse response : responses) {
|
||||
ImapList capabilityList = null;
|
||||
if (!response.isEmpty() && ImapResponseParser.equalsIgnoreCase(response.get(0), "OK")) {
|
||||
for (Object thisPart : response) {
|
||||
if (thisPart instanceof ImapList) {
|
||||
ImapList thisList = (ImapList)thisPart;
|
||||
if (ImapResponseParser.equalsIgnoreCase(thisList.get(0), ImapCommands.CAPABILITY_CAPABILITY)) {
|
||||
capabilityList = thisList;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (response.mTag == null) {
|
||||
capabilityList = response;
|
||||
}
|
||||
|
||||
if (capabilityList != null && !capabilityList.isEmpty() &&
|
||||
ImapResponseParser.equalsIgnoreCase(capabilityList.get(0), ImapCommands.CAPABILITY_CAPABILITY)) {
|
||||
if (K9MailLib.isDebug()) {
|
||||
Log.d(LOG_TAG, "Saving " + capabilityList.size() + " capabilities for " + getLogId());
|
||||
}
|
||||
for (Object capability : capabilityList) {
|
||||
if (capability instanceof String) {
|
||||
// if (K9MailLib.isDebug())
|
||||
// {
|
||||
// Log.v(LOG_TAG, "Saving capability '" + capability + "' for " + getLogId());
|
||||
// }
|
||||
capabilities.add(((String)capability).toUpperCase(Locale.US));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
public void open() throws IOException, MessagingException {
|
||||
if (isOpen()) {
|
||||
@ -395,6 +358,14 @@ class ImapConnection {
|
||||
}
|
||||
}
|
||||
|
||||
private List<ImapResponse> receiveCapabilities(List<ImapResponse> responses) {
|
||||
capabilities = ImapResponseParser.parseCapabilities(responses);
|
||||
if (K9MailLib.isDebug()) {
|
||||
Log.d(LOG_TAG, "Saving " + capabilities + " capabilities for " + getLogId());
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
protected void login() throws IOException, MessagingException {
|
||||
/*
|
||||
* Use quoted strings which permit spaces and quotes. (Using IMAP
|
||||
@ -412,7 +383,7 @@ class ImapConnection {
|
||||
try {
|
||||
receiveCapabilities(executeSimpleCommand(
|
||||
String.format("LOGIN \"%s\" \"%s\"", username, password), true));
|
||||
} catch (ImapStore.ImapException e) {
|
||||
} catch (ImapException e) {
|
||||
throw new AuthenticationFailedException(e.getMessage());
|
||||
}
|
||||
}
|
||||
@ -433,7 +404,7 @@ class ImapConnection {
|
||||
mOut.write('\n');
|
||||
mOut.flush();
|
||||
try {
|
||||
receiveCapabilities(readStatusResponse(tag, command, null));
|
||||
receiveCapabilities(mParser.readStatusResponse(tag, command, getLogId(), null));
|
||||
} catch (MessagingException e) {
|
||||
throw new AuthenticationFailedException(e.getMessage());
|
||||
}
|
||||
@ -449,7 +420,7 @@ class ImapConnection {
|
||||
mOut.write('\n');
|
||||
mOut.flush();
|
||||
try {
|
||||
receiveCapabilities(readStatusResponse(tag, command, null));
|
||||
receiveCapabilities(mParser.readStatusResponse(tag, command, getLogId(), null));
|
||||
} catch (MessagingException e) {
|
||||
throw new AuthenticationFailedException(e.getMessage());
|
||||
}
|
||||
@ -460,7 +431,7 @@ class ImapConnection {
|
||||
receiveCapabilities(executeSimpleCommand(
|
||||
String.format("AUTHENTICATE EXTERNAL %s",
|
||||
Base64.encode(mSettings.getUsername())), false));
|
||||
} catch (ImapStore.ImapException e) {
|
||||
} catch (ImapException e) {
|
||||
/*
|
||||
* Provide notification to the user of a problem authenticating
|
||||
* using client certificates. We don't use an
|
||||
@ -477,8 +448,8 @@ class ImapConnection {
|
||||
ImapResponse response;
|
||||
do {
|
||||
response = readResponse();
|
||||
if (response.mTag != null) {
|
||||
if (response.mTag.equalsIgnoreCase(tag)) {
|
||||
if (response.getTag() != null) {
|
||||
if (response.getTag().equalsIgnoreCase(tag)) {
|
||||
throw new MessagingException(
|
||||
"Command continuation aborted: " + response);
|
||||
} else {
|
||||
@ -487,43 +458,10 @@ class ImapConnection {
|
||||
+ response + " for " + getLogId());
|
||||
}
|
||||
}
|
||||
} while (!response.mCommandContinuationRequested);
|
||||
} while (!response.isContinuationRequested());
|
||||
return response;
|
||||
}
|
||||
|
||||
protected List<ImapResponse> readStatusResponse(String tag,
|
||||
String commandToLog, ImapStore.UntaggedHandler untaggedHandler)
|
||||
throws IOException, MessagingException {
|
||||
List<ImapResponse> responses = new ArrayList<ImapResponse>();
|
||||
ImapResponse response;
|
||||
do {
|
||||
response = mParser.readResponse();
|
||||
if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP)
|
||||
Log.v(LOG_TAG, getLogId() + "<<<" + response);
|
||||
|
||||
if (response.mTag != null && !response.mTag.equalsIgnoreCase(tag)) {
|
||||
Log.w(LOG_TAG, "After sending tag " + tag + ", got tag response from previous command " + response + " for " + getLogId());
|
||||
Iterator<ImapResponse> iter = responses.iterator();
|
||||
while (iter.hasNext()) {
|
||||
ImapResponse delResponse = iter.next();
|
||||
if (delResponse.mTag != null || delResponse.size() < 2
|
||||
|| (!ImapResponseParser.equalsIgnoreCase(delResponse.get(1), "EXISTS") && !ImapResponseParser.equalsIgnoreCase(delResponse.get(1), "EXPUNGE"))) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
response.mTag = null;
|
||||
continue;
|
||||
}
|
||||
if (untaggedHandler != null) {
|
||||
untaggedHandler.handleAsyncUntaggedResponse(response);
|
||||
}
|
||||
responses.add(response);
|
||||
} while (response.mTag == null);
|
||||
if (response.size() < 1 || !ImapResponseParser.equalsIgnoreCase(response.get(0), "OK")) {
|
||||
throw new ImapStore.ImapException("Command: " + commandToLog + "; response: " + response.toString(), response.getAlertText());
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
protected void setReadTimeout(int millis) throws SocketException {
|
||||
Socket sock = mSocket;
|
||||
@ -567,7 +505,7 @@ class ImapConnection {
|
||||
return readResponse(null);
|
||||
}
|
||||
|
||||
public ImapResponse readResponse(ImapResponseParser.IImapResponseCallback callback) throws IOException {
|
||||
public ImapResponse readResponse(ImapResponseCallback callback) throws IOException {
|
||||
try {
|
||||
ImapResponse response = mParser.readResponse(callback);
|
||||
if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP)
|
||||
@ -591,8 +529,7 @@ class ImapConnection {
|
||||
|
||||
}
|
||||
|
||||
public String sendCommand(String command, boolean sensitive)
|
||||
throws MessagingException, IOException {
|
||||
public String sendCommand(String command, boolean sensitive) throws MessagingException, IOException {
|
||||
try {
|
||||
open();
|
||||
String tag = Integer.toString(mNextCommandTag++);
|
||||
@ -613,7 +550,7 @@ class ImapConnection {
|
||||
} catch (IOException ioe) {
|
||||
close();
|
||||
throw ioe;
|
||||
} catch (ImapStore.ImapException ie) {
|
||||
} catch (ImapException ie) {
|
||||
close();
|
||||
throw ie;
|
||||
} catch (MessagingException me) {
|
||||
@ -632,21 +569,18 @@ class ImapConnection {
|
||||
return executeSimpleCommand(command, sensitive, null);
|
||||
}
|
||||
|
||||
public List<ImapResponse> executeSimpleCommand(String command, boolean sensitive, ImapStore.UntaggedHandler untaggedHandler)
|
||||
public List<ImapResponse> executeSimpleCommand(String command, boolean sensitive, UntaggedHandler untaggedHandler)
|
||||
throws IOException, MessagingException {
|
||||
String commandToLog = command;
|
||||
if (sensitive && !K9MailLib.isDebugSensitive()) {
|
||||
commandToLog = "*sensitive*";
|
||||
}
|
||||
|
||||
|
||||
//if (K9MailLib.isDebug())
|
||||
// Log.v(LOG_TAG, "Sending IMAP command " + commandToLog + " on connection " + getLogId());
|
||||
|
||||
String tag = sendCommand(command, sensitive);
|
||||
//if (K9MailLib.isDebug())
|
||||
// Log.v(LOG_TAG, "Sent IMAP command " + commandToLog + " with tag " + tag + " for " + getLogId());
|
||||
|
||||
return readStatusResponse(tag, commandToLog, untaggedHandler);
|
||||
return mParser.readStatusResponse(tag, commandToLog, getLogId(), untaggedHandler);
|
||||
}
|
||||
}
|
||||
|
13
src/com/fsck/k9/mail/store/imap/ImapException.java
Normal file
13
src/com/fsck/k9/mail/store/imap/ImapException.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
|
||||
class ImapException extends MessagingException {
|
||||
private static final long serialVersionUID = 3725007182205882394L;
|
||||
private final String mAlertText;
|
||||
|
||||
public ImapException(String message, String alertText) {
|
||||
super(message, true);
|
||||
this.mAlertText = alertText;
|
||||
}
|
||||
}
|
@ -11,20 +11,32 @@ package com.fsck.k9.mail.store.imap;
|
||||
public class ImapResponse extends ImapList {
|
||||
private static final long serialVersionUID = 6886458551615975669L;
|
||||
|
||||
private ImapResponseParser.IImapResponseCallback mCallback;
|
||||
private ImapResponseCallback mCallback;
|
||||
|
||||
boolean mCommandContinuationRequested;
|
||||
String mTag;
|
||||
private final boolean mCommandContinuationRequested;
|
||||
private final String mTag;
|
||||
|
||||
public ImapResponse(ImapResponseParser.IImapResponseCallback mCallback) {
|
||||
this.mCallback = mCallback;
|
||||
|
||||
public ImapResponse(ImapResponseCallback callback,
|
||||
boolean mCommandContinuationRequested, String mTag) {
|
||||
this.mCallback = callback;
|
||||
this.mCommandContinuationRequested = mCommandContinuationRequested;
|
||||
this.mTag = mTag;
|
||||
}
|
||||
|
||||
public ImapResponseParser.IImapResponseCallback getCallback() {
|
||||
public boolean isContinuationRequested() {
|
||||
return mCommandContinuationRequested;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
public ImapResponseCallback getCallback() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
public void setCallback(ImapResponseParser.IImapResponseCallback mCallback) {
|
||||
public void setCallback(ImapResponseCallback mCallback) {
|
||||
this.mCallback = mCallback;
|
||||
}
|
||||
|
||||
|
24
src/com/fsck/k9/mail/store/imap/ImapResponseCallback.java
Normal file
24
src/com/fsck/k9/mail/store/imap/ImapResponseCallback.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
import com.fsck.k9.mail.filter.FixedLengthInputStream;
|
||||
|
||||
public interface ImapResponseCallback {
|
||||
/**
|
||||
* Callback method that is called by the parser when a literal string
|
||||
* is found in an IMAP response.
|
||||
*
|
||||
* @param response ImapResponse object with the fields that have been
|
||||
* parsed up until now (excluding the literal string).
|
||||
* @param literal FixedLengthInputStream that can be used to access
|
||||
* the literal string.
|
||||
*
|
||||
* @return an Object that will be put in the ImapResponse object at the
|
||||
* place of the literal string.
|
||||
*
|
||||
* @throws java.io.IOException passed-through if thrown by FixedLengthInputStream
|
||||
* @throws Exception if something goes wrong. Parsing will be resumed
|
||||
* and the exception will be thrown after the
|
||||
* complete IMAP response has been parsed.
|
||||
*/
|
||||
public Object foundLiteral(ImapResponse response, FixedLengthInputStream literal) throws Exception;
|
||||
}
|
@ -1,13 +1,25 @@
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.mail.K9MailLib;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.filter.FixedLengthInputStream;
|
||||
import com.fsck.k9.mail.filter.PeekableInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.fsck.k9.mail.K9MailLib.DEBUG_PROTOCOL_IMAP;
|
||||
import static com.fsck.k9.mail.K9MailLib.LOG_TAG;
|
||||
import static com.fsck.k9.mail.store.imap.ImapCommands.CAPABILITY_CAPABILITY;
|
||||
|
||||
class ImapResponseParser {
|
||||
|
||||
private PeekableInputStream mIn;
|
||||
private ImapResponse mResponse;
|
||||
private Exception mException;
|
||||
@ -24,20 +36,18 @@ class ImapResponseParser {
|
||||
* Reads the next response available on the stream and returns an
|
||||
* ImapResponse object that represents it.
|
||||
*/
|
||||
public ImapResponse readResponse(IImapResponseCallback callback) throws IOException {
|
||||
public ImapResponse readResponse(ImapResponseCallback callback) throws IOException {
|
||||
try {
|
||||
mResponse = new ImapResponse(callback);
|
||||
mResponse.setCallback(callback);
|
||||
|
||||
int ch = mIn.peek();
|
||||
if (ch == '*') {
|
||||
parseUntaggedResponse();
|
||||
mResponse = new ImapResponse(callback, false, null);
|
||||
readTokens(mResponse);
|
||||
} else if (ch == '+') {
|
||||
mResponse.mCommandContinuationRequested = parseCommandContinuationRequest();
|
||||
mResponse = new ImapResponse(callback, parseCommandContinuationRequest(), null);
|
||||
parseResponseText(mResponse);
|
||||
} else {
|
||||
mResponse.mTag = parseTaggedResponse();
|
||||
mResponse = new ImapResponse(callback, false, parseTaggedResponse());
|
||||
readTokens(mResponse);
|
||||
}
|
||||
|
||||
@ -52,6 +62,80 @@ class ImapResponseParser {
|
||||
}
|
||||
}
|
||||
|
||||
protected List<ImapResponse> readStatusResponse(String tag,
|
||||
String commandToLog,
|
||||
String logId,
|
||||
UntaggedHandler untaggedHandler)
|
||||
throws IOException, MessagingException {
|
||||
List<ImapResponse> responses = new ArrayList<ImapResponse>();
|
||||
ImapResponse response;
|
||||
do {
|
||||
response = readResponse();
|
||||
if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP) {
|
||||
Log.v(LOG_TAG, logId + "<<<" + response);
|
||||
}
|
||||
|
||||
if (response.getTag() != null && !response.getTag().equalsIgnoreCase(tag)) {
|
||||
Log.w(LOG_TAG, "After sending tag " + tag + ", got tag response from previous command " + response + " for " + logId);
|
||||
|
||||
Iterator<ImapResponse> iter = responses.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
ImapResponse delResponse = iter.next();
|
||||
if (delResponse.getTag() != null
|
||||
|| delResponse.size() < 2
|
||||
|| (!equalsIgnoreCase(delResponse.get(1), "EXISTS") &&
|
||||
!equalsIgnoreCase(delResponse.get(1), "EXPUNGE"))) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
response = null;
|
||||
continue;
|
||||
}
|
||||
if (untaggedHandler != null) {
|
||||
untaggedHandler.handleAsyncUntaggedResponse(response);
|
||||
}
|
||||
responses.add(response);
|
||||
|
||||
} while (response == null || response.getTag() == null);
|
||||
|
||||
if (response.size() < 1 || !equalsIgnoreCase(response.get(0), "OK")) {
|
||||
throw new ImapException("Command: " + commandToLog + "; response: " + response.toString(), response.getAlertText());
|
||||
}
|
||||
|
||||
return responses;
|
||||
}
|
||||
|
||||
protected static Set<String> parseCapabilities(List<ImapResponse> responses) {
|
||||
HashSet<String> capabilities = new HashSet<String>();
|
||||
for (ImapResponse response : responses) {
|
||||
ImapList list = null;
|
||||
if (!response.isEmpty() && equalsIgnoreCase(response.get(0), "OK")) {
|
||||
for (Object thisPart : response) {
|
||||
if (thisPart instanceof ImapList) {
|
||||
ImapList thisList = (ImapList)thisPart;
|
||||
if (equalsIgnoreCase(thisList.get(0), CAPABILITY_CAPABILITY)) {
|
||||
list = thisList;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (response.getTag() == null) {
|
||||
list = response;
|
||||
}
|
||||
|
||||
if (list != null && list.size() > 1 &&
|
||||
equalsIgnoreCase(list.get(0), CAPABILITY_CAPABILITY)) {
|
||||
for (Object capability : list.subList(1, list.size())) {
|
||||
if (capability instanceof String) {
|
||||
capabilities.add(((String)capability).toUpperCase(Locale.US));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
private void readTokens(ImapResponse response) throws IOException {
|
||||
response.clear();
|
||||
|
||||
@ -184,8 +268,7 @@ class ImapResponseParser {
|
||||
|
||||
// 3 OK [READ-WRITE] Select completed.
|
||||
private String parseTaggedResponse() throws IOException {
|
||||
String tag = readStringUntil(' ');
|
||||
return tag;
|
||||
return readStringUntil(' ');
|
||||
}
|
||||
|
||||
private ImapList parseList(ImapList parent) throws IOException {
|
||||
@ -377,24 +460,4 @@ class ImapResponseParser {
|
||||
}
|
||||
}
|
||||
|
||||
public interface IImapResponseCallback {
|
||||
/**
|
||||
* Callback method that is called by the parser when a literal string
|
||||
* is found in an IMAP response.
|
||||
*
|
||||
* @param response ImapResponse object with the fields that have been
|
||||
* parsed up until now (excluding the literal string).
|
||||
* @param literal FixedLengthInputStream that can be used to access
|
||||
* the literal string.
|
||||
*
|
||||
* @return an Object that will be put in the ImapResponse object at the
|
||||
* place of the literal string.
|
||||
*
|
||||
* @throws IOException passed-through if thrown by FixedLengthInputStream
|
||||
* @throws Exception if something goes wrong. Parsing will be resumed
|
||||
* and the exception will be thrown after the
|
||||
* complete IMAP response has been parsed.
|
||||
*/
|
||||
public Object foundLiteral(ImapResponse response, FixedLengthInputStream literal) throws Exception;
|
||||
}
|
||||
}
|
||||
|
@ -789,7 +789,7 @@ public class ImapStore extends RemoteStore {
|
||||
Object keyObj = bracketed.get(0);
|
||||
if (keyObj instanceof String) {
|
||||
String key = (String) keyObj;
|
||||
if (response.mTag != null) {
|
||||
if (response.getTag() != null) {
|
||||
|
||||
if ("READ-ONLY".equalsIgnoreCase(key)) {
|
||||
mMode = OPEN_MODE_RO;
|
||||
@ -1253,7 +1253,7 @@ public class ImapStore extends RemoteStore {
|
||||
List<Long> uids = new ArrayList<Long>();
|
||||
List<ImapResponse> responses = searcher.search(); //
|
||||
for (ImapResponse response : responses) {
|
||||
if (response.mTag == null) {
|
||||
if (response.getTag() == null) {
|
||||
if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) {
|
||||
for (int i = 1, count = response.size(); i < count; i++) {
|
||||
uids.add(response.getLong(i));
|
||||
@ -1385,7 +1385,7 @@ public class ImapStore extends RemoteStore {
|
||||
ImapResponse response;
|
||||
int messageNumber = 0;
|
||||
|
||||
ImapResponseParser.IImapResponseCallback callback = null;
|
||||
ImapResponseCallback callback = null;
|
||||
if (fp.contains(FetchProfile.Item.BODY) || fp.contains(FetchProfile.Item.BODY_SANE)) {
|
||||
callback = new FetchBodyCallback(messageMap);
|
||||
}
|
||||
@ -1393,7 +1393,7 @@ public class ImapStore extends RemoteStore {
|
||||
do {
|
||||
response = mConnection.readResponse(callback);
|
||||
|
||||
if (response.mTag == null && ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
|
||||
if (response.getTag() == null && ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
|
||||
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
|
||||
String uid = fetchList.getKeyedString("UID");
|
||||
long msgSeq = response.getLong(0);
|
||||
@ -1444,7 +1444,7 @@ public class ImapStore extends RemoteStore {
|
||||
handleUntaggedResponse(response);
|
||||
}
|
||||
|
||||
} while (response.mTag == null);
|
||||
} while (response.getTag() == null);
|
||||
} catch (IOException ioe) {
|
||||
throw ioExceptionHandler(mConnection, ioe);
|
||||
}
|
||||
@ -1479,12 +1479,12 @@ public class ImapStore extends RemoteStore {
|
||||
ImapResponse response;
|
||||
int messageNumber = 0;
|
||||
|
||||
ImapResponseParser.IImapResponseCallback callback = new FetchPartCallback(part);
|
||||
ImapResponseCallback callback = new FetchPartCallback(part);
|
||||
|
||||
do {
|
||||
response = mConnection.readResponse(callback);
|
||||
|
||||
if ((response.mTag == null) &&
|
||||
if ((response.getTag() == null) &&
|
||||
(ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH"))) {
|
||||
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
|
||||
String uid = fetchList.getKeyedString("UID");
|
||||
@ -1531,7 +1531,7 @@ public class ImapStore extends RemoteStore {
|
||||
handleUntaggedResponse(response);
|
||||
}
|
||||
|
||||
} while (response.mTag == null);
|
||||
} while (response.getTag() == null);
|
||||
} catch (IOException ioe) {
|
||||
throw ioExceptionHandler(mConnection, ioe);
|
||||
}
|
||||
@ -1643,7 +1643,7 @@ public class ImapStore extends RemoteStore {
|
||||
* @param response
|
||||
*/
|
||||
protected void handleUntaggedResponse(ImapResponse response) {
|
||||
if (response.mTag == null && response.size() > 1) {
|
||||
if (response.getTag() == null && response.size() > 1) {
|
||||
if (ImapResponseParser.equalsIgnoreCase(response.get(1), "EXISTS")) {
|
||||
mMessageCount = response.getNumber(0);
|
||||
if (K9MailLib.isDebug())
|
||||
@ -1873,14 +1873,14 @@ public class ImapStore extends RemoteStore {
|
||||
do {
|
||||
response = mConnection.readResponse();
|
||||
handleUntaggedResponse(response);
|
||||
if (response.mCommandContinuationRequested) {
|
||||
if (response.isContinuationRequested()) {
|
||||
EOLConvertingOutputStream eolOut = new EOLConvertingOutputStream(mConnection.getOutputStream());
|
||||
message.writeTo(eolOut);
|
||||
eolOut.write('\r');
|
||||
eolOut.write('\n');
|
||||
eolOut.flush();
|
||||
}
|
||||
} while (response.mTag == null);
|
||||
} while (response.getTag() == null);
|
||||
|
||||
if (response.size() > 1) {
|
||||
/*
|
||||
@ -1957,7 +1957,7 @@ public class ImapStore extends RemoteStore {
|
||||
executeSimpleCommand(
|
||||
String.format("UID SEARCH HEADER MESSAGE-ID %s", encodeString(messageId)));
|
||||
for (ImapResponse response1 : responses) {
|
||||
if (response1.mTag == null && ImapResponseParser.equalsIgnoreCase(response1.get(0), "SEARCH")
|
||||
if (response1.getTag() == null && ImapResponseParser.equalsIgnoreCase(response1.get(0), "SEARCH")
|
||||
&& response1.size() > 1) {
|
||||
return response1.getString(1);
|
||||
}
|
||||
@ -2232,16 +2232,6 @@ public class ImapStore extends RemoteStore {
|
||||
}
|
||||
}
|
||||
|
||||
static class ImapException extends MessagingException {
|
||||
private static final long serialVersionUID = 3725007182205882394L;
|
||||
private final String mAlertText;
|
||||
|
||||
public ImapException(String message, String alertText) {
|
||||
super(message, true);
|
||||
this.mAlertText = alertText;
|
||||
}
|
||||
}
|
||||
|
||||
public class ImapFolderPusher extends ImapFolder implements UntaggedHandler {
|
||||
private final PushReceiver receiver;
|
||||
private Thread listeningThread = null;
|
||||
@ -2459,7 +2449,7 @@ public class ImapStore extends RemoteStore {
|
||||
|
||||
@Override
|
||||
protected void handleUntaggedResponse(ImapResponse response) {
|
||||
if (response.mTag == null && response.size() > 1) {
|
||||
if (response.getTag() == null && response.size() > 1) {
|
||||
Object responseType = response.get(1);
|
||||
if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH")
|
||||
|| ImapResponseParser.equalsIgnoreCase(responseType, "EXPUNGE")
|
||||
@ -2588,7 +2578,7 @@ public class ImapStore extends RemoteStore {
|
||||
protected int processUntaggedResponse(long oldMessageCount, ImapResponse response, List<Long> flagSyncMsgSeqs, List<String> removeMsgUids) {
|
||||
super.handleUntaggedResponse(response);
|
||||
int messageCountDelta = 0;
|
||||
if (response.mTag == null && response.size() > 1) {
|
||||
if (response.getTag() == null && response.size() > 1) {
|
||||
try {
|
||||
Object responseType = response.get(1);
|
||||
if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH")) {
|
||||
@ -2703,7 +2693,7 @@ public class ImapStore extends RemoteStore {
|
||||
Log.e(LOG_TAG, "Exception while sending DONE for " + getLogId(), e);
|
||||
}
|
||||
} else {
|
||||
if (response.mTag == null) {
|
||||
if (response.getTag() == null) {
|
||||
if (response.size() > 1) {
|
||||
boolean started = false;
|
||||
Object responseType = response.get(1);
|
||||
@ -2723,7 +2713,7 @@ public class ImapStore extends RemoteStore {
|
||||
Log.e(LOG_TAG, "Exception while sending DONE for " + getLogId(), e);
|
||||
}
|
||||
}
|
||||
} else if (response.mCommandContinuationRequested) {
|
||||
} else if (response.isContinuationRequested()) {
|
||||
if (K9MailLib.isDebug())
|
||||
Log.d(LOG_TAG, "Idling " + getLogId());
|
||||
|
||||
@ -2812,10 +2802,6 @@ public class ImapStore extends RemoteStore {
|
||||
public void setLastRefresh(long lastRefresh) {
|
||||
this.lastRefresh = lastRefresh;
|
||||
}
|
||||
|
||||
}
|
||||
public static interface UntaggedHandler {
|
||||
void handleAsyncUntaggedResponse(ImapResponse respose);
|
||||
}
|
||||
|
||||
protected static class ImapPushState {
|
||||
@ -2856,7 +2842,7 @@ public class ImapStore extends RemoteStore {
|
||||
List<ImapResponse> search() throws IOException, MessagingException;
|
||||
}
|
||||
|
||||
private static class FetchBodyCallback implements ImapResponseParser.IImapResponseCallback {
|
||||
private static class FetchBodyCallback implements ImapResponseCallback {
|
||||
private Map<String, Message> mMessageMap;
|
||||
|
||||
FetchBodyCallback(Map<String, Message> messageMap) {
|
||||
@ -2865,8 +2851,8 @@ public class ImapStore extends RemoteStore {
|
||||
|
||||
@Override
|
||||
public Object foundLiteral(ImapResponse response,
|
||||
FixedLengthInputStream literal) throws IOException, Exception {
|
||||
if (response.mTag == null &&
|
||||
FixedLengthInputStream literal) throws MessagingException, IOException {
|
||||
if (response.getTag() == null &&
|
||||
ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
|
||||
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
|
||||
String uid = fetchList.getKeyedString("UID");
|
||||
@ -2875,13 +2861,13 @@ public class ImapStore extends RemoteStore {
|
||||
message.parse(literal);
|
||||
|
||||
// Return placeholder object
|
||||
return Integer.valueOf(1);
|
||||
return 1;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FetchPartCallback implements ImapResponseParser.IImapResponseCallback {
|
||||
private static class FetchPartCallback implements ImapResponseCallback {
|
||||
private Part mPart;
|
||||
|
||||
FetchPartCallback(Part part) {
|
||||
@ -2890,8 +2876,8 @@ public class ImapStore extends RemoteStore {
|
||||
|
||||
@Override
|
||||
public Object foundLiteral(ImapResponse response,
|
||||
FixedLengthInputStream literal) throws IOException, Exception {
|
||||
if (response.mTag == null &&
|
||||
FixedLengthInputStream literal) throws MessagingException, IOException {
|
||||
if (response.getTag() == null &&
|
||||
ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
|
||||
//TODO: check for correct UID
|
||||
|
||||
|
5
src/com/fsck/k9/mail/store/imap/UntaggedHandler.java
Normal file
5
src/com/fsck/k9/mail/store/imap/UntaggedHandler.java
Normal file
@ -0,0 +1,5 @@
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
interface UntaggedHandler {
|
||||
void handleAsyncUntaggedResponse(ImapResponse response);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ImapListTest extends TestCase {
|
||||
public void testImapListMethods() throws IOException {
|
||||
ImapList list = new ImapList();
|
||||
list.add("ONE");
|
||||
list.add("TWO");
|
||||
list.add("THREE");
|
||||
|
||||
assertTrue(list.containsKey("ONE"));
|
||||
assertTrue(list.containsKey("TWO"));
|
||||
assertFalse(list.containsKey("THREE"));
|
||||
assertFalse(list.containsKey("nonexistent"));
|
||||
|
||||
assertEquals("TWO", list.getKeyedValue("ONE"));
|
||||
assertEquals("THREE", list.getKeyedValue("TWO"));
|
||||
assertNull(list.getKeyedValue("THREE"));
|
||||
assertNull(list.getKeyedValue("nonexistent"));
|
||||
|
||||
assertEquals(0, list.getKeyIndex("ONE"));
|
||||
assertEquals(1, list.getKeyIndex("TWO"));
|
||||
|
||||
try {
|
||||
list.getKeyIndex("THREE");
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
} catch (IllegalArgumentException e) { /* do nothing */ }
|
||||
|
||||
try {
|
||||
list.getKeyIndex("nonexistent");
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
} catch (IllegalArgumentException e) { /* do nothing */ }
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
import com.fsck.k9.mail.filter.PeekableInputStream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.fsck.k9.mail.store.imap.ImapResponseParser.parseCapabilities;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ImapResponseParserTest {
|
||||
|
||||
@Test public void testSimpleOkResponse() throws IOException {
|
||||
ImapResponseParser parser = createParser("* OK\r\n");
|
||||
ImapResponse response = parser.readResponse();
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(1, response.size());
|
||||
assertEquals("OK", response.get(0));
|
||||
}
|
||||
|
||||
@Test public void testOkResponseWithText() throws IOException {
|
||||
ImapResponseParser parser = createParser("* OK Some text here\r\n");
|
||||
ImapResponse response = parser.readResponse();
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(2, response.size());
|
||||
assertEquals("OK", response.get(0));
|
||||
assertEquals("Some text here", response.get(1));
|
||||
}
|
||||
|
||||
@Test public void testOkResponseWithRespTextCode() throws IOException {
|
||||
ImapResponseParser parser = createParser("* OK [UIDVALIDITY 3857529045]\r\n");
|
||||
ImapResponse response = parser.readResponse();
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(2, response.size());
|
||||
assertEquals("OK", response.get(0));
|
||||
assertTrue(response.get(1) instanceof ImapList);
|
||||
|
||||
ImapList respTextCode = (ImapList) response.get(1);
|
||||
assertEquals(2, respTextCode.size());
|
||||
assertEquals("UIDVALIDITY", respTextCode.get(0));
|
||||
assertEquals("3857529045", respTextCode.get(1));
|
||||
}
|
||||
|
||||
@Test public void testOkResponseWithRespTextCodeAndText() throws IOException {
|
||||
ImapResponseParser parser = createParser("* OK [token1 token2] {x} test [...]\r\n");
|
||||
ImapResponse response = parser.readResponse();
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(3, response.size());
|
||||
assertEquals("OK", response.get(0));
|
||||
assertTrue(response.get(1) instanceof ImapList);
|
||||
assertEquals("{x} test [...]", response.get(2));
|
||||
|
||||
ImapList respTextCode = (ImapList) response.get(1);
|
||||
assertEquals(2, respTextCode.size());
|
||||
assertEquals("token1", respTextCode.get(0));
|
||||
assertEquals("token2", respTextCode.get(1));
|
||||
}
|
||||
|
||||
|
||||
@Test public void testReadStatusResponseWithOKResponse() throws Exception {
|
||||
ImapResponseParser parser = createParser("* COMMAND BAR BAZ\r\nTAG OK COMMAND completed\r\n");
|
||||
List<ImapResponse> responses = parser.readStatusResponse("TAG", null, null, null);
|
||||
|
||||
assertEquals(2, responses.size());
|
||||
assertEquals(asList("COMMAND", "BAR", "BAZ"), responses.get(0));
|
||||
assertEquals(asList("OK", "COMMAND completed"), responses.get(1));
|
||||
}
|
||||
|
||||
@Test(expected = ImapException.class)
|
||||
public void testReadStatusResponseWithErrorResponse() throws Exception {
|
||||
ImapResponseParser parser = createParser("* COMMAND BAR BAZ\r\nTAG ERROR COMMAND errored\r\n");
|
||||
parser.readStatusResponse("TAG", null, null, null);
|
||||
}
|
||||
|
||||
@Test public void testParseCapabilities() throws Exception {
|
||||
ImapResponse capabilityResponse = new ImapResponse(null, false, null);
|
||||
capabilityResponse.addAll(Arrays.asList("CAPABILITY", "FOO", "BAR"));
|
||||
Set<String> capabilities = parseCapabilities(Arrays.asList(capabilityResponse));
|
||||
|
||||
assertEquals(2, capabilities.size());
|
||||
assertTrue(capabilities.contains("FOO"));
|
||||
assertTrue(capabilities.contains("BAR"));
|
||||
}
|
||||
|
||||
@Test public void testParseCapabilitiesWithInvalidResponse() throws Exception {
|
||||
ImapResponse capabilityResponse = new ImapResponse(null, false, null);
|
||||
capabilityResponse.addAll(Arrays.asList("FOO", "BAZ"));
|
||||
assertTrue(parseCapabilities(Arrays.asList(capabilityResponse)).isEmpty());
|
||||
}
|
||||
|
||||
private ImapResponseParser createParser(String response) {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(response.getBytes());
|
||||
PeekableInputStream pin = new PeekableInputStream(in);
|
||||
return new ImapResponseParser(pin);
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package com.fsck.k9.mail.store.imap;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import com.fsck.k9.mail.filter.PeekableInputStream;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class ImapResponseParserTest extends TestCase {
|
||||
|
||||
public void testSimpleOkResponse() throws IOException {
|
||||
ImapResponseParser parser = createParser("* OK\r\n");
|
||||
ImapResponse response = parser.readResponse();
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(1, response.size());
|
||||
assertEquals("OK", response.get(0));
|
||||
}
|
||||
|
||||
public void testOkResponseWithText() throws IOException {
|
||||
ImapResponseParser parser = createParser("* OK Some text here\r\n");
|
||||
ImapResponse response = parser.readResponse();
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(2, response.size());
|
||||
assertEquals("OK", response.get(0));
|
||||
assertEquals("Some text here", response.get(1));
|
||||
}
|
||||
|
||||
public void testOkResponseWithRespTextCode() throws IOException {
|
||||
ImapResponseParser parser = createParser("* OK [UIDVALIDITY 3857529045]\r\n");
|
||||
ImapResponse response = parser.readResponse();
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(2, response.size());
|
||||
assertEquals("OK", response.get(0));
|
||||
assertTrue(response.get(1) instanceof ImapList);
|
||||
|
||||
ImapList respTextCode = (ImapList) response.get(1);
|
||||
assertEquals(2, respTextCode.size());
|
||||
assertEquals("UIDVALIDITY", respTextCode.get(0));
|
||||
assertEquals("3857529045", respTextCode.get(1));
|
||||
}
|
||||
|
||||
public void testOkResponseWithRespTextCodeAndText() throws IOException {
|
||||
ImapResponseParser parser = createParser("* OK [token1 token2] {x} test [...]\r\n");
|
||||
ImapResponse response = parser.readResponse();
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(3, response.size());
|
||||
assertEquals("OK", response.get(0));
|
||||
assertTrue(response.get(1) instanceof ImapList);
|
||||
assertEquals("{x} test [...]", response.get(2));
|
||||
|
||||
ImapList respTextCode = (ImapList) response.get(1);
|
||||
assertEquals(2, respTextCode.size());
|
||||
assertEquals("token1", respTextCode.get(0));
|
||||
assertEquals("token2", respTextCode.get(1));
|
||||
}
|
||||
|
||||
public void testImapListMethods() throws IOException {
|
||||
ImapList list = new ImapList();
|
||||
list.add("ONE");
|
||||
list.add("TWO");
|
||||
list.add("THREE");
|
||||
|
||||
assertTrue(list.containsKey("ONE"));
|
||||
assertTrue(list.containsKey("TWO"));
|
||||
assertFalse(list.containsKey("THREE"));
|
||||
assertFalse(list.containsKey("nonexistent"));
|
||||
|
||||
assertEquals("TWO", list.getKeyedValue("ONE"));
|
||||
assertEquals("THREE", list.getKeyedValue("TWO"));
|
||||
assertNull(list.getKeyedValue("THREE"));
|
||||
assertNull(list.getKeyedValue("nonexistent"));
|
||||
|
||||
assertEquals(0, list.getKeyIndex("ONE"));
|
||||
assertEquals(1, list.getKeyIndex("TWO"));
|
||||
|
||||
try {
|
||||
list.getKeyIndex("THREE");
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
} catch (IllegalArgumentException e) { /* do nothing */ }
|
||||
|
||||
try {
|
||||
list.getKeyIndex("nonexistent");
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
} catch (IllegalArgumentException e) { /* do nothing */ }
|
||||
}
|
||||
|
||||
private ImapResponseParser createParser(String response) {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(response.getBytes());
|
||||
PeekableInputStream pin = new PeekableInputStream(in);
|
||||
return new ImapResponseParser(pin);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user