Better IMAP compatibility

This commit is contained in:
M66B 2019-03-14 11:08:19 +00:00
parent 8580e29bd4
commit dfc8fee370
1 changed files with 76 additions and 78 deletions

View File

@ -18,6 +18,7 @@ import android.text.TextUtils;
import com.sun.mail.iap.ConnectionException; import com.sun.mail.iap.ConnectionException;
import com.sun.mail.iap.Response; import com.sun.mail.iap.Response;
import com.sun.mail.imap.AppendUID;
import com.sun.mail.imap.IMAPFolder; import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPMessage; import com.sun.mail.imap.IMAPMessage;
import com.sun.mail.imap.IMAPStore; import com.sun.mail.imap.IMAPStore;
@ -423,7 +424,7 @@ class Core {
imessage.setFlag(Flags.Flag.DRAFT, true); imessage.setFlag(Flags.Flag.DRAFT, true);
// Add message // Add message
long uid = append(ifolder, imessage); long uid = append(istore, ifolder, imessage);
Log.i(folder.name + " appended id=" + message.id + " uid=" + uid); Log.i(folder.name + " appended id=" + message.id + " uid=" + uid);
db.message().setMessageUid(message.id, uid); db.message().setMessageUid(message.id, uid);
@ -467,96 +468,86 @@ class Core {
if (imessage == null) if (imessage == null)
throw new MessageRemovedException(); throw new MessageRemovedException();
// Get target folder // Get arguments
long id = jargs.getLong(0); long id = jargs.getLong(0);
boolean autoread = (jargs.length() > 1 && jargs.getBoolean(1));
Long newid = (jargs.length() > 2 && !jargs.isNull(2) ? jargs.getLong(2) : null);
// Get target folder
EntityFolder target = db.folder().getFolder(id); EntityFolder target = db.folder().getFolder(id);
if (target == null) if (target == null)
throw new FolderNotFoundException(); throw new FolderNotFoundException();
IMAPFolder itarget = (IMAPFolder) istore.getFolder(target.name); IMAPFolder itarget = (IMAPFolder) istore.getFolder(target.name);
boolean autoread = (jargs.length() > 1 && jargs.getBoolean(1)); // Serialize source message
ByteArrayOutputStream bos = new ByteArrayOutputStream();
imessage.writeTo(bos);
if (!copy && // Deserialize target message
istore.hasCapability("MOVE") && ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
!EntityFolder.DRAFTS.equals(folder.type) && Message icopy = new MimeMessage(isession, bis);
!EntityFolder.DRAFTS.equals(target.type)) {
// Autoread
if (ifolder.getPermanentFlags().contains(Flags.Flag.SEEN))
if (autoread && !imessage.isSet(Flags.Flag.SEEN))
imessage.setFlag(Flags.Flag.SEEN, true);
// Move message to target folder // Make sure the message has a message ID
ifolder.moveMessages(new Message[]{imessage}, itarget); if (copy || message.msgid == null) {
} else { String msgid = EntityMessage.generateMessageId();
if (!copy) Log.i(target.name + " generated message id=" + msgid);
Log.w(folder.name + " MOVE by DELETE/APPEND"); icopy.setHeader("Message-ID", msgid);
}
// Serialize source message try {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); // Needed to read flags
imessage.writeTo(bos); itarget.open(Folder.READ_WRITE);
// Deserialize target message // Auto read
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); if (itarget.getPermanentFlags().contains(Flags.Flag.SEEN))
Message icopy = new MimeMessage(isession, bis); if (autoread && !icopy.isSet(Flags.Flag.SEEN))
icopy.setFlag(Flags.Flag.SEEN, true);
// Make sure the message has a message ID // Move from drafts
if (copy || message.msgid == null) { if (EntityFolder.DRAFTS.equals(folder.type))
String msgid = EntityMessage.generateMessageId(); if (itarget.getPermanentFlags().contains(Flags.Flag.DRAFT))
Log.i(target.name + " generated message id=" + msgid); icopy.setFlag(Flags.Flag.DRAFT, false);
icopy.setHeader("Message-ID", msgid);
// Move to drafts
if (EntityFolder.DRAFTS.equals(target.type))
if (itarget.getPermanentFlags().contains(Flags.Flag.DRAFT))
icopy.setFlag(Flags.Flag.DRAFT, true);
// Append target
long uid = append(istore, itarget, (MimeMessage) icopy);
if (newid != null) {
Log.i("Moved id=" + newid + " uid=" + uid);
db.message().setMessageUid(newid, uid);
} }
try { // Some providers, like Gmail, don't honor the appended seen flag
// Needed to read flags if (itarget.getPermanentFlags().contains(Flags.Flag.SEEN)) {
itarget.open(Folder.READ_WRITE); boolean seen = (autoread || message.ui_seen);
icopy = itarget.getMessageByUID(uid);
// Auto read if (seen != icopy.isSet(Flags.Flag.SEEN)) {
if (itarget.getPermanentFlags().contains(Flags.Flag.SEEN)) Log.i(target.name + " Fixing id=" + message.id + " seen=" + seen);
if (autoread && !icopy.isSet(Flags.Flag.SEEN)) icopy.setFlag(Flags.Flag.SEEN, seen);
icopy.setFlag(Flags.Flag.SEEN, true);
// Move from drafts
if (EntityFolder.DRAFTS.equals(folder.type))
if (itarget.getPermanentFlags().contains(Flags.Flag.DRAFT))
icopy.setFlag(Flags.Flag.DRAFT, false);
// Move to drafts
if (EntityFolder.DRAFTS.equals(target.type))
if (itarget.getPermanentFlags().contains(Flags.Flag.DRAFT))
icopy.setFlag(Flags.Flag.DRAFT, true);
// Append target
long uid = append(itarget, (MimeMessage) icopy);
// Some providers, like Gmail, don't honor the appended seen flag
if (itarget.getPermanentFlags().contains(Flags.Flag.SEEN)) {
boolean seen = (autoread || message.ui_seen);
icopy = itarget.getMessageByUID(uid);
if (seen != icopy.isSet(Flags.Flag.SEEN)) {
Log.i(target.name + " Fixing id=" + message.id + " seen=" + seen);
icopy.setFlag(Flags.Flag.SEEN, seen);
}
} }
// This is not based on an actual case, so this is just a safeguard
if (itarget.getPermanentFlags().contains(Flags.Flag.DRAFT)) {
boolean draft = EntityFolder.DRAFTS.equals(target.type);
icopy = itarget.getMessageByUID(uid);
if (draft != icopy.isSet(Flags.Flag.DRAFT)) {
Log.i(target.name + " Fixing id=" + message.id + " draft=" + draft);
icopy.setFlag(Flags.Flag.DRAFT, draft);
}
}
// Delete source
if (!copy) {
imessage.setFlag(Flags.Flag.DELETED, true);
ifolder.expunge();
}
} finally {
if (itarget.isOpen())
itarget.close();
} }
// This is not based on an actual case, so this is just a safeguard
if (itarget.getPermanentFlags().contains(Flags.Flag.DRAFT)) {
boolean draft = EntityFolder.DRAFTS.equals(target.type);
icopy = itarget.getMessageByUID(uid);
if (draft != icopy.isSet(Flags.Flag.DRAFT)) {
Log.i(target.name + " Fixing id=" + message.id + " draft=" + draft);
icopy.setFlag(Flags.Flag.DRAFT, draft);
}
}
// Delete source
if (!copy) {
imessage.setFlag(Flags.Flag.DELETED, true);
ifolder.expunge();
}
} finally {
if (itarget.isOpen())
itarget.close();
} }
} }
@ -665,12 +656,19 @@ class Core {
parts.downloadAttachment(context, sequence - 1, attachment.id); parts.downloadAttachment(context, sequence - 1, attachment.id);
} }
private static long append(IMAPFolder ifolder, MimeMessage imessage) throws MessagingException { private static long append(IMAPStore istore, IMAPFolder ifolder, MimeMessage imessage) throws MessagingException {
String msgid = imessage.getMessageID(); String msgid = imessage.getMessageID();
if (msgid == null) if (msgid == null)
throw new IllegalArgumentException("Message ID missing"); throw new IllegalArgumentException("Message ID missing");
ifolder.appendMessages(new Message[]{imessage}); if (istore.hasCapability("UIDPLUS")) {
AppendUID[] uids = ifolder.appendUIDMessages(new Message[]{imessage});
if (uids != null && uids.length > 0) {
Log.i("Appended uid=" + uids[0].uid);
return uids[0].uid;
}
} else
ifolder.appendMessages(new Message[]{imessage});
// Fixed timing issue of at least Courier based servers // Fixed timing issue of at least Courier based servers
ifolder.close(false); ifolder.close(false);