Fix IMAP message upsync to include attachments.
b/13138456 Change-Id: If16b619a650c640a37cb4563750a6327a5e601e6
This commit is contained in:
parent
50c5add15b
commit
0c8696c2eb
|
@ -20,21 +20,30 @@ import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple OutputStream that does nothing but count how many bytes are written to it and
|
* A simple pass-thru OutputStream that also counts how many bytes are written to it and
|
||||||
* makes that count available to callers.
|
* makes that count available to callers.
|
||||||
*/
|
*/
|
||||||
public class CountingOutputStream extends OutputStream {
|
public class CountingOutputStream extends OutputStream {
|
||||||
private long mCount;
|
private long mCount;
|
||||||
|
private final OutputStream mOutputStream;
|
||||||
|
|
||||||
public CountingOutputStream() {
|
public CountingOutputStream(OutputStream outputStream) {
|
||||||
|
mOutputStream = outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getCount() {
|
public long getCount() {
|
||||||
return mCount;
|
return mCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] buffer, int offset, int count) throws IOException {
|
||||||
|
mOutputStream.write(buffer, offset, count);
|
||||||
|
mCount += count;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(int oneByte) throws IOException {
|
public void write(int oneByte) throws IOException {
|
||||||
|
mOutputStream.write(oneByte);
|
||||||
mCount++;
|
mCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,12 @@ import com.android.emailcommon.internet.MimeMultipart;
|
||||||
import com.android.emailcommon.internet.MimeUtility;
|
import com.android.emailcommon.internet.MimeUtility;
|
||||||
import com.android.emailcommon.internet.TextBody;
|
import com.android.emailcommon.internet.TextBody;
|
||||||
import com.android.emailcommon.mail.Address;
|
import com.android.emailcommon.mail.Address;
|
||||||
|
import com.android.emailcommon.mail.Base64Body;
|
||||||
import com.android.emailcommon.mail.Flag;
|
import com.android.emailcommon.mail.Flag;
|
||||||
import com.android.emailcommon.mail.Message;
|
import com.android.emailcommon.mail.Message;
|
||||||
import com.android.emailcommon.mail.Message.RecipientType;
|
import com.android.emailcommon.mail.Message.RecipientType;
|
||||||
import com.android.emailcommon.mail.MessagingException;
|
import com.android.emailcommon.mail.MessagingException;
|
||||||
|
import com.android.emailcommon.mail.Multipart;
|
||||||
import com.android.emailcommon.mail.Part;
|
import com.android.emailcommon.mail.Part;
|
||||||
import com.android.emailcommon.provider.EmailContent;
|
import com.android.emailcommon.provider.EmailContent;
|
||||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||||
|
@ -46,7 +48,9 @@ import com.android.mail.utils.LogUtils;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -421,15 +425,39 @@ public class LegacyConversions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachments
|
// Attachments
|
||||||
// TODO: Make sure we deal with these as structures and don't accidentally upload files
|
Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
|
||||||
// Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
|
Cursor attachments = context.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
|
||||||
// Cursor attachments = context.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
|
null, null, null);
|
||||||
// null, null, null);
|
|
||||||
// try {
|
try {
|
||||||
//
|
while (attachments != null && attachments.moveToNext()) {
|
||||||
// } finally {
|
final Attachment att = new Attachment();
|
||||||
// attachments.close();
|
att.restore(attachments);
|
||||||
// }
|
try {
|
||||||
|
final InputStream content;
|
||||||
|
if (att.mContentBytes != null) {
|
||||||
|
// This is generally only the case for synthetic attachments, such as those
|
||||||
|
// generated by unit tests or calendar invites
|
||||||
|
content = new ByteArrayInputStream(att.mContentBytes);
|
||||||
|
} else {
|
||||||
|
final Uri contentUri = Uri.parse(att.getCachedFileUri());
|
||||||
|
content = context.getContentResolver().openInputStream(contentUri);
|
||||||
|
}
|
||||||
|
final String mimeType = att.mMimeType;
|
||||||
|
final Long contentSize = att.mSize;
|
||||||
|
final String contentId = att.mContentId;
|
||||||
|
final String filename = att.mFileName;
|
||||||
|
addAttachmentPart(mp, mimeType, contentSize, filename, contentId, content);
|
||||||
|
} catch (final FileNotFoundException e) {
|
||||||
|
LogUtils.e(LogUtils.TAG, "File Not Found error on %s while upsyncing message",
|
||||||
|
att.getCachedFileUri());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (attachments != null) {
|
||||||
|
attachments.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
@ -455,6 +483,31 @@ public class LegacyConversions {
|
||||||
mp.addBodyPart(bp);
|
mp.addBodyPart(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to add an attachment part
|
||||||
|
*
|
||||||
|
* @param mp Multipart message to append attachment part to
|
||||||
|
* @param contentType Mime type
|
||||||
|
* @param contentSize Attachment metadata: unencoded file size
|
||||||
|
* @param filename Attachment metadata: file name
|
||||||
|
* @param contentId as referenced from cid: uris in the message body (if applicable)
|
||||||
|
* @param content unencoded bytes
|
||||||
|
* @throws MessagingException
|
||||||
|
*/
|
||||||
|
private static void addAttachmentPart(final Multipart mp, final String contentType,
|
||||||
|
final Long contentSize, final String filename, final String contentId,
|
||||||
|
final InputStream content) throws MessagingException {
|
||||||
|
final Base64Body body = new Base64Body(content);
|
||||||
|
final MimeBodyPart bp = new MimeBodyPart(body, contentType);
|
||||||
|
bp.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
|
||||||
|
bp.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "attachment;\n"
|
||||||
|
+ "filename=\"" + filename + "\";"
|
||||||
|
+ "size=" + contentSize);
|
||||||
|
if (contentId != null) {
|
||||||
|
bp.setHeader(MimeHeader.HEADER_CONTENT_ID, contentId);
|
||||||
|
}
|
||||||
|
mp.addBodyPart(bp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infer mailbox type from mailbox name. Used by MessagingController (for live folder sync).
|
* Infer mailbox type from mailbox name. Used by MessagingController (for live folder sync).
|
||||||
|
|
|
@ -52,6 +52,11 @@ import com.android.emailcommon.utility.Utility;
|
||||||
import com.android.mail.utils.LogUtils;
|
import com.android.mail.utils.LogUtils;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -1025,92 +1030,124 @@ class ImapFolder extends Folder {
|
||||||
* Appends the given messages to the selected folder. This implementation also determines
|
* Appends the given messages to the selected folder. This implementation also determines
|
||||||
* the new UID of the given message on the IMAP server and sets the Message's UID to the
|
* the new UID of the given message on the IMAP server and sets the Message's UID to the
|
||||||
* new server UID.
|
* new server UID.
|
||||||
|
* @param message Message
|
||||||
|
* @param noTimeout Set to true on manual syncs, disables the timeout after sending the message
|
||||||
|
* content to the server
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void appendMessages(Message[] messages) throws MessagingException {
|
public void appendMessage(final Context context, final Message message, final boolean noTimeout)
|
||||||
|
throws MessagingException {
|
||||||
checkOpen();
|
checkOpen();
|
||||||
try {
|
try {
|
||||||
for (Message message : messages) {
|
// Create temp file
|
||||||
// Create output count
|
/**
|
||||||
CountingOutputStream out = new CountingOutputStream();
|
* We need to know the encoded message size before we upload it, and encoding
|
||||||
EOLConvertingOutputStream eolOut = new EOLConvertingOutputStream(out);
|
* attachments as Base64, possibly reading from a slow provider, is a non-trivial
|
||||||
message.writeTo(eolOut);
|
* operation. So we write the contents to a temp file while measuring the size,
|
||||||
eolOut.flush();
|
* and then use that temp file and size to do the actual upsync.
|
||||||
// Create flag list (most often this will be "\SEEN")
|
* For context, most classic email clients would store the message in RFC822 format
|
||||||
String flagList = "";
|
* internally, and so would not need to do this on-the-fly.
|
||||||
Flag[] flags = message.getFlags();
|
*/
|
||||||
if (flags.length > 0) {
|
final File tempDir = context.getExternalCacheDir();
|
||||||
StringBuilder sb = new StringBuilder();
|
final File tempFile = File.createTempFile("IMAPupsync", ".eml", tempDir);
|
||||||
for (int i = 0, count = flags.length; i < count; i++) {
|
// Delete here so we don't leave the file lingering. We've got a handle to it so we
|
||||||
Flag flag = flags[i];
|
// can still use it.
|
||||||
if (flag == Flag.SEEN) {
|
final boolean deleteSuccessful = tempFile.delete();
|
||||||
sb.append(" " + ImapConstants.FLAG_SEEN);
|
if (!deleteSuccessful) {
|
||||||
} else if (flag == Flag.FLAGGED) {
|
LogUtils.w(LogUtils.TAG, "Could not delete temp file %s",
|
||||||
sb.append(" " + ImapConstants.FLAG_FLAGGED);
|
tempFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
final OutputStream tempOut = new FileOutputStream(tempFile);
|
||||||
if (sb.length() > 0) {
|
// Create output count while writing temp file
|
||||||
flagList = sb.substring(1);
|
final CountingOutputStream out = new CountingOutputStream(tempOut);
|
||||||
|
final EOLConvertingOutputStream eolOut = new EOLConvertingOutputStream(out);
|
||||||
|
message.writeTo(eolOut);
|
||||||
|
eolOut.flush();
|
||||||
|
// Create flag list (most often this will be "\SEEN")
|
||||||
|
String flagList = "";
|
||||||
|
Flag[] flags = message.getFlags();
|
||||||
|
if (flags.length > 0) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (final Flag flag : flags) {
|
||||||
|
if (flag == Flag.SEEN) {
|
||||||
|
sb.append(" " + ImapConstants.FLAG_SEEN);
|
||||||
|
} else if (flag == Flag.FLAGGED) {
|
||||||
|
sb.append(" " + ImapConstants.FLAG_FLAGGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
flagList = sb.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mConnection.sendCommand(
|
mConnection.sendCommand(
|
||||||
String.format(Locale.US, ImapConstants.APPEND + " \"%s\" (%s) {%d}",
|
String.format(Locale.US, ImapConstants.APPEND + " \"%s\" (%s) {%d}",
|
||||||
ImapStore.encodeFolderName(mName, mStore.mPathPrefix),
|
ImapStore.encodeFolderName(mName, mStore.mPathPrefix),
|
||||||
flagList,
|
flagList,
|
||||||
out.getCount()), false);
|
out.getCount()), false);
|
||||||
ImapResponse response;
|
ImapResponse response;
|
||||||
do {
|
do {
|
||||||
|
final int socketTimeout = mConnection.mTransport.getSoTimeout();
|
||||||
|
try {
|
||||||
|
// Need to set the timeout to unlimited since we might be upsyncing a pretty
|
||||||
|
// big attachment so who knows how long it'll take. It would sure be nice
|
||||||
|
// if this only timed out after the send buffer drained but welp.
|
||||||
|
if (noTimeout) {
|
||||||
|
// For now, only unset the timeout if we're doing a manual sync
|
||||||
|
mConnection.mTransport.setSoTimeout(0);
|
||||||
|
}
|
||||||
response = mConnection.readResponse();
|
response = mConnection.readResponse();
|
||||||
if (response.isContinuationRequest()) {
|
if (response.isContinuationRequest()) {
|
||||||
eolOut = new EOLConvertingOutputStream(
|
final OutputStream transportOutputStream =
|
||||||
mConnection.mTransport.getOutputStream());
|
mConnection.mTransport.getOutputStream();
|
||||||
message.writeTo(eolOut);
|
IOUtils.copyLarge(new FileInputStream(tempFile), transportOutputStream);
|
||||||
eolOut.write('\r');
|
transportOutputStream.write('\r');
|
||||||
eolOut.write('\n');
|
transportOutputStream.write('\n');
|
||||||
eolOut.flush();
|
transportOutputStream.flush();
|
||||||
} else if (!response.isTagged()) {
|
} else if (!response.isTagged()) {
|
||||||
handleUntaggedResponse(response);
|
handleUntaggedResponse(response);
|
||||||
}
|
}
|
||||||
} while (!response.isTagged());
|
} finally {
|
||||||
|
mConnection.mTransport.setSoTimeout(socketTimeout);
|
||||||
|
}
|
||||||
|
} while (!response.isTagged());
|
||||||
|
|
||||||
// TODO Why not check the response?
|
// TODO Why not check the response?
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to recover the UID of the message from an APPENDUID response.
|
* Try to recover the UID of the message from an APPENDUID response.
|
||||||
* e.g. 11 OK [APPENDUID 2 238268] APPEND completed
|
* e.g. 11 OK [APPENDUID 2 238268] APPEND completed
|
||||||
*/
|
*/
|
||||||
final ImapList appendList = response.getListOrEmpty(1);
|
final ImapList appendList = response.getListOrEmpty(1);
|
||||||
if ((appendList.size() >= 3) && appendList.is(0, ImapConstants.APPENDUID)) {
|
if ((appendList.size() >= 3) && appendList.is(0, ImapConstants.APPENDUID)) {
|
||||||
String serverUid = appendList.getStringOrEmpty(2).getString();
|
String serverUid = appendList.getStringOrEmpty(2).getString();
|
||||||
if (!TextUtils.isEmpty(serverUid)) {
|
if (!TextUtils.isEmpty(serverUid)) {
|
||||||
message.setUid(serverUid);
|
message.setUid(serverUid);
|
||||||
continue;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to find the UID of the message we just appended using the
|
* Try to find the UID of the message we just appended using the
|
||||||
* Message-ID header. If there are more than one response, take the
|
* Message-ID header. If there are more than one response, take the
|
||||||
* last one, as it's most likely the newest (the one we just uploaded).
|
* last one, as it's most likely the newest (the one we just uploaded).
|
||||||
*/
|
*/
|
||||||
final String messageId = message.getMessageId();
|
final String messageId = message.getMessageId();
|
||||||
if (messageId == null || messageId.length() == 0) {
|
if (messageId == null || messageId.length() == 0) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
// Most servers don't care about parenthesis in the search query [and, some
|
// Most servers don't care about parenthesis in the search query [and, some
|
||||||
// fail to work if they are used]
|
// fail to work if they are used]
|
||||||
String[] uids = searchForUids(
|
String[] uids = searchForUids(
|
||||||
String.format(Locale.US, "HEADER MESSAGE-ID %s", messageId));
|
String.format(Locale.US, "HEADER MESSAGE-ID %s", messageId));
|
||||||
if (uids.length > 0) {
|
if (uids.length > 0) {
|
||||||
message.setUid(uids[0]);
|
message.setUid(uids[0]);
|
||||||
}
|
}
|
||||||
// However, there's at least one server [AOL] that fails to work unless there
|
// However, there's at least one server [AOL] that fails to work unless there
|
||||||
// are parenthesis, so, try this as a last resort
|
// are parenthesis, so, try this as a last resort
|
||||||
uids = searchForUids(String.format(Locale.US, "(HEADER MESSAGE-ID %s)", messageId));
|
uids = searchForUids(String.format(Locale.US, "(HEADER MESSAGE-ID %s)", messageId));
|
||||||
if (uids.length > 0) {
|
if (uids.length > 0) {
|
||||||
message.setUid(uids[0]);
|
message.setUid(uids[0]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw ioExceptionHandler(mConnection, ioe);
|
throw ioExceptionHandler(mConnection, ioe);
|
||||||
|
|
|
@ -553,7 +553,7 @@ public class Pop3Store extends Store {
|
||||||
*
|
*
|
||||||
* @param message
|
* @param message
|
||||||
* @param lines
|
* @param lines
|
||||||
* @param optional callback that reports progress of the fetch
|
* @param callback optional callback that reports progress of the fetch
|
||||||
*/
|
*/
|
||||||
public void fetchBody(Pop3Message message, int lines,
|
public void fetchBody(Pop3Message message, int lines,
|
||||||
EOLConvertingInputStream.Callback callback) throws IOException, MessagingException {
|
EOLConvertingInputStream.Callback callback) throws IOException, MessagingException {
|
||||||
|
@ -626,7 +626,7 @@ public class Pop3Store extends Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendMessages(Message[] messages) {
|
public void appendMessage(Context context, Message message, boolean noTimeout) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -209,6 +209,15 @@ public class MailTransport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the socket timeout.
|
||||||
|
* @return the read timeout value in milliseconds
|
||||||
|
* @throws SocketException
|
||||||
|
*/
|
||||||
|
public int getSoTimeout() throws SocketException {
|
||||||
|
return mSocket.getSoTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the socket timeout.
|
* Set the socket timeout.
|
||||||
* @param timeoutMilliseconds the read timeout value if greater than {@code 0}, or
|
* @param timeoutMilliseconds the read timeout value if greater than {@code 0}, or
|
||||||
|
|
|
@ -164,7 +164,7 @@ public class ImapService extends Service {
|
||||||
Store remoteStore = null;
|
Store remoteStore = null;
|
||||||
try {
|
try {
|
||||||
remoteStore = Store.getInstance(account, context);
|
remoteStore = Store.getInstance(account, context);
|
||||||
processPendingActionsSynchronous(context, account, remoteStore);
|
processPendingActionsSynchronous(context, account, remoteStore, uiRefresh);
|
||||||
synchronizeMailboxGeneric(context, account, remoteStore, folder, loadMore, uiRefresh);
|
synchronizeMailboxGeneric(context, account, remoteStore, folder, loadMore, uiRefresh);
|
||||||
// Clear authentication notification for this account
|
// Clear authentication notification for this account
|
||||||
nc.cancelLoginFailedNotification(account.mId);
|
nc.cancelLoginFailedNotification(account.mId);
|
||||||
|
@ -724,7 +724,7 @@ public class ImapService extends Service {
|
||||||
* @throws MessagingException
|
* @throws MessagingException
|
||||||
*/
|
*/
|
||||||
private static void processPendingActionsSynchronous(Context context, Account account,
|
private static void processPendingActionsSynchronous(Context context, Account account,
|
||||||
Store remoteStore)
|
Store remoteStore, boolean manualSync)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(context, account));
|
TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(context, account));
|
||||||
String[] accountIdArgs = new String[] { Long.toString(account.mId) };
|
String[] accountIdArgs = new String[] { Long.toString(account.mId) };
|
||||||
|
@ -733,7 +733,7 @@ public class ImapService extends Service {
|
||||||
processPendingDeletesSynchronous(context, account, remoteStore, accountIdArgs);
|
processPendingDeletesSynchronous(context, account, remoteStore, accountIdArgs);
|
||||||
|
|
||||||
// Handle uploads (currently, only to sent messages)
|
// Handle uploads (currently, only to sent messages)
|
||||||
processPendingUploadsSynchronous(context, account, remoteStore, accountIdArgs);
|
processPendingUploadsSynchronous(context, account, remoteStore, accountIdArgs, manualSync);
|
||||||
|
|
||||||
// Now handle updates / upsyncs
|
// Now handle updates / upsyncs
|
||||||
processPendingUpdatesSynchronous(context, account, remoteStore, accountIdArgs);
|
processPendingUpdatesSynchronous(context, account, remoteStore, accountIdArgs);
|
||||||
|
@ -843,7 +843,7 @@ public class ImapService extends Service {
|
||||||
* uploaded directly to the Sent folder.
|
* uploaded directly to the Sent folder.
|
||||||
*/
|
*/
|
||||||
private static void processPendingUploadsSynchronous(Context context, Account account,
|
private static void processPendingUploadsSynchronous(Context context, Account account,
|
||||||
Store remoteStore, String[] accountIdArgs) {
|
Store remoteStore, String[] accountIdArgs, boolean manualSync) {
|
||||||
ContentResolver resolver = context.getContentResolver();
|
ContentResolver resolver = context.getContentResolver();
|
||||||
// Find the Sent folder (since that's all we're uploading for now
|
// Find the Sent folder (since that's all we're uploading for now
|
||||||
// TODO: Upsync for all folders? (In case a user moves mail from Sent before it is
|
// TODO: Upsync for all folders? (In case a user moves mail from Sent before it is
|
||||||
|
@ -884,7 +884,7 @@ public class ImapService extends Service {
|
||||||
// upsync the message
|
// upsync the message
|
||||||
long id = upsyncs1.getLong(EmailContent.Message.ID_PROJECTION_COLUMN);
|
long id = upsyncs1.getLong(EmailContent.Message.ID_PROJECTION_COLUMN);
|
||||||
lastMessageId = id;
|
lastMessageId = id;
|
||||||
processUploadMessage(context, remoteStore, mailbox, id);
|
processUploadMessage(context, remoteStore, mailbox, id, manualSync);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (upsyncs1 != null) {
|
if (upsyncs1 != null) {
|
||||||
|
@ -1005,7 +1005,7 @@ public class ImapService extends Service {
|
||||||
* @param mailbox the actual mailbox
|
* @param mailbox the actual mailbox
|
||||||
*/
|
*/
|
||||||
private static void processUploadMessage(Context context, Store remoteStore, Mailbox mailbox,
|
private static void processUploadMessage(Context context, Store remoteStore, Mailbox mailbox,
|
||||||
long messageId)
|
long messageId, boolean manualSync)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
EmailContent.Message newMessage =
|
EmailContent.Message newMessage =
|
||||||
EmailContent.Message.restoreMessageWithId(context, messageId);
|
EmailContent.Message.restoreMessageWithId(context, messageId);
|
||||||
|
@ -1026,8 +1026,9 @@ public class ImapService extends Service {
|
||||||
deleteUpdate = false;
|
deleteUpdate = false;
|
||||||
LogUtils.d(Logging.LOG_TAG, "Upsync skipped; mailbox changed, id=" + messageId);
|
LogUtils.d(Logging.LOG_TAG, "Upsync skipped; mailbox changed, id=" + messageId);
|
||||||
} else {
|
} else {
|
||||||
LogUtils.d(Logging.LOG_TAG, "Upsyc triggered for message id=" + messageId);
|
LogUtils.d(Logging.LOG_TAG, "Upsync triggered for message id=" + messageId);
|
||||||
deleteUpdate = processPendingAppend(context, remoteStore, mailbox, newMessage);
|
deleteUpdate =
|
||||||
|
processPendingAppend(context, remoteStore, mailbox, newMessage, manualSync);
|
||||||
}
|
}
|
||||||
if (deleteUpdate) {
|
if (deleteUpdate) {
|
||||||
// Finally, delete the update (if any)
|
// Finally, delete the update (if any)
|
||||||
|
@ -1286,10 +1287,11 @@ public class ImapService extends Service {
|
||||||
* @param remoteStore the remote store we're working in
|
* @param remoteStore the remote store we're working in
|
||||||
* @param mailbox The mailbox we're appending to
|
* @param mailbox The mailbox we're appending to
|
||||||
* @param message The message we're appending
|
* @param message The message we're appending
|
||||||
|
* @param manualSync True if this is a manual sync (changes upsync behavior)
|
||||||
* @return true if successfully uploaded
|
* @return true if successfully uploaded
|
||||||
*/
|
*/
|
||||||
private static boolean processPendingAppend(Context context, Store remoteStore, Mailbox mailbox,
|
private static boolean processPendingAppend(Context context, Store remoteStore, Mailbox mailbox,
|
||||||
EmailContent.Message message)
|
EmailContent.Message message, boolean manualSync)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
boolean updateInternalDate = false;
|
boolean updateInternalDate = false;
|
||||||
boolean updateMessage = false;
|
boolean updateMessage = false;
|
||||||
|
@ -1325,7 +1327,7 @@ public class ImapService extends Service {
|
||||||
//FetchProfile fp = new FetchProfile();
|
//FetchProfile fp = new FetchProfile();
|
||||||
//fp.add(FetchProfile.Item.BODY);
|
//fp.add(FetchProfile.Item.BODY);
|
||||||
// Note that this operation will assign the Uid to localMessage
|
// Note that this operation will assign the Uid to localMessage
|
||||||
remoteFolder.appendMessages(new Message[] { localMessage });
|
remoteFolder.appendMessage(context, localMessage, manualSync /* no timeout */);
|
||||||
|
|
||||||
// 3b. And record the UID from the server
|
// 3b. And record the UID from the server
|
||||||
message.mServerId = localMessage.getUid();
|
message.mServerId = localMessage.getUid();
|
||||||
|
@ -1360,7 +1362,7 @@ public class ImapService extends Service {
|
||||||
fp.clear();
|
fp.clear();
|
||||||
fp = new FetchProfile();
|
fp = new FetchProfile();
|
||||||
fp.add(FetchProfile.Item.BODY);
|
fp.add(FetchProfile.Item.BODY);
|
||||||
remoteFolder.appendMessages(new Message[] { localMessage });
|
remoteFolder.appendMessage(context, localMessage, manualSync /* no timeout */);
|
||||||
|
|
||||||
// 4d. Record the UID and new internalDate from the server
|
// 4d. Record the UID and new internalDate from the server
|
||||||
message.mServerId = localMessage.getUid();
|
message.mServerId = localMessage.getUid();
|
||||||
|
|
|
@ -243,7 +243,8 @@ public class PopImapSyncAdapterService extends Service {
|
||||||
int deltaMessageCount =
|
int deltaMessageCount =
|
||||||
extras.getInt(Mailbox.SYNC_EXTRA_DELTA_MESSAGE_COUNT, 0);
|
extras.getInt(Mailbox.SYNC_EXTRA_DELTA_MESSAGE_COUNT, 0);
|
||||||
for (long mailboxId : mailboxIds) {
|
for (long mailboxId : mailboxIds) {
|
||||||
sync(context, mailboxId, extras, syncResult, uiRefresh, deltaMessageCount);
|
sync(context, mailboxId, extras, syncResult, uiRefresh,
|
||||||
|
deltaMessageCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1185,7 +1185,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase {
|
||||||
|
|
||||||
ImapMessage message = prepareForAppendTest(mock, "oK [aPPENDUID 1234567 13] (Success)");
|
ImapMessage message = prepareForAppendTest(mock, "oK [aPPENDUID 1234567 13] (Success)");
|
||||||
|
|
||||||
mFolder.appendMessages(new Message[] {message});
|
mFolder.appendMessage(getInstrumentation().getTargetContext(), message, false);
|
||||||
|
|
||||||
assertEquals("13", message.getUid());
|
assertEquals("13", message.getUid());
|
||||||
assertEquals(7, mFolder.getMessageCount());
|
assertEquals(7, mFolder.getMessageCount());
|
||||||
|
@ -1216,7 +1216,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase {
|
||||||
getNextTag(true) + " oK success"
|
getNextTag(true) + " oK success"
|
||||||
});
|
});
|
||||||
|
|
||||||
mFolder.appendMessages(new Message[] {message});
|
mFolder.appendMessage(getInstrumentation().getTargetContext(), message, false);
|
||||||
|
|
||||||
assertEquals("321", message.getUid());
|
assertEquals("321", message.getUid());
|
||||||
}
|
}
|
||||||
|
@ -1250,7 +1250,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase {
|
||||||
getNextTag(true) + " oK Search completed."
|
getNextTag(true) + " oK Search completed."
|
||||||
});
|
});
|
||||||
|
|
||||||
mFolder.appendMessages(new Message[] {message});
|
mFolder.appendMessage(getInstrumentation().getTargetContext(), message, false);
|
||||||
|
|
||||||
// Shouldn't have changed
|
// Shouldn't have changed
|
||||||
assertEquals("initial uid", message.getUid());
|
assertEquals("initial uid", message.getUid());
|
||||||
|
|
|
@ -298,9 +298,6 @@ public class Pop3StoreUnitTests extends AndroidTestCase {
|
||||||
assertEquals(1, flags.length);
|
assertEquals(1, flags.length);
|
||||||
assertEquals(Flag.DELETED, flags[0]);
|
assertEquals(Flag.DELETED, flags[0]);
|
||||||
|
|
||||||
// appendMessages(Message[] messages) does nothing
|
|
||||||
mFolder.appendMessages(null);
|
|
||||||
|
|
||||||
// delete(boolean recurse) does nothing
|
// delete(boolean recurse) does nothing
|
||||||
// TODO - it should!
|
// TODO - it should!
|
||||||
mFolder.delete(false);
|
mFolder.delete(false);
|
||||||
|
|
|
@ -16,13 +16,15 @@
|
||||||
|
|
||||||
package com.android.emailcommon.mail;
|
package com.android.emailcommon.mail;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
import com.android.emailcommon.service.SearchParams;
|
import com.android.emailcommon.service.SearchParams;
|
||||||
|
|
||||||
|
|
||||||
public class MockFolder extends Folder {
|
public class MockFolder extends Folder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendMessages(Message[] messages) {
|
public void appendMessage(Context context, Message message, boolean noTimeout) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue