mail.store.* cleanups

This commit is contained in:
Jan Berkel 2014-12-18 09:33:09 +01:00
parent 3c38cb2d7f
commit 0f476978ce
25 changed files with 387 additions and 374 deletions

View File

@ -30,8 +30,6 @@ import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.Folder.FolderClass;
import com.fsck.k9.mail.filter.Base64;
import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory;
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mail.store.StoreConfig;
import com.fsck.k9.mailstore.StorageManager;

View File

@ -81,7 +81,7 @@ import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mailstore.StorageManager;
import com.fsck.k9.mail.store.WebDavStore;
import com.fsck.k9.mail.store.webdav.WebDavStore;
import com.fsck.k9.preferences.SettingsExporter;
import com.fsck.k9.preferences.SettingsImportExportException;
import com.fsck.k9.preferences.SettingsImporter;

View File

@ -39,7 +39,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;
import com.fsck.k9.mail.store.ImapStore;
import com.fsck.k9.mail.store.imap.ImapStore;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mail.transport.SmtpTransport;
import com.fsck.k9.view.ClientCertificateSpinner;

View File

@ -27,7 +27,7 @@ import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.CertificateValidationException;
import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.store.WebDavStore;
import com.fsck.k9.mail.store.webdav.WebDavStore;
import com.fsck.k9.mail.filter.Hex;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;

View File

@ -25,12 +25,12 @@ import com.fsck.k9.mail.ConnectionSecurity;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.store.ImapStore;
import com.fsck.k9.mail.store.Pop3Store;
import com.fsck.k9.mail.store.imap.ImapStore;
import com.fsck.k9.mail.store.pop3.Pop3Store;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mail.store.WebDavStore;
import com.fsck.k9.mail.store.ImapStore.ImapStoreSettings;
import com.fsck.k9.mail.store.WebDavStore.WebDavStoreSettings;
import com.fsck.k9.mail.store.webdav.WebDavStore;
import com.fsck.k9.mail.store.imap.ImapStore.ImapStoreSettings;
import com.fsck.k9.mail.store.webdav.WebDavStore.WebDavStoreSettings;
import com.fsck.k9.mail.transport.SmtpTransport;
import com.fsck.k9.service.MailService;
import com.fsck.k9.view.ClientCertificateSpinner;

View File

@ -88,7 +88,7 @@ import com.fsck.k9.mailstore.LocalFolder;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalStore;
import com.fsck.k9.mailstore.LocalStore.PendingCommand;
import com.fsck.k9.mail.store.Pop3Store;
import com.fsck.k9.mail.store.pop3.Pop3Store;
import com.fsck.k9.mailstore.UnavailableStorageException;
import com.fsck.k9.provider.EmailProvider;
import com.fsck.k9.provider.EmailProvider.StatsColumns;

View File

