Fixed hanging wait operations

pull/152/head
M66B 6 years ago
parent e6d933c231
commit 24a479806e

File diff suppressed because it is too large Load Diff

@ -481,8 +481,10 @@ class Core {
boolean autoread = (jargs.length() > 1 && jargs.getBoolean(1)); boolean autoread = (jargs.length() > 1 && jargs.getBoolean(1));
boolean canMove = istore.hasCapability("MOVE"); long uid;
if (!copy && canMove && if (!copy &&
istore.hasCapability("MOVE") &&
istore.hasCapability("UIDPLUS") &&
!EntityFolder.DRAFTS.equals(folder.type) && !EntityFolder.DRAFTS.equals(folder.type) &&
!EntityFolder.DRAFTS.equals(target.type)) { !EntityFolder.DRAFTS.equals(target.type)) {
// Autoread // Autoread
@ -490,12 +492,14 @@ class Core {
if (autoread && !imessage.isSet(Flags.Flag.SEEN)) if (autoread && !imessage.isSet(Flags.Flag.SEEN))
imessage.setFlag(Flags.Flag.SEEN, true); imessage.setFlag(Flags.Flag.SEEN, true);
// Move message to // Move message to target folder
ifolder.moveMessages(new Message[]{imessage}, itarget); AppendUID[] uids = ifolder.moveUIDMessages(new Message[]{imessage}, itarget);
if (uids == null || uids.length == 0)
throw new MessageRemovedException("Message not moved");
uid = uids[0].uid;
} else { } else {
if (!copy) if (!copy)
Log.w(folder.name + " MOVE by DELETE/APPEND" + Log.w(folder.name + " MOVE by DELETE/APPEND");
" cap=" + canMove + " from=" + folder.type + " to=" + target.type);
// Serialize source message // Serialize source message
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
@ -532,42 +536,63 @@ class Core {
icopy.setFlag(Flags.Flag.DRAFT, true); icopy.setFlag(Flags.Flag.DRAFT, true);
// Append target // Append target
long uid = append(istore, itarget, (MimeMessage) icopy); uid = append(istore, itarget, (MimeMessage) icopy);
Log.i(target.name + " appended id=" + message.id + " uid=" + uid);
// Fixed timing issue of at least Courier based servers
itarget.close(false);
itarget.open(Folder.READ_WRITE);
// Some providers, like Gmail, don't honor the appended seen flag try {
if (itarget.getPermanentFlags().contains(Flags.Flag.SEEN)) { // Fixed timing issue of at least Courier based servers
boolean seen = (autoread || message.ui_seen); itarget.close(false);
icopy = itarget.getMessageByUID(uid); itarget.open(Folder.READ_WRITE);
if (seen != icopy.isSet(Flags.Flag.SEEN)) {
Log.i(target.name + " Fixing id=" + message.id + " seen=" + seen); // Some providers, like Gmail, don't honor the appended seen flag
icopy.setFlag(Flags.Flag.SEEN, seen); 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 // This is not based on an actual case, so this is just a safeguard
if (itarget.getPermanentFlags().contains(Flags.Flag.DRAFT)) { if (itarget.getPermanentFlags().contains(Flags.Flag.DRAFT)) {
boolean draft = EntityFolder.DRAFTS.equals(target.type); boolean draft = EntityFolder.DRAFTS.equals(target.type);
icopy = itarget.getMessageByUID(uid); icopy = itarget.getMessageByUID(uid);
if (draft != icopy.isSet(Flags.Flag.DRAFT)) { if (draft != icopy.isSet(Flags.Flag.DRAFT)) {
Log.i(target.name + " Fixing id=" + message.id + " draft=" + draft); Log.i(target.name + " Fixing id=" + message.id + " draft=" + draft);
icopy.setFlag(Flags.Flag.DRAFT, draft); icopy.setFlag(Flags.Flag.DRAFT, draft);
}
} }
}
// Delete source // Delete source
if (!copy) { if (!copy) {
imessage.setFlag(Flags.Flag.DELETED, true); imessage.setFlag(Flags.Flag.DELETED, true);
ifolder.expunge(); ifolder.expunge();
}
} catch (MessageRemovedException ignored) {
} catch (Throwable ex) {
Log.w(ex);
} }
} catch (Throwable ex) { } finally {
if (itarget.isOpen()) if (itarget.isOpen())
itarget.close(); itarget.close();
throw ex; }
}
Log.i(folder.name + " moved uid=" + uid);
if (jargs.length() > 2) {
long tmpid = jargs.getLong(2);
try {
db.beginTransaction();
db.message().setMessageUid(tmpid, uid);
int waits = -1;
if (jargs.length() > 3) {
long waitid = jargs.getLong(3);
waits = db.operation().deleteOperation(waitid);
}
db.setTransactionSuccessful();
Log.i(folder.name + " set id=" + tmpid + " uid=" + uid + " waits=" + waits);
} finally {
db.endTransaction();
} }
} }
} }
@ -1293,10 +1318,6 @@ class Core {
db.message().updateMessage(message); db.message().updateMessage(message);
else if (BuildConfig.DEBUG) else if (BuildConfig.DEBUG)
Log.i(folder.name + " unchanged uid=" + uid); Log.i(folder.name + " unchanged uid=" + uid);
int wait = db.operation().deleteOperationWait(message.id);
if (wait > 0)
Log.i(folder.name + " deleted wait id=" + message.id);
} }
if (!folder.isOutgoing() && !EntityFolder.ARCHIVE.equals(folder.type)) { if (!folder.isOutgoing() && !EntityFolder.ARCHIVE.equals(folder.type)) {

@ -49,7 +49,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
// https://developer.android.com/topic/libraries/architecture/room.html // https://developer.android.com/topic/libraries/architecture/room.html
@Database( @Database(
version = 50, version = 51,
entities = { entities = {
EntityIdentity.class, EntityIdentity.class,
EntityAccount.class, EntityAccount.class,
@ -546,6 +546,13 @@ public abstract class DB extends RoomDatabase {
db.execSQL("CREATE INDEX `index_message_subject` ON `message` (`subject`)"); db.execSQL("CREATE INDEX `index_message_subject` ON `message` (`subject`)");
} }
}) })
.addMigrations(new Migration(50, 51) {
@Override
public void migrate(SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("DELETE FROM operation WHERE name = '" + EntityOperation.WAIT + "'");
}
})
.build(); .build();
} }

