diff --git a/src/com/android/email/mail/FetchProfile.java b/src/com/android/email/mail/FetchProfile.java index e5449e6b8..cdd109191 100644 --- a/src/com/android/email/mail/FetchProfile.java +++ b/src/com/android/email/mail/FetchProfile.java @@ -28,15 +28,15 @@ import java.util.ArrayList; * Part: Indicates that the given Part should be fetched. The provider * is expected have previously created the given BodyPart and stored * any information it needs to download the content. - * + * */ -public class FetchProfile extends ArrayList { +public class FetchProfile extends ArrayList { /** * Default items available for pre-fetching. It should be expected that any * item fetched by using these items could potentially include all of the * previous items. */ - public enum Item { + public enum Item implements Fetchable { /** * Download the flags of the message. */ @@ -54,7 +54,7 @@ public class FetchProfile extends ArrayList { * The provider should, if possible, fill in a properly formatted MIME structure in * the message without actually downloading any message data. If the provider is not * capable of this operation it should specifically set the body of the message to null - * so that upper levels can detect that a full body download is needed. + * so that upper levels can detect that a full body download is needed. */ STRUCTURE, @@ -63,7 +63,7 @@ public class FetchProfile extends ArrayList { * This should generaly be around 50kB. */ BODY_SANE, - + /** * The entire message. */ diff --git a/src/com/android/email/mail/Fetchable.java b/src/com/android/email/mail/Fetchable.java new file mode 100644 index 000000000..a3b5465a5 --- /dev/null +++ b/src/com/android/email/mail/Fetchable.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.email.mail; + +/** + * Interface for classes that can be added to {@link FetchProfile}. + * i.e. {@link Part} and its subclasses, and {@link FetchProfile.Item}. + */ +public interface Fetchable { +} diff --git a/src/com/android/email/mail/Part.java b/src/com/android/email/mail/Part.java index fe1f258b5..683d79784 100644 --- a/src/com/android/email/mail/Part.java +++ b/src/com/android/email/mail/Part.java @@ -19,7 +19,7 @@ package com.android.email.mail; import java.io.IOException; import java.io.OutputStream; -public interface Part { +public interface Part extends Fetchable { public void addHeader(String name, String value) throws MessagingException; public void removeHeader(String name) throws MessagingException; @@ -31,17 +31,17 @@ public interface Part { public String getContentType() throws MessagingException; public String getDisposition() throws MessagingException; - + public String getContentId() throws MessagingException; public String[] getHeader(String name) throws MessagingException; public void setExtendedHeader(String name, String value) throws MessagingException; - + public String getExtendedHeader(String name) throws MessagingException; - + public int getSize() throws MessagingException; - + public boolean isMimeType(String mimeType) throws MessagingException; public String getMimeType() throws MessagingException; diff --git a/src/com/android/email/mail/internet/MimeUtility.java b/src/com/android/email/mail/internet/MimeUtility.java index ee65cf02a..c89dc0a64 100644 --- a/src/com/android/email/mail/internet/MimeUtility.java +++ b/src/com/android/email/mail/internet/MimeUtility.java @@ -44,6 +44,7 @@ import java.util.regex.Pattern; public class MimeUtility { + public static final String MIME_TYPE_RFC822 = "message/rfc822"; private final static Pattern PATTERN_CR_OR_LF = Pattern.compile("\r|\n"); /** @@ -179,6 +180,8 @@ public class MimeUtility { * TODO: Also has a latent bug: uses "startsWith" to match the name, which can false-positive. * TODO: The doc says that for a null name you get the first param, but you get the header. * Should probably just fix the doc, but if other code assumes that behavior, fix the code. + * TODO: Need to decode %-escaped strings, as in: filename="ab%22d". + * ('+' -> ' ' conversion too? check RFC) * * @param header * @param name diff --git a/src/com/android/email/mail/store/ImapStore.java b/src/com/android/email/mail/store/ImapStore.java index 5019cc90f..cd4d7db1e 100644 --- a/src/com/android/email/mail/store/ImapStore.java +++ b/src/com/android/email/mail/store/ImapStore.java @@ -77,6 +77,7 @@ import javax.net.ssl.SSLException; * TODO Need to start keeping track of UIDVALIDITY * TODO Need a default response handler for things like folder updates * TODO In fetch(), if we need a ImapMessage and were given + * TODO Collect ALERT messages and show them to users. * something else we can try to do a pre-fetch first. * * ftp://ftp.isi.edu/in-notes/rfc2683.txt When a client asks for @@ -230,7 +231,8 @@ public class ImapStore extends Store { * @param capability the capabilities string from the server * @return a String for use in an IMAP ID message. */ - public String getImapId(Context context, String userName, String host, String capability) { + public static String getImapId(Context context, String userName, String host, + String capability) { // The first section is global to all IMAP connections, and generates the fixed // values in any IMAP ID message synchronized (ImapStore.class) { @@ -290,7 +292,7 @@ public class ImapStore extends Store { * @param networkOperator TelephonyManager.getNetworkOperatorName() * @return the static (never changes) portion of the IMAP ID */ - /* package */ String makeCommonImapId(String packageName, String version, + /* package */ static String makeCommonImapId(String packageName, String version, String codeName, String model, String id, String vendor, String networkOperator) { // Before building up IMAP ID string, pre-filter the input strings for "legal" chars @@ -363,7 +365,7 @@ public class ImapStore extends Store { synchronized (mFolderCache) { folder = mFolderCache.get(name); if (folder == null) { - folder = new ImapFolder(name); + folder = new ImapFolder(this, name); mFolderCache.put(name, folder); } } @@ -413,8 +415,7 @@ public class ImapStore extends Store { ImapConnection connection = new ImapConnection(); connection.open(); connection.close(); - } - catch (IOException ioe) { + } catch (IOException ioe) { throw new MessagingException(MessagingException.IOERROR, ioe.toString()); } } @@ -457,8 +458,7 @@ public class ImapStore extends Store { byte[] b = new byte[bb.limit()]; bb.get(b); return new String(b, "US-ASCII"); - } - catch (UnsupportedEncodingException uee) { + } catch (UnsupportedEncodingException uee) { /* * The only thing that can throw this is getBytes("US-ASCII") and if US-ASCII doesn't * exist we're totally screwed. @@ -476,8 +476,7 @@ public class ImapStore extends Store { byte[] encoded = name.getBytes("US-ASCII"); CharBuffer cb = MODIFIED_UTF_7_CHARSET.decode(ByteBuffer.wrap(encoded)); return cb.toString(); - } - catch (UnsupportedEncodingException uee) { + } catch (UnsupportedEncodingException uee) { /* * The only thing that can throw this is getBytes("US-ASCII") and if US-ASCII doesn't * exist we're totally screwed. @@ -486,15 +485,17 @@ public class ImapStore extends Store { } } - class ImapFolder extends Folder { + static class ImapFolder extends Folder { + private final ImapStore mStore; private final String mName; private int mMessageCount = -1; private ImapConnection mConnection; private OpenMode mMode; private boolean mExists; - public ImapFolder(String name) { - this.mName = name; + public ImapFolder(ImapStore store, String name) { + mStore = store; + mName = name; } @Override @@ -512,7 +513,7 @@ public class ImapStore extends Store { } } synchronized (this) { - mConnection = getConnection(); + mConnection = mStore.getConnection(); } // * FLAGS (\Answered \Flagged \Deleted \Seen \Draft NonJunk // $MDNSent) @@ -578,7 +579,7 @@ public class ImapStore extends Store { // TODO implement expunge mMessageCount = -1; synchronized (this) { - poolConnection(mConnection); + mStore.poolConnection(mConnection); mConnection = null; } } @@ -601,9 +602,8 @@ public class ImapStore extends Store { ImapConnection connection = null; synchronized(this) { if (mConnection == null) { - connection = getConnection(); - } - else { + connection = mStore.getConnection(); + } else { connection = mConnection; } } @@ -612,16 +612,16 @@ public class ImapStore extends Store { encodeFolderName(mName))); mExists = true; return true; - } - catch (MessagingException me) { + + } catch (MessagingException me) { return false; - } - catch (IOException ioe) { + + } catch (IOException ioe) { throw ioExceptionHandler(connection, ioe); - } - finally { + + } finally { if (mConnection == null) { - poolConnection(connection); + mStore.poolConnection(connection); } } } @@ -642,9 +642,8 @@ public class ImapStore extends Store { ImapConnection connection = null; synchronized(this) { if (mConnection == null) { - connection = getConnection(); - } - else { + connection = mStore.getConnection(); + } else { connection = mConnection; } } @@ -652,16 +651,16 @@ public class ImapStore extends Store { connection.executeSimpleCommand(String.format("CREATE \"%s\"", encodeFolderName(mName))); return true; - } - catch (MessagingException me) { + + } catch (MessagingException me) { return false; - } - catch (IOException ioe) { + + } catch (IOException ioe) { throw ioExceptionHandler(connection, ioe); - } - finally { + + } finally { if (mConnection == null) { - poolConnection(connection); + mStore.poolConnection(connection); } } } @@ -678,8 +677,7 @@ public class ImapStore extends Store { mConnection.executeSimpleCommand(String.format("UID COPY %s \"%s\"", Utility.combine(uids, ','), encodeFolderName(folder.getName()))); - } - catch (IOException ioe) { + } catch (IOException ioe) { throw ioExceptionHandler(mConnection, ioe); } } @@ -704,8 +702,7 @@ public class ImapStore extends Store { } } return unreadMessageCount; - } - catch (IOException ioe) { + } catch (IOException ioe) { throw ioExceptionHandler(mConnection, ioe); } } @@ -1007,7 +1004,7 @@ public class ImapStore extends Store { } } - private void parseBodyStructure(ImapList bs, Part part, String id) + private static void parseBodyStructure(ImapList bs, Part part, String id) throws MessagingException { if (bs.get(0) instanceof ImapList) { /* @@ -1020,7 +1017,7 @@ public class ImapStore extends Store { * For each part in the message we're going to add a new BodyPart and parse * into it. */ - ImapBodyPart bp = new ImapBodyPart(); + MimeBodyPart bp = new MimeBodyPart(); if (id.equals("TEXT")) { parseBodyStructure(bs.getList(i), bp, Integer.toString(i + 1)); } @@ -1040,8 +1037,7 @@ public class ImapStore extends Store { } } part.setBody(mp); - } - else{ + } else { /* * This is a body. We need to add as much information as we can find out about * it to the Part. @@ -1070,16 +1066,18 @@ public class ImapStore extends Store { String encoding = bs.getString(5); int size = bs.getNumber(6); - if (MimeUtility.mimeTypeMatches(mimeType, "message/rfc822")) { -// A body type of type MESSAGE and subtype RFC822 -// contains, immediately after the basic fields, the -// envelope structure, body structure, and size in -// text lines of the encapsulated message. -// [MESSAGE, RFC822, [NAME, Fwd: [#HTR-517941]: update plans at 1am Friday - Memory allocation - displayware.eml], NIL, NIL, 7BIT, 5974, NIL, [INLINE, [FILENAME*0, Fwd: [#HTR-517941]: update plans at 1am Friday - Memory all, FILENAME*1, ocation - displayware.eml]], NIL] + if (MimeUtility.mimeTypeMatches(mimeType, MimeUtility.MIME_TYPE_RFC822)) { + // A body type of type MESSAGE and subtype RFC822 + // contains, immediately after the basic fields, the + // envelope structure, body structure, and size in + // text lines of the encapsulated message. + // [MESSAGE, RFC822, [NAME, filename.eml], NIL, NIL, 7BIT, 5974, NIL, + // [INLINE, [FILENAME*0, Fwd: Xxx..., FILENAME*1, filename.eml]], NIL] /* * This will be caught by fetch and handled appropriately. */ - throw new MessagingException("BODYSTRUCTURE message/rfc822 not yet supported."); + throw new MessagingException("BODYSTRUCTURE " + MimeUtility.MIME_TYPE_RFC822 + + " not yet supported."); } /* @@ -1161,11 +1159,9 @@ public class ImapStore extends Store { if (part instanceof ImapMessage) { ((ImapMessage) part).setSize(size); - } - else if (part instanceof ImapBodyPart) { - ((ImapBodyPart) part).setSize(size); - } - else { + } else if (part instanceof MimeBodyPart) { + ((MimeBodyPart) part).setSize(size); + } else { throw new MessagingException("Unknown part type " + part.toString()); } part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, id); @@ -1220,8 +1216,7 @@ public class ImapStore extends Store { eolOut.write('\r'); eolOut.write('\n'); eolOut.flush(); - } - else if (response.mTag == null) { + } else if (response.mTag == null) { handleUntaggedResponse(response); } while (response.more()); @@ -1256,10 +1251,8 @@ public class ImapStore extends Store { message.setUid(response1.getString(response1.size()-1)); } } - } - } - catch (IOException ioe) { + } catch (IOException ioe) { throw ioExceptionHandler(mConnection, ioe); } } @@ -1305,8 +1298,8 @@ public class ImapStore extends Store { uidList, value ? "+" : "-", allFlags)); - } - catch (IOException ioe) { + + } catch (IOException ioe) { throw ioExceptionHandler(mConnection, ioe); } } @@ -1448,13 +1441,6 @@ public class ImapStore extends Store { } public void close() { -// if (isOpen()) { -// try { -// executeSimpleCommand("LOGOUT"); -// } catch (Exception e) { -// -// } -// } if (mTransport != null) { mTransport.close(); mTransport = null; @@ -1529,7 +1515,7 @@ public class ImapStore extends Store { } } - class ImapMessage extends MimeMessage { + static class ImapMessage extends MimeMessage { ImapMessage(String uid, Folder folder) throws MessagingException { this.mUid = uid; this.mFolder = folder; @@ -1555,17 +1541,7 @@ public class ImapStore extends Store { } } - class ImapBodyPart extends MimeBodyPart { - public ImapBodyPart() throws MessagingException { - super(); - } - -// public void setSize(int size) { -// this.mSize = size; -// } - } - - class ImapException extends MessagingException { + static class ImapException extends MessagingException { String mAlertText; public ImapException(String message, String alertText, Throwable throwable) {