Merge "Try TOP even on POP servers that fail to report CAPA" into froyo

This commit is contained in:
Andrew Stadler 2010-04-12 11:27:25 -07:00 committed by Android (Google) Code Review
commit 9cc6f46b05
2 changed files with 97 additions and 10 deletions

View File

@ -755,20 +755,28 @@ public class Pop3Store extends Store {
* is fetched. This is implemented with RETR for lines = -1 or TOP * is fetched. This is implemented with RETR for lines = -1 or TOP
* for any other value. If the server does not support TOP it is * for any other value. If the server does not support TOP it is
* emulated with RETR and extra lines are thrown away. * emulated with RETR and extra lines are thrown away.
*
* Note: Some servers (e.g. live.com) don't support CAPA, but turn out to
* support TOP after all. For better performance on these servers, we'll always
* probe TOP, and fall back to RETR when it's truly unsupported.
*
* @param message * @param message
* @param lines * @param lines
*/ */
private void fetchBody(Pop3Message message, int lines) private void fetchBody(Pop3Message message, int lines)
throws IOException, MessagingException { throws IOException, MessagingException {
String response = null; String response = null;
if (lines == -1 || !mCapabilities.top) { int messageId = mUidToMsgNumMap.get(message.getUid());
response = executeSimpleCommand(String.format("RETR %d", if (lines == -1) {
mUidToMsgNumMap.get(message.getUid()))); // Fetch entire message
response = executeSimpleCommand(String.format("RETR %d", messageId));
} else {
// Fetch partial message. Try "TOP", and fall back to slower "RETR" if necessary
try {
response = executeSimpleCommand(String.format("TOP %d %d", messageId, lines));
} catch (MessagingException me) {
response = executeSimpleCommand(String.format("RETR %d", messageId));
} }
else {
response = executeSimpleCommand(String.format("TOP %d %d",
mUidToMsgNumMap.get(message.getUid()),
lines));
} }
if (response != null) { if (response != null) {
try { try {

View File

@ -791,6 +791,57 @@ public class Pop3StoreUnitTests extends AndroidTestCase {
checkFetchedMessage(messages[0], 1, false); checkFetchedMessage(messages[0], 1, false);
} }
/**
* A group of tests to confirm that we're properly juggling the RETR and TOP commands.
* Some servers (hello, live.com) support TOP but don't support CAPA. So we ignore CAPA
* and just try TOP.
*/
public void testRetrVariants() throws MessagingException {
MockTransport mockTransport = openAndInjectMockTransport();
openFolderWithMessage(mockTransport);
// index the message(s)
setupUidlSequence(mockTransport, 2);
Message[] messages = mFolder.getMessages(1, 2, null);
assertEquals(2, messages.length);
// basic fetch of flags & envelope
setupListSequence(mockTransport, 2);
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.FLAGS);
fp.add(FetchProfile.Item.ENVELOPE);
mFolder.fetch(messages, fp, null);
// A side effect of how messages work is that if you get fields that are empty,
// then empty arrays are written back into the parsed header fields (e.g. mTo, mFrom). The
// standard message parser needs to clear these before parsing. Make sure that this
// is happening. (This doesn't affect IMAP, which reads the headers directly via
// IMAP envelopes.)
for (Message message : messages) {
message.getRecipients(RecipientType.TO);
message.getRecipients(RecipientType.CC);
message.getRecipients(RecipientType.BCC);
}
// In the cases below, we fetch BODY_SANE which tries to load the first chunk of the
// message (not the entire thing) in order to quickly access the headers.
// In the first test, TOP succeeds
Message[] singleMessage = new Message[] { messages[0] };
setupSingleMessageTop(mockTransport, 1, true, true); // try TOP & succeed
fp = new FetchProfile();
fp.add(FetchProfile.Item.BODY_SANE);
mFolder.fetch(singleMessage, fp, null);
checkFetchedMessage(singleMessage[0], 1, false);
// In the 2nd test, TOP fails, so we should fall back to RETR
singleMessage[0] = messages[1];
setupSingleMessageTop(mockTransport, 2, true, false); // try TOP & fail
fp = new FetchProfile();
fp.add(FetchProfile.Item.BODY_SANE);
mFolder.fetch(singleMessage, fp, null);
checkFetchedMessage(singleMessage[0], 2, false);
}
/** /**
* Set up a basic MockTransport. open it, and inject it into mStore * Set up a basic MockTransport. open it, and inject it into mStore
*/ */
@ -944,7 +995,35 @@ public class Pop3StoreUnitTests extends AndroidTestCase {
* @param body if true, a non-empty body will be added * @param body if true, a non-empty body will be added
*/ */
private static void setupSingleMessage(MockTransport transport, int msgNum, boolean body) { private static void setupSingleMessage(MockTransport transport, int msgNum, boolean body) {
transport.expect("RETR " + Integer.toString(msgNum), "+OK message follows"); setupSingleMessageTop(transport, msgNum, false, false);
}
/**
* Setup a single message to be retrieved (headers only).
* This is very similar to setupSingleMessage() but is intended to test the BODY_SANE
* fetch mode.
* @param transport the mock transport
* @param msgNum the message number to expect and return
* @param topTry if true, the "client" is going to attempt the TOP command
* @param topSupported if true, the "server" supports the TOP command
*/
private static void setupSingleMessageTop(MockTransport transport, int msgNum,
boolean topTry, boolean topSupported) {
String msgNumString = Integer.toString(msgNum);
String topCommand = "TOP " + msgNumString + " 673";
String retrCommand = "RETR " + msgNumString;
if (topTry) {
if (topSupported) {
transport.expect(topCommand, "+OK message follows");
} else {
transport.expect(topCommand, "-ERR unsupported command");
transport.expect(retrCommand, "+OK message follows");
}
} else {
transport.expect(retrCommand, "+OK message follows");
}
transport.expect(null, "Date: 26 Aug 76 1429 EDT"); transport.expect(null, "Date: 26 Aug 76 1429 EDT");
transport.expect(null, "From: Jones@Registry.Org"); transport.expect(null, "From: Jones@Registry.Org");
transport.expect(null, "To: Smith@Registry.Org"); transport.expect(null, "To: Smith@Registry.Org");