@ -94,11 +94,6 @@ public interface DaoOperation {
@Insert @Insert
long insertOperation(EntityOperation operation); long insertOperation(EntityOperation operation);
@Query("DELETE FROM operation" +
" WHERE message = :message" +
" AND name = '" + EntityOperation.WAIT + "'")
int deleteOperationWait(long message);
@Query("DELETE FROM operation WHERE id = :id") @Query("DELETE FROM operation WHERE id = :id")
void deleteOperation(long id); int deleteOperation(long id);
} }

@ -108,6 +108,8 @@ public class EntityOperation {
// Parameters: // Parameters:
// 0: target folder id // 0: target folder id
// 1: allow auto read // 1: allow auto read
// 2: temporary target message id
// 3: wait operation id
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean autoread = prefs.getBoolean("autoread", false); boolean autoread = prefs.getBoolean("autoread", false);
@ -132,11 +134,12 @@ public class EntityOperation {
// Create copy without uid in target folder // Create copy without uid in target folder
// Message with same msgid can be in archive // Message with same msgid can be in archive
Long newid = null; Long tmpid = null;
if (message.uid != null && if (message.uid != null &&
target.synchronize && target.synchronize &&
message.received > cal_keep.getTimeInMillis() && message.received > cal_keep.getTimeInMillis() &&
db.message().countMessageByMsgId(target.id, message.msgid) == 0) { db.message().countMessageByMsgId(target.id, message.msgid) == 0) {
// Copy message to target folder
long id = message.id; long id = message.id;
long uid = message.uid; long uid = message.uid;
boolean seen = message.seen; boolean seen = message.seen;
@ -149,9 +152,8 @@ public class EntityOperation {
message.seen = true; message.seen = true;
message.ui_seen = true; message.ui_seen = true;
} }
newid = db.message().insertMessage(message); tmpid = db.message().insertMessage(message);
message.id = newid;
queue(context, db, message, WAIT);
message.id = id; message.id = id;
message.account = source.account; message.account = source.account;
message.folder = source.id; message.folder = source.id;
@ -163,33 +165,48 @@ public class EntityOperation {
try { try {
Helper.copy( Helper.copy(
EntityMessage.getFile(context, id), EntityMessage.getFile(context, id),
EntityMessage.getFile(context, newid)); EntityMessage.getFile(context, tmpid));
} catch (IOException ex) { } catch (IOException ex) {
Log.e(ex); Log.e(ex);
db.message().setMessageContent(newid, false, null, null); db.message().setMessageContent(tmpid, false, null, null);
} }
EntityAttachment.copy(context, db, message.id, newid); EntityAttachment.copy(context, db, message.id, tmpid);
// Store new id for when source message was deleted
jargs.put(2, newid);
} }
// Cross account move // Cross account move
if (!source.account.equals(target.account)) if (source.account.equals(target.account)) {
jargs.put(2, tmpid);
// Block operations until message is moved
JSONArray wargs = new JSONArray();
wargs.put(source.id);
wargs.put(message.id);
EntityOperation wait = new EntityOperation();
wait.folder = target.id;
wait.message = tmpid;
wait.name = EntityOperation.WAIT;
wait.args = wargs.toString();
wait.created = new Date().getTime();
wait.id = db.operation().insertOperation(wait);
jargs.put(3, wait.id);
} else {
if (message.raw != null && message.raw) { if (message.raw != null && message.raw) {
name = ADD; name = ADD;
folder = target.id; folder = target.id;
jargs = new JSONArray(); jargs = new JSONArray();
jargs.put(0, newid); // Can be null jargs.put(0, tmpid); // Can be null
jargs.put(1, autoread); jargs.put(1, autoread);
} else { } else {
name = RAW; name = RAW;
jargs = new JSONArray(); jargs = new JSONArray();
jargs.put(0, newid); // Can be null jargs.put(0, tmpid); // Can be null
jargs.put(1, autoread); jargs.put(1, autoread);
jargs.put(2, target.id); jargs.put(2, target.id);
} }
}
} else if (DELETE.equals(name)) } else if (DELETE.equals(name))
db.message().setMessageUiHide(message.id, true); db.message().setMessageUiHide(message.id, true);

Loading…
Cancel
Save