@ -142,7 +142,7 @@ public abstract class Folder<T extends Message> {
MessageRetrievalListener<T> listener) throws MessagingException;
public void fetchPart(Message message, Part part,
MessageRetrievalListener<T> listener) throws MessagingException {
MessageRetrievalListener<Message> listener) throws MessagingException {
// This is causing trouble. Disabled for now. See issue 1733
//throw new RuntimeException("fetchPart() not implemented.");
@ -227,7 +227,7 @@ public abstract class Folder<T extends Message> {
this.status = status;
}
public List<Message> search(String queryString, final Set<Flag> requiredFlags, final Set<Flag> forbiddenFlags)
public List<T> search(String queryString, final Set<Flag> requiredFlags, final Set<Flag> forbiddenFlags)
throws MessagingException {
throw new MessagingException("K-9 does not support searches on this folder type");
}

View File

@ -7,13 +7,13 @@ import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
import android.content.Context;
public interface PushReceiver {
public Context getContext();
public void syncFolder(Folder folder);
public void messagesArrived(Folder folder, List<Message> mess);
public void messagesFlagsChanged(Folder folder, List<Message> mess);
public void messagesRemoved(Folder folder, List<Message> mess);
public String getPushState(String folderName);
public void pushError(String errorMessage, Exception e);
public void setPushActive(String folderName, boolean enabled);
public void sleep(TracingWakeLock wakeLock, long millis);
Context getContext();
void syncFolder(Folder folder);
void messagesArrived(Folder folder, List<Message> mess);
void messagesFlagsChanged(Folder folder, List<Message> mess);
void messagesRemoved(Folder folder, List<Message> mess);
String getPushState(String folderName);
void pushError(String errorMessage, Exception e);
void setPushActive(String folderName, boolean enabled);
void sleep(TracingWakeLock wakeLock, long millis);
}

View File

@ -8,13 +8,16 @@ import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory;
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
import com.fsck.k9.mail.store.imap.ImapStore;
import com.fsck.k9.mail.store.pop3.Pop3Store;
import com.fsck.k9.mail.store.webdav.WebDavStore;
import java.util.HashMap;
import java.util.Map;
public abstract class RemoteStore extends Store {
protected static final int SOCKET_CONNECT_TIMEOUT = 30000;
protected static final int SOCKET_READ_TIMEOUT = 60000;
public static final int SOCKET_CONNECT_TIMEOUT = 30000;
public static final int SOCKET_READ_TIMEOUT = 60000;
protected StoreConfig mStoreConfig;
protected TrustedSocketFactory mTrustedSocketFactory;
@ -89,9 +92,9 @@ public abstract class RemoteStore extends Store {
*
* @return A {@link com.fsck.k9.mail.ServerSettings} object holding the settings contained in the URI.
*
* @see com.fsck.k9.mail.store.ImapStore#decodeUri(String)
* @see com.fsck.k9.mail.store.Pop3Store#decodeUri(String)
* @see com.fsck.k9.mail.store.WebDavStore#decodeUri(String)
* @see com.fsck.k9.mail.store.imap.ImapStore#decodeUri(String)
* @see com.fsck.k9.mail.store.pop3.Pop3Store#decodeUri(String)
* @see com.fsck.k9.mail.store.webdav.WebDavStore#decodeUri(String)
*/
public static ServerSettings decodeStoreUri(String uri) {
if (uri.startsWith("imap")) {
@ -113,9 +116,9 @@ public abstract class RemoteStore extends Store {
*
* @return A store URI that holds the same information as the {@code server} parameter.
*
* @see com.fsck.k9.mail.store.ImapStore#createUri(com.fsck.k9.mail.ServerSettings)
* @see com.fsck.k9.mail.store.Pop3Store#createUri(com.fsck.k9.mail.ServerSettings)
* @see com.fsck.k9.mail.store.WebDavStore#createUri(com.fsck.k9.mail.ServerSettings)
* @see com.fsck.k9.mail.store.imap.ImapStore#createUri(com.fsck.k9.mail.ServerSettings)
* @see com.fsck.k9.mail.store.pop3.Pop3Store#createUri(com.fsck.k9.mail.ServerSettings)
* @see com.fsck.k9.mail.store.webdav.WebDavStore#createUri(com.fsck.k9.mail.ServerSettings)
*/
public static String createStoreUri(ServerSettings server) {
if (ImapStore.STORE_TYPE.equals(server.type)) {

View File

@ -1,4 +1,4 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.imap;
class ImapCommands {
static final String COMMAND_IDLE = "IDLE";

View File

@ -1,4 +1,4 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.imap;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@ -13,6 +13,7 @@ import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.filter.Base64;
import com.fsck.k9.mail.filter.PeekableInputStream;
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mail.transport.imap.ImapSettings;
import com.jcraft.jzlib.JZlib;
import com.jcraft.jzlib.ZOutputStream;
@ -83,13 +84,13 @@ class ImapConnection {
return "conn" + hashCode();
}
private List<ImapResponseParser.ImapResponse> receiveCapabilities(List<ImapResponseParser.ImapResponse> responses) {
for (ImapResponseParser.ImapResponse response : responses) {
ImapResponseParser.ImapList capabilityList = null;
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 ImapResponseParser.ImapList) {
ImapResponseParser.ImapList thisList = (ImapResponseParser.ImapList)thisPart;
if (thisPart instanceof ImapList) {
ImapList thisList = (ImapList)thisPart;
if (ImapResponseParser.equalsIgnoreCase(thisList.get(0), ImapCommands.CAPABILITY_CAPABILITY)) {
capabilityList = thisList;
break;
@ -186,18 +187,18 @@ class ImapConnection {
mOut = new BufferedOutputStream(mSocket.getOutputStream(), 1024);
capabilities.clear();
ImapResponseParser.ImapResponse nullResponse = mParser.readResponse();
ImapResponse nullResponse = mParser.readResponse();
if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP)
Log.v(LOG_TAG, getLogId() + "<<<" + nullResponse);
List<ImapResponseParser.ImapResponse> nullResponses = new LinkedList<ImapResponseParser.ImapResponse>();
List<ImapResponse> nullResponses = new LinkedList<ImapResponse>();
nullResponses.add(nullResponse);
receiveCapabilities(nullResponses);
if (!hasCapability(ImapCommands.CAPABILITY_CAPABILITY)) {
if (K9MailLib.isDebug())
Log.i(LOG_TAG, "Did not get capabilities in banner, requesting CAPABILITY for " + getLogId());
List<ImapResponseParser.ImapResponse> responses = receiveCapabilities(executeSimpleCommand(ImapCommands.COMMAND_CAPABILITY));
List<ImapResponse> responses = receiveCapabilities(executeSimpleCommand(ImapCommands.COMMAND_CAPABILITY));
if (responses.size() != 2) {
throw new MessagingException("Invalid CAPABILITY response received");
}
@ -223,7 +224,7 @@ class ImapConnection {
if (K9MailLib.isDebug())
Log.i(LOG_TAG, "Updating capabilities after STARTTLS for " + getLogId());
capabilities.clear();
List<ImapResponseParser.ImapResponse> responses = receiveCapabilities(executeSimpleCommand(ImapCommands.COMMAND_CAPABILITY));
List<ImapResponse> responses = receiveCapabilities(executeSimpleCommand(ImapCommands.COMMAND_CAPABILITY));
if (responses.size() != 2) {
throw new MessagingException("Invalid CAPABILITY response received");
}
@ -319,23 +320,23 @@ class ImapConnection {
if (hasCapability(ImapCommands.CAPABILITY_NAMESPACE)) {
if (K9MailLib.isDebug())
Log.i(LOG_TAG, "mPathPrefix is unset and server has NAMESPACE capability");
List<ImapResponseParser.ImapResponse> namespaceResponses =
List<ImapResponse> namespaceResponses =
executeSimpleCommand(ImapCommands.COMMAND_NAMESPACE);
for (ImapResponseParser.ImapResponse response : namespaceResponses) {
for (ImapResponse response : namespaceResponses) {
if (ImapResponseParser.equalsIgnoreCase(response.get(0), ImapCommands.COMMAND_NAMESPACE)) {
if (K9MailLib.isDebug())
Log.d(LOG_TAG, "Got NAMESPACE response " + response + " on " + getLogId());
Object personalNamespaces = response.get(1);
if (personalNamespaces != null && personalNamespaces instanceof ImapResponseParser.ImapList) {
if (personalNamespaces != null && personalNamespaces instanceof ImapList) {
if (K9MailLib.isDebug())
Log.d(LOG_TAG, "Got personal namespaces: " + personalNamespaces);
ImapResponseParser.ImapList bracketed = (ImapResponseParser.ImapList)personalNamespaces;
ImapList bracketed = (ImapList)personalNamespaces;
Object firstNamespace = bracketed.get(0);
if (firstNamespace != null && firstNamespace instanceof ImapResponseParser.ImapList) {
if (firstNamespace != null && firstNamespace instanceof ImapList) {
if (K9MailLib.isDebug())
Log.d(LOG_TAG, "Got first personal namespaces: " + firstNamespace);
bracketed = (ImapResponseParser.ImapList)firstNamespace;
bracketed = (ImapList)firstNamespace;
mSettings.setPathPrefix(bracketed.getString(0));
mSettings.setPathDelimeter(bracketed.getString(1));
mSettings.setCombinedPrefix(null);
@ -353,9 +354,9 @@ class ImapConnection {
}
if (mSettings.getPathDelimeter() == null) {
try {
List<ImapResponseParser.ImapResponse> nameResponses =
List<ImapResponse> nameResponses =
executeSimpleCommand("LIST \"\" \"\"");
for (ImapResponseParser.ImapResponse response : nameResponses) {
for (ImapResponse response : nameResponses) {
if (ImapResponseParser.equalsIgnoreCase(response.get(0), "LIST")) {
mSettings.setPathDelimeter(response.getString(2));
mSettings.setCombinedPrefix(null);
@ -380,7 +381,7 @@ class ImapConnection {
} catch (ConnectException ce) {
String ceMess = ce.getMessage();
String[] tokens = ceMess.split("-");
if (tokens != null && tokens.length > 1 && tokens[1] != null) {
if (tokens.length > 1 && tokens[1] != null) {
Log.e(LOG_TAG, "Stripping host/port from ConnectionException for " + getLogId(), ce);
throw new ConnectException(tokens[1].trim());
} else {
@ -419,7 +420,7 @@ class ImapConnection {
protected void authCramMD5() throws MessagingException, IOException {
String command = "AUTHENTICATE CRAM-MD5";
String tag = sendCommand(command, false);
ImapResponseParser.ImapResponse response = readContinuationResponse(tag);
ImapResponse response = readContinuationResponse(tag);
if (response.size() != 1 || !(response.get(0) instanceof String)) {
throw new MessagingException("Invalid Cram-MD5 nonce received");
}
@ -471,9 +472,9 @@ class ImapConnection {
}
}
protected ImapResponseParser.ImapResponse readContinuationResponse(String tag)
protected ImapResponse readContinuationResponse(String tag)
throws IOException, MessagingException {
ImapResponseParser.ImapResponse response;
ImapResponse response;
do {
response = readResponse();
if (response.mTag != null) {
@ -490,11 +491,11 @@ class ImapConnection {
return response;
}
protected List<ImapResponseParser.ImapResponse> readStatusResponse(String tag,
protected List<ImapResponse> readStatusResponse(String tag,
String commandToLog, ImapStore.UntaggedHandler untaggedHandler)
throws IOException, MessagingException {
List<ImapResponseParser.ImapResponse> responses = new ArrayList<ImapResponseParser.ImapResponse>();
ImapResponseParser.ImapResponse response;
List<ImapResponse> responses = new ArrayList<ImapResponse>();
ImapResponse response;
do {
response = mParser.readResponse();
if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP)
@ -502,9 +503,9 @@ class ImapConnection {
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<ImapResponseParser.ImapResponse> iter = responses.iterator();
Iterator<ImapResponse> iter = responses.iterator();
while (iter.hasNext()) {
ImapResponseParser.ImapResponse delResponse = iter.next();
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();
@ -562,13 +563,13 @@ class ImapConnection {
mSocket = null;
}
public ImapResponseParser.ImapResponse readResponse() throws IOException, MessagingException {
public ImapResponse readResponse() throws IOException, MessagingException {
return readResponse(null);
}
public ImapResponseParser.ImapResponse readResponse(ImapResponseParser.IImapResponseCallback callback) throws IOException {
public ImapResponse readResponse(ImapResponseParser.IImapResponseCallback callback) throws IOException {
try {
ImapResponseParser.ImapResponse response = mParser.readResponse(callback);
ImapResponse response = mParser.readResponse(callback);
if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP)
Log.v(LOG_TAG, getLogId() + "<<<" + response);
@ -621,17 +622,17 @@ class ImapConnection {
}
}
public List<ImapResponseParser.ImapResponse> executeSimpleCommand(String command) throws IOException,
public List<ImapResponse> executeSimpleCommand(String command) throws IOException,
MessagingException {
return executeSimpleCommand(command, false, null);
}
public List<ImapResponseParser.ImapResponse> executeSimpleCommand(String command, boolean sensitive) throws IOException,
public List<ImapResponse> executeSimpleCommand(String command, boolean sensitive) throws IOException,
MessagingException {
return executeSimpleCommand(command, sensitive, null);
}
public List<ImapResponseParser.ImapResponse> executeSimpleCommand(String command, boolean sensitive, ImapStore.UntaggedHandler untaggedHandler)
public List<ImapResponse> executeSimpleCommand(String command, boolean sensitive, ImapStore.UntaggedHandler untaggedHandler)
throws IOException, MessagingException {
String commandToLog = command;
if (sensitive && !K9MailLib.isDebugSensitive()) {

View File

@ -0,0 +1,131 @@
package com.fsck.k9.mail.store.imap;
import com.fsck.k9.mail.MessagingException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
/**
* Represents an IMAP list response and is also the base class for the
* ImapResponse.
*/
public class ImapList extends ArrayList<Object> {
private static final long serialVersionUID = -4067248341419617583L;
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.US);
private static final DateFormat BAD_DATE_TIME_FORMAT = new SimpleDateFormat("dd MMM yyyy HH:mm:ss Z", Locale.US);
private static final DateFormat BAD_DATE_TIME_FORMAT_2 = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z", Locale.US);
private static final DateFormat BAD_DATE_TIME_FORMAT_3 = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss", Locale.US);
public ImapList getList(int index) {
return (ImapList)get(index);
}
public Object getObject(int index) {
return get(index);
}
public String getString(int index) {
return (String)get(index);
}
public long getLong(int index) {
return Long.parseLong(getString(index));
}
public int getNumber(int index) {
return Integer.parseInt(getString(index));
}
public Date getDate(int index) throws MessagingException {
return getDate(getString(index));
}
public Date getKeyedDate(Object key) throws MessagingException {
return getDate(getKeyedString(key));
}
private Date getDate(String value) throws MessagingException {
try {
if (value == null) {
return null;
}
return parseDate(value);
} catch (ParseException pe) {
throw new MessagingException("Unable to parse IMAP datetime '" + value + "' ", pe);
}
}
public Object getKeyedValue(Object key) {
for (int i = 0, count = size() - 1; i < count; i++) {
if (ImapResponseParser.equalsIgnoreCase(get(i), key)) {
return get(i + 1);
}
}
return null;
}
public ImapList getKeyedList(Object key) {
return (ImapList)getKeyedValue(key);
}
public String getKeyedString(Object key) {
return (String)getKeyedValue(key);
}
public int getKeyedNumber(Object key) {
return Integer.parseInt(getKeyedString(key));
}
public boolean containsKey(Object key) {
if (key == null) {
return false;
}
for (int i = 0, count = size() - 1; i < count; i++) {
if (ImapResponseParser.equalsIgnoreCase(key, get(i))) {
return true;
}
}
return false;
}
public int getKeyIndex(Object key) {
for (int i = 0, count = size() - 1; i < count; i++) {
if (ImapResponseParser.equalsIgnoreCase(key, get(i))) {
return i;
}
}
throw new IllegalArgumentException("getKeyIndex() only works for keys that are in the collection.");
}
private Date parseDate(String value) throws ParseException {
//TODO: clean this up a bit
try {
synchronized (DATE_FORMAT) {
return DATE_FORMAT.parse(value);
}
} catch (Exception e) {
try {
synchronized (BAD_DATE_TIME_FORMAT) {
return BAD_DATE_TIME_FORMAT.parse(value);
}
} catch (Exception e2) {
try {
synchronized (BAD_DATE_TIME_FORMAT_2) {
return BAD_DATE_TIME_FORMAT_2.parse(value);
}
} catch (Exception e3) {
synchronized (BAD_DATE_TIME_FORMAT_3) {
return BAD_DATE_TIME_FORMAT_3.parse(value);
}
}
}
}
}
}

View File

@ -0,0 +1,48 @@
package com.fsck.k9.mail.store.imap;
/**
* Represents a single response from the IMAP server.
*
* <p>
* Tagged responses will have a non-null tag. Untagged responses will have a null tag. The
* object will contain all of the available tokens at the time the response is received.
* </p>
*/
public class ImapResponse extends ImapList {
private static final long serialVersionUID = 6886458551615975669L;
private ImapResponseParser.IImapResponseCallback mCallback;
boolean mCommandContinuationRequested;
String mTag;
public ImapResponse(ImapResponseParser.IImapResponseCallback mCallback) {
this.mCallback = mCallback;
}
public ImapResponseParser.IImapResponseCallback getCallback() {
return mCallback;
}
public void setCallback(ImapResponseParser.IImapResponseCallback mCallback) {
this.mCallback = mCallback;
}
public String getAlertText() {
if (size() > 1 && ImapResponseParser.equalsIgnoreCase("[ALERT]", get(1))) {
StringBuilder sb = new StringBuilder();
for (int i = 2, count = size(); i < count; i++) {
sb.append(get(i).toString());
sb.append(' ');
}
return sb.toString();
} else {
return null;
}
}
@Override
public String toString() {
return "#" + (mCommandContinuationRequested ? "+" : mTag) + "# " + super.toString();
}
}

View File

@ -1,21 +1,12 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.imap;
import android.text.TextUtils;
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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
class ImapResponseParser {
private static final SimpleDateFormat mDateTimeFormat = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.US);
private static final SimpleDateFormat badDateTimeFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss Z", Locale.US);
private static final SimpleDateFormat badDateTimeFormat2 = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z", Locale.US);
private static final SimpleDateFormat badDateTimeFormat3 = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss", Locale.US);
private PeekableInputStream mIn;
private ImapResponse mResponse;
@ -35,29 +26,27 @@ class ImapResponseParser {
*/
public ImapResponse readResponse(IImapResponseCallback callback) throws IOException {
try {
ImapResponse response = new ImapResponse();
mResponse = response;
mResponse.mCallback = callback;
mResponse = new ImapResponse(callback);
mResponse.setCallback(callback);
int ch = mIn.peek();
if (ch == '*') {
parseUntaggedResponse();
readTokens(response);
readTokens(mResponse);
} else if (ch == '+') {
response.mCommandContinuationRequested = parseCommandContinuationRequest();
parseResponseText(response);
mResponse.mCommandContinuationRequested = parseCommandContinuationRequest();
parseResponseText(mResponse);
} else {
response.mTag = parseTaggedResponse();
readTokens(response);
mResponse.mTag = parseTaggedResponse();
readTokens(mResponse);
}
if (mException != null) {
throw new RuntimeException("readResponse(): Exception in callback method", mException);
}
return response;
return mResponse;
} finally {
mResponse.mCallback = null;
mResponse = null;
mException = null;
}
@ -281,12 +270,12 @@ class ImapResponseParser {
return "";
}
if (mResponse.mCallback != null) {
if (mResponse.getCallback() != null) {
FixedLengthInputStream fixed = new FixedLengthInputStream(mIn, size);
Object result = null;
try {
result = mResponse.mCallback.foundLiteral(mResponse, fixed);
result = mResponse.getCallback().foundLiteral(mResponse, fixed);
} catch (IOException e) {
// Pass IOExceptions through
throw e;
@ -365,160 +354,6 @@ class ImapResponseParser {
return d;
}
/**
* Represents an IMAP list response and is also the base class for the
* ImapResponse.
*/
public static class ImapList extends ArrayList<Object> {
private static final long serialVersionUID = -4067248341419617583L;
public ImapList getList(int index) {
return (ImapList)get(index);
}
public Object getObject(int index) {
return get(index);
}
public String getString(int index) {
return (String)get(index);
}
public long getLong(int index) {
return Long.parseLong(getString(index));
}
public int getNumber(int index) {
return Integer.parseInt(getString(index));
}
public Date getDate(int index) throws MessagingException {
return getDate(getString(index));
}
public Date getKeyedDate(Object key) throws MessagingException {
return getDate(getKeyedString(key));
}
private Date getDate(String value) throws MessagingException {
try {
if (value == null) {
return null;
}
return parseDate(value);
} catch (ParseException pe) {
throw new MessagingException("Unable to parse IMAP datetime '" + value + "' ", pe);
}
}
public Object getKeyedValue(Object key) {
for (int i = 0, count = size() - 1; i < count; i++) {
if (equalsIgnoreCase(get(i), key)) {
return get(i + 1);
}
}
return null;
}
public ImapList getKeyedList(Object key) {
return (ImapList)getKeyedValue(key);
}
public String getKeyedString(Object key) {
return (String)getKeyedValue(key);
}
public int getKeyedNumber(Object key) {
return Integer.parseInt(getKeyedString(key));
}
public boolean containsKey(Object key) {
if (key == null) {
return false;
}
for (int i = 0, count = size() - 1; i < count; i++) {
if (equalsIgnoreCase(key, get(i))) {
return true;
}
}
return false;
}
public int getKeyIndex(Object key) {
for (int i = 0, count = size() - 1; i < count; i++) {
if (equalsIgnoreCase(key, get(i))) {
return i;
}
}
throw new IllegalArgumentException("getKeyIndex() only works for keys that are in the collection.");
}
private Date parseDate(String value) throws ParseException {
//TODO: clean this up a bit
try {
synchronized (mDateTimeFormat) {
return mDateTimeFormat.parse(value);
}
} catch (Exception e) {
try {
synchronized (badDateTimeFormat) {
return badDateTimeFormat.parse(value);
}
} catch (Exception e2) {
try {
synchronized (badDateTimeFormat2) {
return badDateTimeFormat2.parse(value);
}
} catch (Exception e3) {
synchronized (badDateTimeFormat3) {
return badDateTimeFormat3.parse(value);
}
}
}
}
}
}
/**
* Represents a single response from the IMAP server.
*
* <p>
* Tagged responses will have a non-null tag. Untagged responses will have a null tag. The
* object will contain all of the available tokens at the time the response is received.
* </p>
*/
public class ImapResponse extends ImapList {
/**
*
*/
private static final long serialVersionUID = 6886458551615975669L;
private IImapResponseCallback mCallback;
boolean mCommandContinuationRequested;
String mTag;
public String getAlertText() {
if (size() > 1 && equalsIgnoreCase("[ALERT]", get(1))) {
StringBuilder sb = new StringBuilder();
for (int i = 2, count = size(); i < count; i++) {
sb.append(get(i).toString());
sb.append(' ');
}
return sb.toString();
} else {
return null;
}
}
@Override
public String toString() {
return "#" + (mCommandContinuationRequested ? "+" : mTag) + "# " + super.toString();
}
}
public boolean isStatusResponse(String symbol) {
return symbol.equalsIgnoreCase("OK") ||
symbol.equalsIgnoreCase("NO") ||
@ -560,7 +395,6 @@ class ImapResponseParser {
* and the exception will be thrown after the
* complete IMAP response has been parsed.
*/
public Object foundLiteral(ImapResponse response, FixedLengthInputStream literal)
throws IOException, Exception;
public Object foundLiteral(ImapResponse response, FixedLengthInputStream literal) throws Exception;
}
}

View File

@ -1,5 +1,5 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.imap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ -61,8 +61,8 @@ import com.fsck.k9.mail.internet.MimeMessage;
import com.fsck.k9.mail.internet.MimeMultipart;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mail.store.StoreConfig;
import com.fsck.k9.mail.transport.imap.ImapSettings;
import com.beetstra.jutf7.CharsetProvider;
@ -81,15 +81,25 @@ public class ImapStore extends RemoteStore {
private static final int IDLE_READ_TIMEOUT_INCREMENT = 5 * 60 * 1000;
private static final int IDLE_FAILURE_COUNT_LIMIT = 10;
private static int MAX_DELAY_TIME = 5 * 60 * 1000; // 5 minutes
private static int NORMAL_DELAY_TIME = 5000;
private static final int MAX_DELAY_TIME = 5 * 60 * 1000; // 5 minutes
private static final int NORMAL_DELAY_TIME = 5000;
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final int FETCH_WINDOW_SIZE = 100;
private Set<Flag> mPermanentFlagsIndex = EnumSet.noneOf(Flag.class);
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private ConnectivityManager mConnectivityManager;
private String mHost;
private int mPort;
private String mUsername;
private String mPassword;
private String mClientCertificateAlias;
private ConnectionSecurity mConnectionSecurity;
private AuthType mAuthType;
private String mPathPrefix;
private String mCombinedPrefix = null;
private String mPathDelimiter = null;
/**
* Decodes an ImapStore URI.
*
@ -293,91 +303,7 @@ public class ImapStore extends RemoteStore {
}
private String mHost;
private int mPort;
private String mUsername;
private String mPassword;
private String mClientCertificateAlias;
private ConnectionSecurity mConnectionSecurity;
private AuthType mAuthType;
private volatile String mPathPrefix;
private volatile String mCombinedPrefix = null;
private volatile String mPathDelimeter = null;
public class StoreImapSettings implements ImapSettings {
@Override
public String getHost() {
return mHost;
}
@Override
public int getPort() {
return mPort;
}
@Override
public ConnectionSecurity getConnectionSecurity() {
return mConnectionSecurity;
}
@Override
public AuthType getAuthType() {
return mAuthType;
}
@Override
public String getUsername() {
return mUsername;
}
@Override
public String getPassword() {
return mPassword;
}
@Override
public String getClientCertificateAlias() {
return mClientCertificateAlias;
}
@Override
public boolean useCompression(final int type) {
return mStoreConfig.useCompression(type);
}
@Override
public String getPathPrefix() {
return mPathPrefix;
}
@Override
public void setPathPrefix(String prefix) {
mPathPrefix = prefix;
}
@Override
public String getPathDelimeter() {
return mPathDelimeter;
}
@Override
public void setPathDelimeter(String delimeter) {
mPathDelimeter = delimeter;
}
@Override
public String getCombinedPrefix() {
return mCombinedPrefix;
}
@Override
public void setCombinedPrefix(String prefix) {
mCombinedPrefix = prefix;
}
}
private static final SimpleDateFormat RFC3501_DATE = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
protected static final SimpleDateFormat RFC3501_DATE = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
private final Deque<ImapConnection> mConnections =
new LinkedList<ImapConnection>();
@ -442,7 +368,7 @@ public class ImapStore extends RemoteStore {
if (mCombinedPrefix == null) {
if (mPathPrefix != null) {
String tmpPrefix = mPathPrefix.trim();
String tmpDelim = (mPathDelimeter != null ? mPathDelimeter.trim() : "");
String tmpDelim = (mPathDelimiter != null ? mPathDelimiter.trim() : "");
if (tmpPrefix.endsWith(tmpDelim)) {
mCombinedPrefix = tmpPrefix;
} else if (tmpPrefix.length() > 0) {
@ -525,8 +451,8 @@ public class ImapStore extends RemoteStore {
String folder = decodedFolderName;
if (mPathDelimeter == null) {
mPathDelimeter = response.getString(2);
if (mPathDelimiter == null) {
mPathDelimiter = response.getString(2);
mCombinedPrefix = null;
}
@ -612,8 +538,8 @@ public class ImapStore extends RemoteStore {
continue;
}
if (mPathDelimeter == null) {
mPathDelimeter = response.getString(2);
if (mPathDelimiter == null) {
mPathDelimiter = response.getString(2);
mCombinedPrefix = null;
}
@ -1265,12 +1191,12 @@ public class ImapStore extends RemoteStore {
@Override
public List<? extends Message> getMessages(int start, int end, Date earliestDate, MessageRetrievalListener listener)
public List<ImapMessage> getMessages(int start, int end, Date earliestDate, MessageRetrievalListener listener)
throws MessagingException {
return getMessages(start, end, earliestDate, false, listener);
}
protected List<? extends Message> getMessages(final int start, final int end, Date earliestDate, final boolean includeDeleted, final MessageRetrievalListener listener)
protected List<ImapMessage> getMessages(final int start, final int end, Date earliestDate, final boolean includeDeleted, final MessageRetrievalListener listener)
throws MessagingException {
if (start < 1 || end < 1 || end < start) {
throw new MessagingException(
@ -1295,7 +1221,9 @@ public class ImapStore extends RemoteStore {
return search(searcher, listener);
}
protected List<? extends Message> getMessages(final List<Long> mesgSeqs, final boolean includeDeleted, final MessageRetrievalListener listener)
protected List<ImapMessage> getMessages(final List<Long> mesgSeqs,
final boolean includeDeleted,
final MessageRetrievalListener listener)
throws MessagingException {
ImapSearcher searcher = new ImapSearcher() {
@Override
@ -1306,8 +1234,9 @@ public class ImapStore extends RemoteStore {
return search(searcher, listener);
}
protected List<? extends Message> getMessagesFromUids(final List<String> mesgUids, final boolean includeDeleted, final MessageRetrievalListener listener)
throws MessagingException {
protected List<? extends Message> getMessagesFromUids(final List<String> mesgUids,
final boolean includeDeleted,
final MessageRetrievalListener listener) throws MessagingException {
ImapSearcher searcher = new ImapSearcher() {
@Override
public List<ImapResponse> search() throws IOException, MessagingException {
@ -1317,10 +1246,9 @@ public class ImapStore extends RemoteStore {
return search(searcher, listener);
}
private List<Message> search(ImapSearcher searcher, MessageRetrievalListener<ImapMessage> listener) throws MessagingException {
protected List<ImapMessage> search(ImapSearcher searcher, MessageRetrievalListener<ImapMessage> listener) throws MessagingException {
checkOpen(); //only need READ access
List<Message> messages = new ArrayList<Message>();
List<ImapMessage> messages = new ArrayList<ImapMessage>();
try {
List<Long> uids = new ArrayList<Long>();
List<ImapResponse> responses = searcher.search(); //
@ -1359,15 +1287,15 @@ public class ImapStore extends RemoteStore {
@Override
public List<? extends Message> getMessages(MessageRetrievalListener listener) throws MessagingException {
public List<ImapMessage> getMessages(MessageRetrievalListener<ImapMessage> listener) throws MessagingException {
return getMessages(null, listener);
}
@Override
public List<? extends Message> getMessages(String[] uids, MessageRetrievalListener listener)
public List<ImapMessage> getMessages(String[] uids, MessageRetrievalListener<ImapMessage> listener)
throws MessagingException {
checkOpen(); //only need READ access
List<Message> messages = new ArrayList<Message>();
List<ImapMessage> messages = new ArrayList<ImapMessage>();
try {
if (uids == null) {
List<ImapResponse> responses = executeSimpleCommand("UID SEARCH 1:* NOT DELETED");
@ -1525,7 +1453,7 @@ public class ImapStore extends RemoteStore {
@Override
public void fetchPart(Message message, Part part, MessageRetrievalListener listener)
public void fetchPart(Message message, Part part, MessageRetrievalListener<Message> listener)
throws MessagingException {
checkOpen(); //only need READ access
@ -2176,7 +2104,7 @@ public class ImapStore extends RemoteStore {
* @throws MessagingException On any error.
*/
@Override
public List<Message> search(final String queryString, final Set<Flag> requiredFlags, final Set<Flag> forbiddenFlags)
public List<ImapMessage> search(final String queryString, final Set<Flag> requiredFlags, final Set<Flag> forbiddenFlags)
throws MessagingException {
if (!mStoreConfig.allowRemoteSearch()) {
@ -2312,11 +2240,6 @@ public class ImapStore extends RemoteStore {
super(message, true);
this.mAlertText = alertText;
}
public String getAlertText() {
return mAlertText;
}
}
public class ImapFolderPusher extends ImapFolder implements UntaggedHandler {
@ -2465,7 +2388,7 @@ public class ImapStore extends RemoteStore {
}
} else {
List<ImapResponse> untaggedResponses = null;
List<ImapResponse> untaggedResponses;
while (!storedUntaggedResponses.isEmpty()) {
if (K9MailLib.isDebug())
Log.i(LOG_TAG, "Processing " + storedUntaggedResponses.size() + " untagged responses from previous commands for " + getLogId());
@ -2929,15 +2852,15 @@ public class ImapStore extends RemoteStore {
}
}
private interface ImapSearcher {
protected interface ImapSearcher {
List<ImapResponse> search() throws IOException, MessagingException;
}
private static class FetchBodyCallback implements ImapResponseParser.IImapResponseCallback {
private Map<String, Message> mMessageMap;
FetchBodyCallback(Map<String, Message> mesageMap) {
mMessageMap = mesageMap;
FetchBodyCallback(Map<String, Message> messageMap) {
mMessageMap = messageMap;
}
@Override
@ -2990,4 +2913,76 @@ public class ImapStore extends RemoteStore {
}
return TextUtils.join(String.valueOf(separator), parts);
}
private class StoreImapSettings implements ImapSettings {
@Override
public String getHost() {
return mHost;
}
@Override
public int getPort() {
return mPort;
}
@Override
public ConnectionSecurity getConnectionSecurity() {
return mConnectionSecurity;
}
@Override
public AuthType getAuthType() {
return mAuthType;
}
@Override
public String getUsername() {
return mUsername;
}
@Override
public String getPassword() {
return mPassword;
}
@Override
public String getClientCertificateAlias() {
return mClientCertificateAlias;
}
@Override
public boolean useCompression(final int type) {
return mStoreConfig.useCompression(type);
}
@Override
public String getPathPrefix() {
return mPathPrefix;
}
@Override
public void setPathPrefix(String prefix) {
mPathPrefix = prefix;
}
@Override
public String getPathDelimeter() {
return mPathDelimiter;
}
@Override
public void setPathDelimeter(String delimeter) {
mPathDelimiter = delimeter;
}
@Override
public String getCombinedPrefix() {
return mCombinedPrefix;
}
@Override
public void setCombinedPrefix(String prefix) {
mCombinedPrefix = prefix;
}
}
}

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.imap;
import android.util.Log;

View File

@ -1,5 +1,5 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.pop3;
import android.util.Log;
@ -10,6 +10,8 @@ import com.fsck.k9.mail.internet.MimeMessage;
import com.fsck.k9.mail.CertificateValidationException;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mail.store.StoreConfig;
import javax.net.ssl.SSLException;

View File

@ -1,4 +1,4 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.webdav;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.LayeredSocketFactory;

View File

@ -1,4 +1,4 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.webdav;
import android.util.Log;
@ -8,6 +8,8 @@ import com.fsck.k9.mail.filter.EOLConvertingOutputStream;
import com.fsck.k9.mail.internet.MimeMessage;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.CertificateValidationException;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mail.store.StoreConfig;
import org.apache.commons.io.IOUtils;
import org.apache.http.*;

View File

@ -9,7 +9,7 @@ import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.store.StoreConfig;
import com.fsck.k9.mail.store.WebDavStore;
import com.fsck.k9.mail.store.webdav.WebDavStore;
import java.util.Collections;

View File

@ -2,7 +2,7 @@ package com.fsck.k9.mail.transport.imap;
import com.fsck.k9.mail.AuthType;
import com.fsck.k9.mail.ConnectionSecurity;
import com.fsck.k9.mail.store.ImapStore;
import com.fsck.k9.mail.store.imap.ImapStore;
/**
* Settings source for IMAP. Implemented in order to remove coupling between {@link ImapStore} and {@link com.fsck.k9.mail.store.ImapConnection}.

View File

@ -28,7 +28,7 @@ import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.filter.Base64;
import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mail.store.WebDavStore;
import com.fsck.k9.mail.store.webdav.WebDavStore;
import com.fsck.k9.preferences.Settings.InvalidSettingValueException;
public class SettingsImporter {

View File

@ -1,10 +1,8 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.imap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import com.fsck.k9.mail.filter.PeekableInputStream;
import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
import junit.framework.TestCase;
public class ImapResponseParserTest extends TestCase {

View File

@ -1,4 +1,4 @@
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.imap;
import java.util.HashMap;
import java.util.Map;
@ -6,6 +6,7 @@ import java.util.Map;
import com.fsck.k9.mail.AuthType;
import com.fsck.k9.mail.ConnectionSecurity;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.store.RemoteStore;
import junit.framework.TestCase;

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
package com.fsck.k9.mail.store;
package com.fsck.k9.mail.store.imap;
import java.util.List;
import android.test.MoreAsserts;