Fixed hanging wait operations

This commit is contained in:
M66B 2019-03-07 08:45:10 +00:00
parent e6d933c231
commit 24a479806e
5 changed files with 1631 additions and 57 deletions

File diff suppressed because it is too large Load Diff

View File

@ -481,8 +481,10 @@ class Core {
boolean autoread = (jargs.length() > 1 && jargs.getBoolean(1));
boolean canMove = istore.hasCapability("MOVE");
if (!copy && canMove &&
long uid;
if (!copy &&
istore.hasCapability("MOVE") &&
istore.hasCapability("UIDPLUS") &&
!EntityFolder.DRAFTS.equals(folder.type) &&
!EntityFolder.DRAFTS.equals(target.type)) {
// Autoread
@ -490,12 +492,14 @@ class Core {
if (autoread && !imessage.isSet(Flags.Flag.SEEN))
imessage.setFlag(Flags.Flag.SEEN, true);
// Move message to
ifolder.moveMessages(new Message[]{imessage}, itarget);
// Move message to target folder
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 {
if (!copy)
Log.w(folder.name + " MOVE by DELETE/APPEND" +
" cap=" + canMove + " from=" + folder.type + " to=" + target.type);
Log.w(folder.name + " MOVE by DELETE/APPEND");
// Serialize source message
ByteArrayOutputStream bos = new ByteArrayOutputStream();
@ -532,42 +536,63 @@ class Core {
icopy.setFlag(Flags.Flag.DRAFT, true);
// Append target
long uid = append(istore, itarget, (MimeMessage) icopy);
Log.i(target.name + " appended id=" + message.id + " uid=" + uid);
uid = append(istore, itarget, (MimeMessage) icopy);
// Fixed timing issue of at least Courier based servers
itarget.close(false);
itarget.open(Folder.READ_WRITE);
try {
// 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
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);
// 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);
// 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();
// Delete source
if (!copy) {
imessage.setFlag(Flags.Flag.DELETED, true);
ifolder.expunge();
}
} catch (MessageRemovedException ignored) {
} catch (Throwable ex) {
Log.w(ex);
}
} catch (Throwable ex) {
} finally {
if (itarget.isOpen())
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);
else if (BuildConfig.DEBUG)
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)) {

View File

@ -49,7 +49,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
// https://developer.android.com/topic/libraries/architecture/room.html
@Database(
version = 50,
version = 51,
entities = {
EntityIdentity.class,
EntityAccount.class,
@ -546,6 +546,13 @@ public abstract class DB extends RoomDatabase {
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();
}

View File

@ -94,11 +94,6 @@ public interface DaoOperation {
@Insert
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")
void deleteOperation(long id);
int deleteOperation(long id);
}

View File

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