mirror of
https://github.com/moparisthebest/k-9
synced 2025-03-01 09:01:47 -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.GeneralSecurityException;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -84,41 +82,6 @@ class ImapConnection {
|
|||||||
return "conn" + hashCode();
|
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 {
|
public void open() throws IOException, MessagingException {
|
||||||
if (isOpen()) {
|
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 {
|
protected void login() throws IOException, MessagingException {
|
||||||
/*
|
/*
|
||||||
* Use quoted strings which permit spaces and quotes. (Using IMAP
|
* Use quoted strings which permit spaces and quotes. (Using IMAP
|
||||||
@ -412,7 +383,7 @@ class ImapConnection {
|
|||||||
try {
|
try {
|
||||||
receiveCapabilities(executeSimpleCommand(
|
receiveCapabilities(executeSimpleCommand(
|
||||||
String.format("LOGIN \"%s\" \"%s\"", username, password), true));
|
String.format("LOGIN \"%s\" \"%s\"", username, password), true));
|
||||||
} catch (ImapStore.ImapException e) {
|
} catch (ImapException e) {
|
||||||
throw new AuthenticationFailedException(e.getMessage());
|
throw new AuthenticationFailedException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -433,7 +404,7 @@ class ImapConnection {
|
|||||||
mOut.write('\n');
|
mOut.write('\n');
|
||||||
mOut.flush();
|
mOut.flush();
|
||||||
try {
|
try {
|
||||||
receiveCapabilities(readStatusResponse(tag, command, null));
|
receiveCapabilities(mParser.readStatusResponse(tag, command, getLogId(), null));
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
throw new AuthenticationFailedException(e.getMessage());
|
throw new AuthenticationFailedException(e.getMessage());
|
||||||
}
|
}
|
||||||
@ -449,7 +420,7 @@ class ImapConnection {
|
|||||||
mOut.write('\n');
|
mOut.write('\n');
|
||||||
mOut.flush();
|
mOut.flush();
|
||||||
try {
|
try {
|
||||||
receiveCapabilities(readStatusResponse(tag, command, null));
|
receiveCapabilities(mParser.readStatusResponse(tag, command, getLogId(), null));
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
throw new AuthenticationFailedException(e.getMessage());
|
throw new AuthenticationFailedException(e.getMessage());
|
||||||
}
|
}
|
||||||
@ -460,7 +431,7 @@ class ImapConnection {
|
|||||||
receiveCapabilities(executeSimpleCommand(
|
receiveCapabilities(executeSimpleCommand(
|
||||||
String.format("AUTHENTICATE EXTERNAL %s",
|
String.format("AUTHENTICATE EXTERNAL %s",
|
||||||
Base64.encode(mSettings.getUsername())), false));
|
Base64.encode(mSettings.getUsername())), false));
|
||||||
} catch (ImapStore.ImapException e) {
|
} catch (ImapException e) {
|
||||||
/*
|
/*
|
||||||
* Provide notification to the user of a problem authenticating
|
* Provide notification to the user of a problem authenticating
|
||||||
* using client certificates. We don't use an
|
* using client certificates. We don't use an
|
||||||
@ -477,8 +448,8 @@ class ImapConnection {
|
|||||||
ImapResponse response;
|
ImapResponse response;
|
||||||
do {
|
do {
|
||||||
response = readResponse();
|
response = readResponse();
|
||||||
if (response.mTag != null) {
|
if (response.getTag() != null) {
|
||||||
if (response.mTag.equalsIgnoreCase(tag)) {
|
if (response.getTag().equalsIgnoreCase(tag)) {
|
||||||
throw new MessagingException(
|
throw new MessagingException(
|
||||||
"Command continuation aborted: " + response);
|
"Command continuation aborted: " + response);
|
||||||
} else {
|
} else {
|
||||||
@ -487,43 +458,10 @@ class ImapConnection {
|
|||||||
+ response + " for " + getLogId());
|
+ response + " for " + getLogId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (!response.mCommandContinuationRequested);
|
} while (!response.isContinuationRequested());
|
||||||
return response;
|
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 {
|
protected void setReadTimeout(int millis) throws SocketException {
|
||||||
Socket sock = mSocket;
|
Socket sock = mSocket;
|
||||||
@ -567,7 +505,7 @@ class ImapConnection {
|
|||||||
return readResponse(null);
|
return readResponse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImapResponse readResponse(ImapResponseParser.IImapResponseCallback callback) throws IOException {
|
public ImapResponse readResponse(ImapResponseCallback callback) throws IOException {
|
||||||
try {
|
try {
|
||||||
ImapResponse response = mParser.readResponse(callback);
|
ImapResponse response = mParser.readResponse(callback);
|
||||||
if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP)
|
if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP)
|
||||||
@ -591,8 +529,7 @@ class ImapConnection {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendCommand(String command, boolean sensitive)
|
public String sendCommand(String command, boolean sensitive) throws MessagingException, IOException {
|
||||||
throws MessagingException, IOException {
|
|
||||||
try {
|
try {
|
||||||
open();
|
open();
|
||||||
String tag = Integer.toString(mNextCommandTag++);
|
String tag = Integer.toString(mNextCommandTag++);
|
||||||
@ -613,7 +550,7 @@ class ImapConnection {
|
|||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
close();
|
close();
|
||||||
throw ioe;
|
throw ioe;
|
||||||
} catch (ImapStore.ImapException ie) {
|
} catch (ImapException ie) {
|
||||||
close();
|
close();
|
||||||
throw ie;
|
throw ie;
|
||||||
} catch (MessagingException me) {
|
} catch (MessagingException me) {
|
||||||
@ -632,21 +569,18 @@ class ImapConnection {
|
|||||||
return executeSimpleCommand(command, sensitive, null);
|
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 {
|
throws IOException, MessagingException {
|
||||||
String commandToLog = command;
|
String commandToLog = command;
|
||||||
if (sensitive && !K9MailLib.isDebugSensitive()) {
|
if (sensitive && !K9MailLib.isDebugSensitive()) {
|
||||||
commandToLog = "*sensitive*";
|
commandToLog = "*sensitive*";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//if (K9MailLib.isDebug())
|
//if (K9MailLib.isDebug())
|
||||||
// Log.v(LOG_TAG, "Sending IMAP command " + commandToLog + " on connection " + getLogId());
|
// Log.v(LOG_TAG, "Sending IMAP command " + commandToLog + " on connection " + getLogId());
|
||||||
|
|
||||||
String tag = sendCommand(command, sensitive);
|
String tag = sendCommand(command, sensitive);
|
||||||
//if (K9MailLib.isDebug())
|
//if (K9MailLib.isDebug())
|
||||||
// Log.v(LOG_TAG, "Sent IMAP command " + commandToLog + " with tag " + tag + " for " + getLogId());
|
// 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 {
|
public class ImapResponse extends ImapList {
|
||||||
private static final long serialVersionUID = 6886458551615975669L;
|
private static final long serialVersionUID = 6886458551615975669L;
|
||||||
|
|
||||||
private ImapResponseParser.IImapResponseCallback mCallback;
|
private ImapResponseCallback mCallback;
|
||||||
|
|
||||||
boolean mCommandContinuationRequested;
|
private final boolean mCommandContinuationRequested;
|
||||||
String mTag;
|
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;
|
return mCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCallback(ImapResponseParser.IImapResponseCallback mCallback) {
|
public void setCallback(ImapResponseCallback mCallback) {
|
||||||
this.mCallback = 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;
|
package com.fsck.k9.mail.store.imap;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
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.FixedLengthInputStream;
|
||||||
import com.fsck.k9.mail.filter.PeekableInputStream;
|
import com.fsck.k9.mail.filter.PeekableInputStream;
|
||||||
import java.io.IOException;
|
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 {
|
class ImapResponseParser {
|
||||||
|
|
||||||
private PeekableInputStream mIn;
|
private PeekableInputStream mIn;
|
||||||
private ImapResponse mResponse;
|
private ImapResponse mResponse;
|
||||||
private Exception mException;
|
private Exception mException;
|
||||||
@ -24,20 +36,18 @@ class ImapResponseParser {
|
|||||||
* Reads the next response available on the stream and returns an
|
* Reads the next response available on the stream and returns an
|
||||||
* ImapResponse object that represents it.
|
* ImapResponse object that represents it.
|
||||||
*/
|
*/
|
||||||
public ImapResponse readResponse(IImapResponseCallback callback) throws IOException {
|
public ImapResponse readResponse(ImapResponseCallback callback) throws IOException {
|
||||||
try {
|
try {
|
||||||
mResponse = new ImapResponse(callback);
|
|
||||||
mResponse.setCallback(callback);
|
|
||||||
|
|
||||||
int ch = mIn.peek();
|
int ch = mIn.peek();
|
||||||
if (ch == '*') {
|
if (ch == '*') {
|
||||||
parseUntaggedResponse();
|
parseUntaggedResponse();
|
||||||
|
mResponse = new ImapResponse(callback, false, null);
|
||||||
readTokens(mResponse);
|
readTokens(mResponse);
|
||||||
} else if (ch == '+') {
|
} else if (ch == '+') {
|
||||||
mResponse.mCommandContinuationRequested = parseCommandContinuationRequest();
|
mResponse = new ImapResponse(callback, parseCommandContinuationRequest(), null);
|
||||||
parseResponseText(mResponse);
|
parseResponseText(mResponse);
|
||||||
} else {
|
} else {
|
||||||
mResponse.mTag = parseTaggedResponse();
|
mResponse = new ImapResponse(callback, false, parseTaggedResponse());
|
||||||
readTokens(mResponse);
|
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 {
|
private void readTokens(ImapResponse response) throws IOException {
|
||||||
response.clear();
|
response.clear();
|
||||||
|
|
||||||
@ -184,8 +268,7 @@ class ImapResponseParser {
|
|||||||
|
|
||||||
// 3 OK [READ-WRITE] Select completed.
|
// 3 OK [READ-WRITE] Select completed.
|
||||||
private String parseTaggedResponse() throws IOException {
|
private String parseTaggedResponse() throws IOException {
|
||||||
String tag = readStringUntil(' ');
|
return readStringUntil(' ');
|
||||||
return tag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImapList parseList(ImapList parent) throws IOException {
|
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);
|
Object keyObj = bracketed.get(0);
|
||||||
if (keyObj instanceof String) {
|
if (keyObj instanceof String) {
|
||||||
String key = (String) keyObj;
|
String key = (String) keyObj;
|
||||||
if (response.mTag != null) {
|
if (response.getTag() != null) {
|
||||||
|
|
||||||
if ("READ-ONLY".equalsIgnoreCase(key)) {
|
if ("READ-ONLY".equalsIgnoreCase(key)) {
|
||||||
mMode = OPEN_MODE_RO;
|
mMode = OPEN_MODE_RO;
|
||||||
@ -1253,7 +1253,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
List<Long> uids = new ArrayList<Long>();
|
List<Long> uids = new ArrayList<Long>();
|
||||||
List<ImapResponse> responses = searcher.search(); //
|
List<ImapResponse> responses = searcher.search(); //
|
||||||
for (ImapResponse response : responses) {
|
for (ImapResponse response : responses) {
|
||||||
if (response.mTag == null) {
|
if (response.getTag() == null) {
|
||||||
if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) {
|
if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) {
|
||||||
for (int i = 1, count = response.size(); i < count; i++) {
|
for (int i = 1, count = response.size(); i < count; i++) {
|
||||||
uids.add(response.getLong(i));
|
uids.add(response.getLong(i));
|
||||||
@ -1385,7 +1385,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
ImapResponse response;
|
ImapResponse response;
|
||||||
int messageNumber = 0;
|
int messageNumber = 0;
|
||||||
|
|
||||||
ImapResponseParser.IImapResponseCallback callback = null;
|
ImapResponseCallback callback = null;
|
||||||
if (fp.contains(FetchProfile.Item.BODY) || fp.contains(FetchProfile.Item.BODY_SANE)) {
|
if (fp.contains(FetchProfile.Item.BODY) || fp.contains(FetchProfile.Item.BODY_SANE)) {
|
||||||
callback = new FetchBodyCallback(messageMap);
|
callback = new FetchBodyCallback(messageMap);
|
||||||
}
|
}
|
||||||
@ -1393,7 +1393,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
do {
|
do {
|
||||||
response = mConnection.readResponse(callback);
|
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");
|
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
|
||||||
String uid = fetchList.getKeyedString("UID");
|
String uid = fetchList.getKeyedString("UID");
|
||||||
long msgSeq = response.getLong(0);
|
long msgSeq = response.getLong(0);
|
||||||
@ -1444,7 +1444,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
handleUntaggedResponse(response);
|
handleUntaggedResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (response.mTag == null);
|
} while (response.getTag() == null);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw ioExceptionHandler(mConnection, ioe);
|
throw ioExceptionHandler(mConnection, ioe);
|
||||||
}
|
}
|
||||||
@ -1479,12 +1479,12 @@ public class ImapStore extends RemoteStore {
|
|||||||
ImapResponse response;
|
ImapResponse response;
|
||||||
int messageNumber = 0;
|
int messageNumber = 0;
|
||||||
|
|
||||||
ImapResponseParser.IImapResponseCallback callback = new FetchPartCallback(part);
|
ImapResponseCallback callback = new FetchPartCallback(part);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
response = mConnection.readResponse(callback);
|
response = mConnection.readResponse(callback);
|
||||||
|
|
||||||
if ((response.mTag == null) &&
|
if ((response.getTag() == null) &&
|
||||||
(ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH"))) {
|
(ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH"))) {
|
||||||
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
|
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
|
||||||
String uid = fetchList.getKeyedString("UID");
|
String uid = fetchList.getKeyedString("UID");
|
||||||
@ -1531,7 +1531,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
handleUntaggedResponse(response);
|
handleUntaggedResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (response.mTag == null);
|
} while (response.getTag() == null);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw ioExceptionHandler(mConnection, ioe);
|
throw ioExceptionHandler(mConnection, ioe);
|
||||||
}
|
}
|
||||||
@ -1643,7 +1643,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
* @param response
|
* @param response
|
||||||
*/
|
*/
|
||||||
protected void handleUntaggedResponse(ImapResponse 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")) {
|
if (ImapResponseParser.equalsIgnoreCase(response.get(1), "EXISTS")) {
|
||||||
mMessageCount = response.getNumber(0);
|
mMessageCount = response.getNumber(0);
|
||||||
if (K9MailLib.isDebug())
|
if (K9MailLib.isDebug())
|
||||||
@ -1873,14 +1873,14 @@ public class ImapStore extends RemoteStore {
|
|||||||
do {
|
do {
|
||||||
response = mConnection.readResponse();
|
response = mConnection.readResponse();
|
||||||
handleUntaggedResponse(response);
|
handleUntaggedResponse(response);
|
||||||
if (response.mCommandContinuationRequested) {
|
if (response.isContinuationRequested()) {
|
||||||
EOLConvertingOutputStream eolOut = new EOLConvertingOutputStream(mConnection.getOutputStream());
|
EOLConvertingOutputStream eolOut = new EOLConvertingOutputStream(mConnection.getOutputStream());
|
||||||
message.writeTo(eolOut);
|
message.writeTo(eolOut);
|
||||||
eolOut.write('\r');
|
eolOut.write('\r');
|
||||||
eolOut.write('\n');
|
eolOut.write('\n');
|
||||||
eolOut.flush();
|
eolOut.flush();
|
||||||
}
|
}
|
||||||
} while (response.mTag == null);
|
} while (response.getTag() == null);
|
||||||
|
|
||||||
if (response.size() > 1) {
|
if (response.size() > 1) {
|
||||||
/*
|
/*
|
||||||
@ -1957,7 +1957,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
executeSimpleCommand(
|
executeSimpleCommand(
|
||||||
String.format("UID SEARCH HEADER MESSAGE-ID %s", encodeString(messageId)));
|
String.format("UID SEARCH HEADER MESSAGE-ID %s", encodeString(messageId)));
|
||||||
for (ImapResponse response1 : responses) {
|
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) {
|
&& response1.size() > 1) {
|
||||||
return response1.getString(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 {
|
public class ImapFolderPusher extends ImapFolder implements UntaggedHandler {
|
||||||
private final PushReceiver receiver;
|
private final PushReceiver receiver;
|
||||||
private Thread listeningThread = null;
|
private Thread listeningThread = null;
|
||||||
@ -2459,7 +2449,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleUntaggedResponse(ImapResponse response) {
|
protected void handleUntaggedResponse(ImapResponse response) {
|
||||||
if (response.mTag == null && response.size() > 1) {
|
if (response.getTag() == null && response.size() > 1) {
|
||||||
Object responseType = response.get(1);
|
Object responseType = response.get(1);
|
||||||
if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH")
|
if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH")
|
||||||
|| ImapResponseParser.equalsIgnoreCase(responseType, "EXPUNGE")
|
|| 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) {
|
protected int processUntaggedResponse(long oldMessageCount, ImapResponse response, List<Long> flagSyncMsgSeqs, List<String> removeMsgUids) {
|
||||||
super.handleUntaggedResponse(response);
|
super.handleUntaggedResponse(response);
|
||||||
int messageCountDelta = 0;
|
int messageCountDelta = 0;
|
||||||
if (response.mTag == null && response.size() > 1) {
|
if (response.getTag() == null && response.size() > 1) {
|
||||||
try {
|
try {
|
||||||
Object responseType = response.get(1);
|
Object responseType = response.get(1);
|
||||||
if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH")) {
|
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);
|
Log.e(LOG_TAG, "Exception while sending DONE for " + getLogId(), e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (response.mTag == null) {
|
if (response.getTag() == null) {
|
||||||
if (response.size() > 1) {
|
if (response.size() > 1) {
|
||||||
boolean started = false;
|
boolean started = false;
|
||||||
Object responseType = response.get(1);
|
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);
|
Log.e(LOG_TAG, "Exception while sending DONE for " + getLogId(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (response.mCommandContinuationRequested) {
|
} else if (response.isContinuationRequested()) {
|
||||||
if (K9MailLib.isDebug())
|
if (K9MailLib.isDebug())
|
||||||
Log.d(LOG_TAG, "Idling " + getLogId());
|
Log.d(LOG_TAG, "Idling " + getLogId());
|
||||||
|
|
||||||
@ -2812,10 +2802,6 @@ public class ImapStore extends RemoteStore {
|
|||||||
public void setLastRefresh(long lastRefresh) {
|
public void setLastRefresh(long lastRefresh) {
|
||||||
this.lastRefresh = lastRefresh;
|
this.lastRefresh = lastRefresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
public static interface UntaggedHandler {
|
|
||||||
void handleAsyncUntaggedResponse(ImapResponse respose);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ImapPushState {
|
protected static class ImapPushState {
|
||||||
@ -2856,7 +2842,7 @@ public class ImapStore extends RemoteStore {
|
|||||||
List<ImapResponse> search() throws IOException, MessagingException;
|
List<ImapResponse> search() throws IOException, MessagingException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class FetchBodyCallback implements ImapResponseParser.IImapResponseCallback {
|
private static class FetchBodyCallback implements ImapResponseCallback {
|
||||||
private Map<String, Message> mMessageMap;
|
private Map<String, Message> mMessageMap;
|
||||||
|
|
||||||
FetchBodyCallback(Map<String, Message> messageMap) {
|
FetchBodyCallback(Map<String, Message> messageMap) {
|
||||||
@ -2865,8 +2851,8 @@ public class ImapStore extends RemoteStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object foundLiteral(ImapResponse response,
|
public Object foundLiteral(ImapResponse response,
|
||||||
FixedLengthInputStream literal) throws IOException, Exception {
|
FixedLengthInputStream literal) throws MessagingException, IOException {
|
||||||
if (response.mTag == null &&
|
if (response.getTag() == null &&
|
||||||
ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
|
ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
|
||||||
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
|
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
|
||||||
String uid = fetchList.getKeyedString("UID");
|
String uid = fetchList.getKeyedString("UID");
|
||||||
@ -2875,13 +2861,13 @@ public class ImapStore extends RemoteStore {
|
|||||||
message.parse(literal);
|
message.parse(literal);
|
||||||
|
|
||||||
// Return placeholder object
|
// Return placeholder object
|
||||||
return Integer.valueOf(1);
|
return 1;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class FetchPartCallback implements ImapResponseParser.IImapResponseCallback {
|
private static class FetchPartCallback implements ImapResponseCallback {
|
||||||
private Part mPart;
|
private Part mPart;
|
||||||
|
|
||||||
FetchPartCallback(Part part) {
|
FetchPartCallback(Part part) {
|
||||||
@ -2890,8 +2876,8 @@ public class ImapStore extends RemoteStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object foundLiteral(ImapResponse response,
|
public Object foundLiteral(ImapResponse response,
|
||||||
FixedLengthInputStream literal) throws IOException, Exception {
|
FixedLengthInputStream literal) throws MessagingException, IOException {
|
||||||
if (response.mTag == null &&
|
if (response.getTag() == null &&
|
||||||
ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
|
ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
|
||||||
//TODO: check for correct UID
|
//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…
x
Reference in New Issue
Block a user