FileDocCategorySizeDatePackage
ImapStore.javaAPI DocAndroid 1.5 API52332Wed May 06 22:42:46 BST 2009com.android.email.mail.store

ImapStore

public class ImapStore extends com.android.email.mail.Store
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
something else we can try to do a pre-fetch first.

ftp://ftp.isi.edu/in-notes/rfc2683.txt When a client asks for
certain information in a FETCH command, the server may return the requested
information in any order, not necessarily in the order that it was requested.
Further, the server may return the information in separate FETCH responses
and may also return information that was not explicitly requested (to reflect
to the client changes in the state of the subject message).

Fields Summary
public static final int
CONNECTION_SECURITY_NONE
public static final int
CONNECTION_SECURITY_TLS_OPTIONAL
public static final int
CONNECTION_SECURITY_TLS_REQUIRED
public static final int
CONNECTION_SECURITY_SSL_REQUIRED
public static final int
CONNECTION_SECURITY_SSL_OPTIONAL
private static final com.android.email.mail.Flag[]
PERMANENT_FLAGS
private com.android.email.mail.Transport
mRootTransport
private String
mUsername
private String
mPassword
private String
mLoginPhrase
private String
mPathPrefix
private LinkedList
mConnections
private Charset
mModifiedUtf7Charset
Charset used for converting folder names to and from UTF-7 as defined by RFC 3501.
private HashMap
mFolderCache
Cache of ImapFolder objects. ImapFolders are attached to a given folder on the server and as long as their associated connection remains open they are reusable between requests. This cache lets us make sure we always reuse, if possible, for a given folder name.
Constructors Summary
public ImapStore(String uriString)
Allowed formats for the Uri: imap://user:password@server:port CONNECTION_SECURITY_NONE imap+tls://user:password@server:port CONNECTION_SECURITY_TLS_OPTIONAL imap+tls+://user:password@server:port CONNECTION_SECURITY_TLS_REQUIRED imap+ssl+://user:password@server:port CONNECTION_SECURITY_SSL_REQUIRED imap+ssl://user:password@server:port CONNECTION_SECURITY_SSL_OPTIONAL

param
uriString the Uri containing information to configure this store


                                  
         
        URI uri;
        try {
            uri = new URI(uriString);
        } catch (URISyntaxException use) {
            throw new MessagingException("Invalid ImapStore URI", use);
        }

        String scheme = uri.getScheme();
        int connectionSecurity = Transport.CONNECTION_SECURITY_NONE;
        int defaultPort = -1;
        if (scheme.equals("imap")) {
            connectionSecurity = CONNECTION_SECURITY_NONE;
            defaultPort = 143;
        } else if (scheme.equals("imap+tls")) {
            connectionSecurity = CONNECTION_SECURITY_TLS_OPTIONAL;
            defaultPort = 143;
        } else if (scheme.equals("imap+tls+")) {
            connectionSecurity = CONNECTION_SECURITY_TLS_REQUIRED;
            defaultPort = 143;
        } else if (scheme.equals("imap+ssl+")) {
            connectionSecurity = CONNECTION_SECURITY_SSL_REQUIRED;
            defaultPort = 993;
        } else if (scheme.equals("imap+ssl")) {
            connectionSecurity = CONNECTION_SECURITY_SSL_OPTIONAL;
            defaultPort = 993;
        } else {
            throw new MessagingException("Unsupported protocol");
        }

        mRootTransport = new MailTransport("IMAP");
        mRootTransport.setUri(uri, defaultPort);
        mRootTransport.setSecurity(connectionSecurity);

        String[] userInfoParts = mRootTransport.getUserInfoParts();
        if (userInfoParts != null) {
            mUsername = userInfoParts[0];
            if (userInfoParts.length > 1) {
                mPassword = userInfoParts[1];
                
                // build the LOGIN string once (instead of over-and-over again.)
                // apply the quoting here around the built-up password
                mLoginPhrase = "LOGIN " + mUsername + " " + Utility.imapQuoted(mPassword);
            }
        }

        if ((uri.getPath() != null) && (uri.getPath().length() > 0)) {
            mPathPrefix = uri.getPath().substring(1);
        }

        mModifiedUtf7Charset = new CharsetProvider().charsetForName("X-RFC-3501");
    
