196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/* 296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License. 696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at 796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and 1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License. 1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email.mail.store; 1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 19627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blankimport android.content.Context; 20627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blankimport android.os.Bundle; 21627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blankimport android.util.Log; 22627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank 23e71a19a52313a0fb615700e52a336b65f3c305daBen Komaloimport com.android.email.Controller; 2496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.Email; 2596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.Store; 2696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.Transport; 2796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.transport.MailTransport; 2831d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.Logging; 292193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.MimeMessage; 302193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.AuthenticationFailedException; 312193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.FetchProfile; 322193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Flag; 332193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Folder; 34627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blankimport com.android.emailcommon.mail.Folder.OpenMode; 352193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Message; 362193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessagingException; 37f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blankimport com.android.emailcommon.provider.Account; 3812b82d9374947c9268217f45befe8a74bd9b60d7Ben Komaloimport com.android.emailcommon.provider.HostAuth; 3953ea83ebf91f820692e8fa8e781f5cc982dd94dbBen Komaloimport com.android.emailcommon.provider.Mailbox; 400d4fc55861ed4393aa82f124f2865695ef564641Marc Blankimport com.android.emailcommon.service.EmailServiceProxy; 41627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blankimport com.android.emailcommon.service.SearchParams; 4231d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.utility.LoggingInputStream; 4331d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.utility.Utility; 44745b33b8ff55e9a9c4871f07f9d97db893f784b2Makoto Onukiimport com.google.common.annotations.VisibleForTesting; 4596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.IOException; 4796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStream; 4896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.ArrayList; 4996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.HashMap; 5096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.HashSet; 5196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 5296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class Pop3Store extends Store { 5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // All flags defining debug or development code settings must be FALSE 5496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // when code is checked in or released. 5596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static boolean DEBUG_FORCE_SINGLE_LINE_UIDL = false; 563469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project private static boolean DEBUG_LOG_RAW_STREAM = false; 57dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki 5896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED }; 5922208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy /** The name of the only mailbox available to POP3 accounts */ 6022208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy private static final String POP3_MAILBOX_NAME = "INBOX"; 61b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final HashMap<String, Folder> mFolders = new HashMap<String, Folder>(); 6296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 6396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// /** 6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * Detected latency, used for usage scaling. 65171c3f2273223652b9999977d530a715420c0f64Todd Kennedy// * Usage scaling occurs when it is necessary to get information about 6696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * messages that could result in large data loads. This value allows 6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * the code that loads this data to decide between using large downloads 6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * (high latency) or multiple round trips (low latency) to accomplish 6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * the same thing. 7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * Default is Integer.MAX_VALUE implying massive latency so that the large 7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * download method is used by default until latency data is collected. 7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// */ 7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// private int mLatencyMs = Integer.MAX_VALUE; 7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// 7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// /** 7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * Detected throughput, used for usage scaling. 77171c3f2273223652b9999977d530a715420c0f64Todd Kennedy// * Usage scaling occurs when it is necessary to get information about 7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * messages that could result in large data loads. This value allows 7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * the code that loads this data to decide between using large downloads 8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * (high latency) or multiple round trips (low latency) to accomplish 8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * the same thing. 8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * Default is Integer.MAX_VALUE implying massive bandwidth so that the 8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * large download method is used by default until latency data is 8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// * collected. 8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// */ 8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// private int mThroughputKbS = Integer.MAX_VALUE; 8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 89ae8ca3fbd1545c3a94011d7d70bcadac99e7779fAndy Stadler * Static named constructor. 90ae8ca3fbd1545c3a94011d7d70bcadac99e7779fAndy Stadler */ 9135b0e95ca795e17b6dc8dd98c7ab847d65d9aa0cMarc Blank public static Store newInstance(Account account, Context context) throws MessagingException { 92a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy return new Pop3Store(context, account); 93ae8ca3fbd1545c3a94011d7d70bcadac99e7779fAndy Stadler } 94ae8ca3fbd1545c3a94011d7d70bcadac99e7779fAndy Stadler 95ae8ca3fbd1545c3a94011d7d70bcadac99e7779fAndy Stadler /** 96a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy * Creates a new store for the given account. 9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 98a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy private Pop3Store(Context context, Account account) throws MessagingException { 99200c6bd9fa19b78acc2c1664f858521aa9885353Todd Kennedy mContext = context; 100200c6bd9fa19b78acc2c1664f858521aa9885353Todd Kennedy mAccount = account; 101200c6bd9fa19b78acc2c1664f858521aa9885353Todd Kennedy 102a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy HostAuth recvAuth = account.getOrCreateHostAuthRecv(context); 1036fea021e3dbe71aaa93512aba699d1bfda3d520dMarc Blank if (recvAuth == null || !HostAuth.SCHEME_POP3.equalsIgnoreCase(recvAuth.mProtocol)) { 104e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler throw new MessagingException("Unsupported protocol"); 105e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler } 106e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler // defaults, which can be changed by security modifiers 10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int connectionSecurity = Transport.CONNECTION_SECURITY_NONE; 108e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler int defaultPort = 110; 109a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy 110a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy // check for security flags and apply changes 111a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy if ((recvAuth.mFlags & HostAuth.FLAG_SSL) != 0) { 112e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler connectionSecurity = Transport.CONNECTION_SECURITY_SSL; 11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project defaultPort = 995; 114a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy } else if ((recvAuth.mFlags & HostAuth.FLAG_TLS) != 0) { 115e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler connectionSecurity = Transport.CONNECTION_SECURITY_TLS; 11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 117a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy boolean trustCertificates = ((recvAuth.mFlags & HostAuth.FLAG_TRUST_ALL) != 0); 118e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler 119a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy int port = defaultPort; 120a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy if (recvAuth.mPort != HostAuth.PORT_UNKNOWN) { 121a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy port = recvAuth.mPort; 122a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy } 12396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport = new MailTransport("POP3"); 124a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy mTransport.setHost(recvAuth.mAddress); 125a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy mTransport.setPort(port); 126e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler mTransport.setSecurity(connectionSecurity, trustCertificates); 12796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 128a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy String[] userInfoParts = recvAuth.getLogin(); 12996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (userInfoParts != null) { 13096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUsername = userInfoParts[0]; 131a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy mPassword = userInfoParts[1]; 13296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 13396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 134dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki 13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * For testing only. Injects a different transport. The transport should already be set 13796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * up and ready to use. Do not use for real code. 13896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param testTransport The Transport to inject and use for all future communication. 13996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 14096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* package */ void setTransport(Transport testTransport) { 14196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport = testTransport; 14296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 14396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 14496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 145a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public Folder getFolder(String name) { 14696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Folder folder = mFolders.get(name); 14796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (folder == null) { 14896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project folder = new Pop3Folder(name); 14996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mFolders.put(folder.getName(), folder); 15096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 15196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return folder; 15296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 15396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 154e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo private final int[] DEFAULT_FOLDERS = { 155e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo Mailbox.TYPE_DRAFTS, 156e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo Mailbox.TYPE_OUTBOX, 157e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo Mailbox.TYPE_SENT, 158e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo Mailbox.TYPE_TRASH 159e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo }; 160e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo 16196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 16222208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy public Folder[] updateFolders() { 1630b8e04c84def3a06ef45126b48efc485fa0a7628Marc Blank Mailbox mailbox = Mailbox.getMailboxForPath(mContext, mAccount.mId, POP3_MAILBOX_NAME); 164019341af98ffe2dcd484bd0468c9858d9e7cd7a3Todd Kennedy updateMailbox(mailbox, mAccount.mId, POP3_MAILBOX_NAME, '\0', true, Mailbox.TYPE_INBOX); 165e07ecb8864b2b77270a1fa4844d6614c93c7291bTodd Kennedy // Force the parent key to be "no mailbox" for the mail POP3 mailbox 166e07ecb8864b2b77270a1fa4844d6614c93c7291bTodd Kennedy mailbox.mParentKey = Mailbox.NO_MAILBOX; 16722208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy if (mailbox.isSaved()) { 16822208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy mailbox.update(mContext, mailbox.toContentValues()); 16922208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy } else { 17022208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy mailbox.save(mContext); 17122208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy } 172e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo 173e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo // Build default mailboxes as well, in case they're not already made. 174e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo for (int type : DEFAULT_FOLDERS) { 175e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo if (Mailbox.findMailboxOfType(mContext, mAccount.mId, type) == Mailbox.NO_MAILBOX) { 176e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo String name = Controller.getMailboxServerName(mContext, type); 177e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo Mailbox.newSystemMailbox(mAccount.mId, type, name).save(mContext); 178e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo } 179e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo } 180e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo 18122208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy return new Folder[] { getFolder(POP3_MAILBOX_NAME) }; 18296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 18396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 18496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 18596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Used by account setup to test if an account's settings are appropriate. The definition 18696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * of "checked" here is simply, can you log into the account and does it meet some minimum set 18796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * of feature requirements? 188dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @throws MessagingException if there was some problem with the account 19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 192d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank public Bundle checkSettings() throws MessagingException { 19322208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy Pop3Folder folder = new Pop3Folder(POP3_MAILBOX_NAME); 194d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank Bundle bundle = null; 19554ab7a27a3756a241ba06f0762969cf5a338bf60Andy Stadler // Close any open or half-open connections - checkSettings should always be "fresh" 19654ab7a27a3756a241ba06f0762969cf5a338bf60Andy Stadler if (mTransport.isOpen()) { 19754ab7a27a3756a241ba06f0762969cf5a338bf60Andy Stadler folder.close(false); 19854ab7a27a3756a241ba06f0762969cf5a338bf60Andy Stadler } 19996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 200244d306ebb0addbc5d87008af9412b76c80e861eMarc Blank folder.open(OpenMode.READ_WRITE); 201d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank bundle = folder.checkSettings(); 20296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } finally { 20396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project folder.close(false); // false == don't expunge anything 20496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 205d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank return bundle; 20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project class Pop3Folder extends Folder { 209b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final HashMap<String, Pop3Message> mUidToMsgMap 210b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki = new HashMap<String, Pop3Message>(); 211b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final HashMap<Integer, Pop3Message> mMsgNumToMsgMap 212b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki = new HashMap<Integer, Pop3Message>(); 213b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final HashMap<String, Integer> mUidToMsgNumMap = new HashMap<String, Integer>(); 214b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final String mName; 21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private int mMessageCount; 21696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private Pop3Capabilities mCapabilities; 21796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 21896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Pop3Folder(String name) { 21922208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy if (name.equalsIgnoreCase(POP3_MAILBOX_NAME)) { 22022208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy mName = POP3_MAILBOX_NAME; 221b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki } else { 222b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki mName = name; 22396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 225dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki 22696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 22796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Used by account setup to test if an account's settings are appropriate. Here, we run 22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * an additional test to see if UIDL is supported on the server. If it's not we 22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * can't service this account. 230dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 231d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank * @return Bundle containing validation data (code and, if appropriate, error message) 23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @throws MessagingException if the account is not going to be useable 23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 234d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank public Bundle checkSettings() throws MessagingException { 235d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank Bundle bundle = new Bundle(); 236d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank int result = MessagingException.NO_ERROR; 23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!mCapabilities.uidl) { 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 23996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project UidlParser parser = new UidlParser(); 24096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project executeSimpleCommand("UIDL"); 24196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // drain the entire output, so additional communications don't get confused. 24296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response; 24396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((response = mTransport.readLine()) != null) { 24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project parser.parseMultiLine(response); 24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (parser.mEndOfMessage) { 24696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project break; 24796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (IOException ioe) { 25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.close(); 251d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank result = MessagingException.IOERROR; 252d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank bundle.putString(EmailServiceProxy.VALIDATE_BUNDLE_ERROR_MESSAGE, 253d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank ioe.getMessage()); 25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 256d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank bundle.putInt(EmailServiceProxy.VALIDATE_BUNDLE_RESULT_CODE, result); 257d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank return bundle; 25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 26096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 261244d306ebb0addbc5d87008af9412b76c80e861eMarc Blank public synchronized void open(OpenMode mode) throws MessagingException { 26296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mTransport.isOpen()) { 26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 26496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 26622208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy if (!mName.equalsIgnoreCase(POP3_MAILBOX_NAME)) { 26796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("Folder does not exist"); 26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.open(); 27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 27396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Eat the banner 27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project executeSimpleCommand(null); 27596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 27696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mCapabilities = getCapabilities(); 27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 27896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mTransport.canTryTlsSecurity()) { 27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mCapabilities.stls) { 2803b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project executeSimpleCommand("STLS"); 28196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.reopenTls(); 282e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler } else { 2838d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (Email.DEBUG) { 28431d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "TLS not supported but required"); 28596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException(MessagingException.TLS_REQUIRED); 28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 29196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project executeSensitiveCommand("USER " + mUsername, "USER /redacted/"); 29296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project executeSensitiveCommand("PASS " + mPassword, "PASS /redacted/"); 29396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (MessagingException me) { 2948d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (Email.DEBUG) { 29531d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, me.toString()); 29696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new AuthenticationFailedException(null, me); 29896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (IOException ioe) { 300092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler mTransport.close(); 3018d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (Email.DEBUG) { 30231d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, ioe.toString()); 30396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 30496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException(MessagingException.IOERROR, ioe.toString()); 30596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 30696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 307092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler Exception statException = null; 30896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 30996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = executeSimpleCommand("STAT"); 31096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String[] parts = response.split(" "); 311092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler if (parts.length < 2) { 312092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler statException = new IOException(); 313092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } else { 314092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler mMessageCount = Integer.parseInt(parts[1]); 315092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } 316092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } catch (IOException ioe) { 317092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler statException = ioe; 318092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } catch (NumberFormatException nfe) { 319092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler statException = nfe; 32096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 321092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler if (statException != null) { 322092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler mTransport.close(); 3238d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (Email.DEBUG) { 32431d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, statException.toString()); 32596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 326092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler throw new MessagingException("POP3 STAT", statException); 32796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 32896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUidToMsgMap.clear(); 32996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mMsgNumToMsgMap.clear(); 33096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUidToMsgNumMap.clear(); 33196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 33296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 33396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 334a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public OpenMode getMode() { 3354f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi return OpenMode.READ_WRITE; 33696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 33796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 33896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 339dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * Close the folder (and the transport below it). 340dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 34196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * MUST NOT return any exceptions. 342dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 34396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param expunge If true all deleted messages will be expunged (TODO - not implemented) 34496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 34596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 34696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void close(boolean expunge) { 34796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 34896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project executeSimpleCommand("QUIT"); 34996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 35096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (Exception e) { 35196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // ignore any problems here - just continue closing 35296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 35396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.close(); 35496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 35596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 35696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 35796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String getName() { 35896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mName; 35996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 36096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 361c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // POP3 does not folder creation 362165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 363c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler public boolean canCreate(FolderType type) { 364c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler return false; 365c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 366c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 36796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 368a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public boolean create(FolderType type) { 36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 37096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 37296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 373a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public boolean exists() { 37422208771b7b39c5d131372ba6bc45ab23cc22232Todd Kennedy return mName.equalsIgnoreCase(POP3_MAILBOX_NAME); 37596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int getMessageCount() { 37996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mMessageCount; 38096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 383a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public int getUnreadMessageCount() { 38496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return -1; 38596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 38796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 38896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Message getMessage(String uid) throws MessagingException { 3894f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi if (mUidToMsgNumMap.size() == 0) { 3904f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi try { 3914f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi indexMsgNums(1, mMessageCount); 3924f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi } catch (IOException ioe) { 3934f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi mTransport.close(); 3944f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi if (Email.DEBUG) { 39531d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "Unable to index during getMessage " + ioe); 3964f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi } 3974f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi throw new MessagingException("getMessages", ioe); 3984f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi } 39996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 4004f23ebd3dcca596533a33e6faedb446a814d32e3Takaoka G. Tadashi Pop3Message message = mUidToMsgMap.get(uid); 40196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return message; 40296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 40396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 40496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 40596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Message[] getMessages(int start, int end, MessageRetrievalListener listener) 40696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throws MessagingException { 40796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (start < 1 || end < 1 || end < start) { 40896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException(String.format("Invalid message set %d %d", 40996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project start, end)); 41096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 41196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 41296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project indexMsgNums(start, end); 41396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (IOException ioe) { 41496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.close(); 4158d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (Email.DEBUG) { 41631d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, ioe.toString()); 41796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 41896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("getMessages", ioe); 41996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 42096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ArrayList<Message> messages = new ArrayList<Message>(); 42196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int msgNum = start; msgNum <= end; msgNum++) { 42296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Pop3Message message = mMsgNumToMsgMap.get(msgNum); 42396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project messages.add(message); 42496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (listener != null) { 425dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki listener.messageRetrieved(message); 42696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 42796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 42896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return messages.toArray(new Message[messages.size()]); 42996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 43096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 43196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 43296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Ensures that the given message set (from start to end inclusive) 43396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * has been queried so that uids are available in the local cache. 43496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param start 43596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param end 43696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @throws MessagingException 43796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @throws IOException 43896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 43996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private void indexMsgNums(int start, int end) 44096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throws MessagingException, IOException { 44196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int unindexedMessageCount = 0; 44296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int msgNum = start; msgNum <= end; msgNum++) { 44396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mMsgNumToMsgMap.get(msgNum) == null) { 44496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project unindexedMessageCount++; 44596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 44696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 44796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (unindexedMessageCount == 0) { 44896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 44996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 45096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project UidlParser parser = new UidlParser(); 45196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (DEBUG_FORCE_SINGLE_LINE_UIDL || 45296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project (unindexedMessageCount < 50 && mMessageCount > 5000)) { 45396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 45496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * In extreme cases we'll do a UIDL command per message instead of a bulk 45596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * download. 45696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 45796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int msgNum = start; msgNum <= end; msgNum++) { 45896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Pop3Message message = mMsgNumToMsgMap.get(msgNum); 45996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (message == null) { 46096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = executeSimpleCommand("UIDL " + msgNum); 461092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler if (!parser.parseSingleLine(response)) { 462092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler throw new IOException(); 463092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } 46496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project message = new Pop3Message(parser.mUniqueId, this); 46596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project indexMessage(msgNum, message); 46696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 46796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 468092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } else { 46996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = executeSimpleCommand("UIDL"); 47096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((response = mTransport.readLine()) != null) { 471092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler if (!parser.parseMultiLine(response)) { 472092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler throw new IOException(); 473092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } 47496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (parser.mEndOfMessage) { 47596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project break; 47696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 47796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int msgNum = parser.mMessageNumber; 47896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (msgNum >= start && msgNum <= end) { 47996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Pop3Message message = mMsgNumToMsgMap.get(msgNum); 48096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (message == null) { 48196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project message = new Pop3Message(parser.mUniqueId, this); 48296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project indexMessage(msgNum, message); 48396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 48496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 48596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 48696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 48796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 48896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 48996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private void indexUids(ArrayList<String> uids) 49096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throws MessagingException, IOException { 49196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project HashSet<String> unindexedUids = new HashSet<String>(); 49296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (String uid : uids) { 49396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mUidToMsgMap.get(uid) == null) { 49496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project unindexedUids.add(uid); 49596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 49696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 49796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (unindexedUids.size() == 0) { 49896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 49996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 50096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 50196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If we are missing uids in the cache the only sure way to 50296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * get them is to do a full UIDL list. A possible optimization 50396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * would be trying UIDL for the latest X messages and praying. 50496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 50596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project UidlParser parser = new UidlParser(); 50696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = executeSimpleCommand("UIDL"); 50796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((response = mTransport.readLine()) != null) { 50896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project parser.parseMultiLine(response); 50996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (parser.mEndOfMessage) { 51096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project break; 51196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 51296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (unindexedUids.contains(parser.mUniqueId)) { 51396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Pop3Message message = mUidToMsgMap.get(parser.mUniqueId); 51496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (message == null) { 51596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project message = new Pop3Message(parser.mUniqueId, this); 51696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 51796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project indexMessage(parser.mMessageNumber, message); 51896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 51996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 52096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 52196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 52296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 52396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Simple parser class for UIDL messages. 524dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 525dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * <p>NOTE: In variance with RFC 1939, we allow multiple whitespace between the 526dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * message-number and unique-id fields. This provides greater compatibility with some 52796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * non-compliant POP3 servers, e.g. mail.comcast.net. 52896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 52996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* package */ class UidlParser { 530dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki 53196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 53296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Caller can read back message-number from this field 53396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 53496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int mMessageNumber; 53596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 53696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Caller can read back unique-id from this field 53796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 53896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String mUniqueId; 53996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 54096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * True if the response was "end-of-message" 54196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 54296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean mEndOfMessage; 54396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 54496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * True if an error was reported 54596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 54696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean mErr; 547dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki 54896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 54996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Construct & Initialize 55096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 55196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public UidlParser() { 55296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mErr = true; 55396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 554dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki 55596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 55696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Parse a single-line response. This is returned from a command of the form 557dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * "UIDL msg-num" and will be formatted as: "+OK msg-num unique-id" or 55896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "-ERR diagnostic text" 559dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 56096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param response The string returned from the server 56196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return true if the string parsed as expected (e.g. no syntax problems) 56296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 56396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean parseSingleLine(String response) { 56496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mErr = false; 565b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler if (response == null || response.length() == 0) { 566b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler return false; 567b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler } 56896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project char first = response.charAt(0); 56996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (first == '+') { 57096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String[] uidParts = response.split(" +"); 57196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (uidParts.length >= 3) { 572092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler try { 573092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler mMessageNumber = Integer.parseInt(uidParts[1]); 574092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } catch (NumberFormatException nfe) { 575092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler return false; 576092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } 57796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUniqueId = uidParts[2]; 57896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mEndOfMessage = true; 57996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 58096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 58196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else if (first == '-') { 58296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mErr = true; 58396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 58496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 58596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 58696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 587dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki 58896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 58996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Parse a multi-line response. This is returned from a command of the form 59096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "UIDL" and will be formatted as: "." or "msg-num unique-id". 591dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 59296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param response The string returned from the server 59396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return true if the string parsed as expected (e.g. no syntax problems) 59496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 59596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean parseMultiLine(String response) { 59696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mErr = false; 597b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler if (response == null || response.length() == 0) { 598b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler return false; 599b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler } 60096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project char first = response.charAt(0); 60196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (first == '.') { 60296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mEndOfMessage = true; 60396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 60496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 60596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String[] uidParts = response.split(" +"); 60696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (uidParts.length >= 2) { 607092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler try { 608092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler mMessageNumber = Integer.parseInt(uidParts[0]); 609092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } catch (NumberFormatException nfe) { 610092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler return false; 611092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } 61296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUniqueId = uidParts[1]; 61396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mEndOfMessage = false; 61496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 61596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 61696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 61796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 61896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 61996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 62096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 62196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private void indexMessage(int msgNum, Pop3Message message) { 62296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mMsgNumToMsgMap.put(msgNum, message); 62396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUidToMsgMap.put(message.getUid(), message); 62496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUidToMsgNumMap.put(message.getUid(), msgNum); 62596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 62696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 62796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 628a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public Message[] getMessages(String[] uids, MessageRetrievalListener listener) { 629a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy throw new UnsupportedOperationException( 630a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy "Pop3Folder.getMessage(MessageRetrievalListener)"); 63196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 63296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 63396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 63496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Fetch the items contained in the FetchProfile into the given set of 63596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Messages in as efficient a manner as possible. 63696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param messages 63796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param fp 63896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @throws MessagingException 63996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 640165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 64196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener) 64296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throws MessagingException { 64396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (messages == null || messages.length == 0) { 64496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 64596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 64696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ArrayList<String> uids = new ArrayList<String>(); 64796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (Message message : messages) { 64896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project uids.add(message.getUid()); 64996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 65096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 65196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project indexUids(uids); 65296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (fp.contains(FetchProfile.Item.ENVELOPE)) { 65396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Note: We never pass the listener for the ENVELOPE call, because we're going 65496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // to be calling the listener below in the per-message loop. 65596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project fetchEnvelope(messages, null); 65696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 657092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } catch (IOException ioe) { 65896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.close(); 6598d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (Email.DEBUG) { 66031d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, ioe.toString()); 66196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 66296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("fetch", ioe); 66396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 66496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = messages.length; i < count; i++) { 66596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Message message = messages[i]; 66696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!(message instanceof Pop3Message)) { 66796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("Pop3Store.fetch called with non-Pop3 Message"); 66896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 66996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Pop3Message pop3Message = (Pop3Message)message; 67096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 67196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (fp.contains(FetchProfile.Item.BODY)) { 67296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project fetchBody(pop3Message, -1); 67396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 67496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (fp.contains(FetchProfile.Item.BODY_SANE)) { 67596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 67696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * To convert the suggested download size we take the size 67796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * divided by the maximum line size (76). 67896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 67996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project fetchBody(pop3Message, 68096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project FETCH_BODY_SANE_SUGGESTED_SIZE / 76); 68196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 68296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (fp.contains(FetchProfile.Item.STRUCTURE)) { 68396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 68496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If the user is requesting STRUCTURE we are required to set the body 68596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * to null since we do not support the function. 68696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 68796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project pop3Message.setBody(null); 68896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 68996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (listener != null) { 690dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki listener.messageRetrieved(message); 69196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 69296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (IOException ioe) { 69396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.close(); 6948d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (Email.DEBUG) { 69531d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, ioe.toString()); 69696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 69796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("Unable to fetch message", ioe); 69896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 69996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 70096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 70196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 70296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private void fetchEnvelope(Message[] messages, 70396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project MessageRetrievalListener listener) throws IOException, MessagingException { 70496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int unsizedMessages = 0; 70596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (Message message : messages) { 70696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (message.getSize() == -1) { 70796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project unsizedMessages++; 70896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 70996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 71096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (unsizedMessages == 0) { 71196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 71296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 71396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (unsizedMessages < 50 && mMessageCount > 5000) { 71496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 71596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * In extreme cases we'll do a command per message instead of a bulk request 71696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * to hopefully save some time and bandwidth. 71796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 71896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = messages.length; i < count; i++) { 71996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Message message = messages[i]; 72096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!(message instanceof Pop3Message)) { 721e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo throw new MessagingException( 722e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo "Pop3Store.fetch called with non-Pop3 Message"); 72396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 72496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Pop3Message pop3Message = (Pop3Message)message; 72596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = executeSimpleCommand(String.format("LIST %d", 72696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUidToMsgNumMap.get(pop3Message.getUid()))); 727092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler try { 728092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler String[] listParts = response.split(" "); 729092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler int msgNum = Integer.parseInt(listParts[1]); 730092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler int msgSize = Integer.parseInt(listParts[2]); 731092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler pop3Message.setSize(msgSize); 732092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } catch (NumberFormatException nfe) { 733092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler throw new IOException(); 734092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } 73596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (listener != null) { 736dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki listener.messageRetrieved(pop3Message); 73796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 73896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 739092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } else { 74096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project HashSet<String> msgUidIndex = new HashSet<String>(); 74196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (Message message : messages) { 74296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project msgUidIndex.add(message.getUid()); 74396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 74496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = executeSimpleCommand("LIST"); 74596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((response = mTransport.readLine()) != null) { 74696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (response.equals(".")) { 74796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project break; 74896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 749092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler Pop3Message pop3Message = null; 750092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler int msgSize = 0; 751092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler try { 752092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler String[] listParts = response.split(" "); 753092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler int msgNum = Integer.parseInt(listParts[0]); 754092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler msgSize = Integer.parseInt(listParts[1]); 755092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler pop3Message = mMsgNumToMsgMap.get(msgNum); 756092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } catch (NumberFormatException nfe) { 757092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler throw new IOException(); 758092d35c98d00c5a8b1ba93f51f8e59220f1488cbAndrew Stadler } 75996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (pop3Message != null && msgUidIndex.contains(pop3Message.getUid())) { 76096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project pop3Message.setSize(msgSize); 76196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (listener != null) { 762dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki listener.messageRetrieved(pop3Message); 76396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 76496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 76596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 76696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 76796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 76896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 76996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 77096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Fetches the body of the given message, limiting the stored data 77196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * to the specified number of lines. If lines is -1 the entire message 77296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * is fetched. This is implemented with RETR for lines = -1 or TOP 77396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * for any other value. If the server does not support TOP it is 77496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * emulated with RETR and extra lines are thrown away. 775645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler * 776645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler * Note: Some servers (e.g. live.com) don't support CAPA, but turn out to 777645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler * support TOP after all. For better performance on these servers, we'll always 778645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler * probe TOP, and fall back to RETR when it's truly unsupported. 779645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler * 78096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param message 78196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param lines 78296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 78396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private void fetchBody(Pop3Message message, int lines) 78496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throws IOException, MessagingException { 78596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = null; 786645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler int messageId = mUidToMsgNumMap.get(message.getUid()); 787645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler if (lines == -1) { 788645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler // Fetch entire message 789645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler response = executeSimpleCommand(String.format("RETR %d", messageId)); 790645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler } else { 791645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler // Fetch partial message. Try "TOP", and fall back to slower "RETR" if necessary 792645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler try { 793645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler response = executeSimpleCommand(String.format("TOP %d %d", messageId, lines)); 794645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler } catch (MessagingException me) { 795645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler response = executeSimpleCommand(String.format("RETR %d", messageId)); 796645fc2830118e19e604f24ba7ffe71c775631f64Andrew Stadler } 79796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 79896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (response != null) { 79996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 8003469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project InputStream in = mTransport.getInputStream(); 8018d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (DEBUG_LOG_RAW_STREAM && Email.DEBUG) { 8023469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project in = new LoggingInputStream(in); 8033469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project } 8043469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project message.parse(new Pop3ResponseInputStream(in)); 80596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 80696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (MessagingException me) { 80796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 80896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If we're only downloading headers it's possible 80996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * we'll get a broken MIME message which we're not 81096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * real worried about. If we've downloaded the body 81196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * and can't parse it we need to let the user know. 81296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 81396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (lines == -1) { 81496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw me; 81596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 81696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 81796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 81896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 81996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 82096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 821a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public Flag[] getPermanentFlags() { 82296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return PERMANENT_FLAGS; 82396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 82496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 825165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 826a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public void appendMessages(Message[] messages) { 82796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 82896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 829165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 830a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public void delete(boolean recurse) { 83196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 83296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 833165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 834a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public Message[] expunge() { 83596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 83696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 83796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 838165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 83996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setFlags(Message[] messages, Flag[] flags, boolean value) 84096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throws MessagingException { 84196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!value || !Utility.arrayContains(flags, Flag.DELETED)) { 84296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 84396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * The only flagging we support is setting the Deleted flag. 84496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 84596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 84696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 84796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 84896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (Message message : messages) { 84996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project executeSimpleCommand(String.format("DELE %s", 85096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUidToMsgNumMap.get(message.getUid()))); 85196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 85296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 85396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (IOException ioe) { 85496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.close(); 8558d8537cd2e39268e0fdcd019bc8b6c4572b7c520Todd Kennedy if (Email.DEBUG) { 85631d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, ioe.toString()); 85796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 85896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("setFlags()", ioe); 85996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 86096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 86196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 86296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 863a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public void copyMessages(Message[] msgs, Folder folder, MessageUpdateCallbacks callbacks) { 86496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new UnsupportedOperationException("copyMessages is not supported in POP3"); 86596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 86696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 86796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// private boolean isRoundTripModeSuggested() { 86896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// long roundTripMethodMs = 86996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// (uncachedMessageCount * 2 * mLatencyMs); 87096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// long bulkMethodMs = 87196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// (mMessageCount * 58) / (mThroughputKbS * 1024 / 8) * 1000; 87296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// } 87396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 874a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy private Pop3Capabilities getCapabilities() throws IOException { 87596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Pop3Capabilities capabilities = new Pop3Capabilities(); 87696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 87796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = executeSimpleCommand("CAPA"); 87896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((response = mTransport.readLine()) != null) { 87996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (response.equals(".")) { 88096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project break; 88196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 88296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (response.equalsIgnoreCase("STLS")){ 88396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project capabilities.stls = true; 88496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 88596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (response.equalsIgnoreCase("UIDL")) { 88696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project capabilities.uidl = true; 88796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 88896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (response.equalsIgnoreCase("PIPELINING")) { 88996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project capabilities.pipelining = true; 89096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 89196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (response.equalsIgnoreCase("USER")) { 89296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project capabilities.user = true; 89396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 89496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (response.equalsIgnoreCase("TOP")) { 89596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project capabilities.top = true; 89696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 89796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 89896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 89996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (MessagingException me) { 90096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 90196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * The server may not support the CAPA command, so we just eat this Exception 90296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * and allow the empty capabilities object to be returned. 90396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 90496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 90596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return capabilities; 90696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 90796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 90896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 90996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Send a single command and wait for a single line response. Reopens the connection, 91096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * if it is closed. Leaves the connection open. 911dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 91296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param command The command string to send to the server. 91396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return Returns the response string from the server. 91496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 91596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private String executeSimpleCommand(String command) throws IOException, MessagingException { 91696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return executeSensitiveCommand(command, null); 91796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 918dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki 91996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 92096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Send a single command and wait for a single line response. Reopens the connection, 92196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * if it is closed. Leaves the connection open. 922dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * 92396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param command The command string to send to the server. 92496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param sensitiveReplacement If the command includes sensitive data (e.g. authentication) 92596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * please pass a replacement string here (for logging). 92696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return Returns the response string from the server. 92796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 92896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private String executeSensitiveCommand(String command, String sensitiveReplacement) 92996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throws IOException, MessagingException { 930244d306ebb0addbc5d87008af9412b76c80e861eMarc Blank open(OpenMode.READ_WRITE); 93196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 93296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (command != null) { 93396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTransport.writeLine(command, sensitiveReplacement); 93496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 93596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 93696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String response = mTransport.readLine(); 93796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 93896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (response.length() > 1 && response.charAt(0) == '-') { 93996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException(response); 94096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 94196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 94296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return response; 94396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 94496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 94596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 94696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean equals(Object o) { 94796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (o instanceof Pop3Folder) { 94896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return ((Pop3Folder) o).mName.equals(mName); 94996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 95096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return super.equals(o); 95196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 95296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 95396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 954745b33b8ff55e9a9c4871f07f9d97db893f784b2Makoto Onuki @VisibleForTesting 9552720a818d5de169734434b114adfdf824a485f55Marc Blank public boolean isOpen() { 95696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mTransport.isOpen(); 95796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9580d1078363581db8caded06cf94e729e88a88761aAndrew Stadler 9590d1078363581db8caded06cf94e729e88a88761aAndrew Stadler @Override 960a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public Message createMessage(String uid) { 9610d1078363581db8caded06cf94e729e88a88761aAndrew Stadler return new Pop3Message(uid, this); 9620d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 963627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank 964627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank @Override 965e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo public Message[] getMessages(SearchParams params, MessageRetrievalListener listener) { 966627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank return null; 967627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank } 96896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 96996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 970391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank public static class Pop3Message extends MimeMessage { 971a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public Pop3Message(String uid, Pop3Folder folder) { 97296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mUid = uid; 97396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mFolder = folder; 97496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mSize = -1; 97596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 97696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 97796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setSize(int size) { 97896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mSize = size; 97996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 98096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 981165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 982391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank public void parse(InputStream in) throws IOException, MessagingException { 98396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project super.parse(in); 98496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 98596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 98696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 98796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setFlag(Flag flag, boolean set) throws MessagingException { 98896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project super.setFlag(flag, set); 98996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mFolder.setFlags(new Message[] { this }, new Flag[] { flag }, set); 99096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 99196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 99296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 993dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki /** 99496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * POP3 Capabilities as defined in RFC 2449. This is not a complete list of CAPA 995dbbd2ba22c63f38c268c1c33e285cfcc50f6da27Makoto Onuki * responses - just those that we use in this client. 99696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 99796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project class Pop3Capabilities { 99896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** The STLS (start TLS) command is supported */ 99996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean stls; 100096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** the TOP command (retrieve a partial message) is supported */ 100196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean top; 100296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** USER and PASS login/auth commands are supported */ 100396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean user; 100496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** the optional UIDL command is supported (unused) */ 100596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean uidl; 100696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** the server is capable of accepting multiple commands at a time (unused) */ 100796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean pipelining; 100896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 1009165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 101096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String toString() { 101196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return String.format("STLS %b, TOP %b, USER %b, UIDL %b, PIPELINING %b", 101296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project stls, 101396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project top, 101496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project user, 101596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project uidl, 101696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project pipelining); 101796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 101896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 101996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 102096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // TODO figure out what is special about this and merge it into MailTransport 102196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project class Pop3ResponseInputStream extends InputStream { 1022b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final InputStream mIn; 1023b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private boolean mStartOfLine = true; 1024b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private boolean mFinished; 102596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 102696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Pop3ResponseInputStream(InputStream in) { 102796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mIn = in; 102896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 102996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 103096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 103196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int read() throws IOException { 103296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mFinished) { 103396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return -1; 103496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 103596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int d = mIn.read(); 103696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mStartOfLine && d == '.') { 103796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project d = mIn.read(); 103896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (d == '\r') { 103996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mFinished = true; 104096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mIn.read(); 104196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return -1; 104296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 104396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 104496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 104596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mStartOfLine = (d == '\n'); 104696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 104796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return d; 104896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 104996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 105096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project} 1051