Methods Summary
public voidcheckSettings()

        try {
            ImapConnection connection = new ImapConnection();
            connection.open();
            connection.close();
        }
        catch (IOException ioe) {
            throw new MessagingException(MessagingException.IOERROR, ioe.toString());
        }
    
private java.lang.StringdecodeFolderName(java.lang.String name)

        /*
         * Convert the encoded name to US-ASCII, then pass it through the modified UTF-7
         * decoder and return the Unicode String.
         */
        try {
            byte[] encoded = name.getBytes("US-ASCII");
            CharBuffer cb = mModifiedUtf7Charset.decode(ByteBuffer.wrap(encoded));
            return cb.toString();
        }
        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.
             */
            throw new RuntimeException("Unable to decode folder name: " + name, uee);
        }
    
private java.lang.StringencodeFolderName(java.lang.String name)

        try {
            ByteBuffer bb = mModifiedUtf7Charset.encode(name);
            byte[] b = new byte[bb.limit()];
            bb.get(b);
            return new String(b, "US-ASCII");
        }
        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.
             */
            throw new RuntimeException("Unabel to encode folder name: " + name, uee);
        }
    
private com.android.email.mail.store.ImapStore$ImapConnectiongetConnection()
Gets a connection if one is available for reuse, or creates a new one if not.

return

        synchronized (mConnections) {
            ImapConnection connection = null;
            while ((connection = mConnections.poll()) != null) {
                try {
                    connection.executeSimpleCommand("NOOP");
                    break;
                }
                catch (IOException ioe) {
                    connection.close();
                }
            }
            if (connection == null) {
                connection = new ImapConnection();
            }
            return connection;
        }
    
public com.android.email.mail.FoldergetFolder(java.lang.String name)

        ImapFolder folder;
        synchronized (mFolderCache) {
            folder = mFolderCache.get(name);
            if (folder == null) {
                folder = new ImapFolder(name);
                mFolderCache.put(name, folder);
            }
        }
        return folder;
    
public com.android.email.mail.Folder[]getPersonalNamespaces()

        ImapConnection connection = getConnection();
        try {
            ArrayList<Folder> folders = new ArrayList<Folder>();
            List<ImapResponse> responses =
                    connection.executeSimpleCommand(String.format("LIST \"\" \"%s*\"",
                        mPathPrefix == null ? "" : mPathPrefix));
            for (ImapResponse response : responses) {
                if (response.get(0).equals("LIST")) {
                    boolean includeFolder = true;
                    String folder = decodeFolderName(response.getString(3));
                    if (folder.equalsIgnoreCase("INBOX")) {
                        continue;
                    }
                    ImapList attributes = response.getList(1);
                    for (int i = 0, count = attributes.size(); i < count; i++) {
                        String attribute = attributes.getString(i);
                        if (attribute.equalsIgnoreCase("\\NoSelect")) {
                            includeFolder = false;
                        }
                    }
                    if (includeFolder) {
                        folders.add(getFolder(folder));
                    }
                }
            }
            folders.add(getFolder("INBOX"));
            return folders.toArray(new Folder[] {});
        } catch (IOException ioe) {
            connection.close();
            throw new MessagingException("Unable to get folder list.", ioe);
        } finally {
            releaseConnection(connection);
        }
    
private voidreleaseConnection(com.android.email.mail.store.ImapStore$ImapConnection connection)

        mConnections.offer(connection);
    
voidsetTransport(com.android.email.mail.Transport testTransport)
For testing only. Injects a different root transport (it will be copied using newInstanceWithConfiguration() each time IMAP sets up a new channel). The transport should already be set up and ready to use. Do not use for real code.

param
testTransport The Transport to inject and use for all future communication.

        mRootTransport = testTransport;