commit eab3874918f9c80db69a1b72d2f546efba4caa01
parent f2f519e20b75a0cfb21198ddaa5e24b72f92f5f8
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Wed, 1 Jun 2022 14:04:12 +0200
orphan/prune sync entries also if messages were expunged externally
deletions we propagated ourselves are implicitly covered by that as
well, so we don't need to record them separately anymore.
Diffstat:
3 files changed, 47 insertions(+), 22 deletions(-)
diff --git a/src/run-tests.pl b/src/run-tests.pl
@@ -941,6 +941,7 @@ sub test($$$$)
my @x01 = (
I, 0, I,
+ P, "_", "*", "_",
R, "*", "", "", # Skipped/failed messages to prevent maxuid topping
S, "", "", "*",
A, "*F", "*", "*",
@@ -949,6 +950,8 @@ my @x01 = (
D, "*", "*", "*",
E, "*T", "*", "*",
F, "*", "*", "*T",
+ O, "*T", "*T", "*T",
+ Q, "_", "*T", "*T",
G, "*F", "*", "_",
H, "*FT", "*", "*",
I, "_", "*", "*",
@@ -961,11 +964,13 @@ my @x01 = (
my @O01 = ("", "", "");
my @X01 = (
M, 0, K,
+ P, "", "/", "",
A, "", "+F", "+F",
B, "+F", "+F", "",
C, "", "+FS", "+S",
E, "", "+T", "+T",
F, "+T", "+T", "",
+ Q, "", "<", "",
G, "+T", ">", "",
H, "", "+FT", "+FT",
I, "", "<", "+T",
@@ -979,11 +984,14 @@ test("full", \@x01, \@X01, \@O01);
my @O02 = ("", "", "Expunge Both\n");
my @X02 = (
M, 0, K,
+ P, "", "/", "",
A, "", "+F", "+F",
B, "+F", "+F", "",
C, "", "+FS", "+S",
E, "/", "/", "/",
F, "/", "/", "/",
+ O, "/", "/", "/",
+ Q, "", "/", "/",
G, "/", "/", "",
H, "/", "/", "/",
I, "", "/", "/",
@@ -997,11 +1005,14 @@ test("full + expunge both", \@x01, \@X02, \@O02);
my @O03 = ("", "", "Expunge Near\n");
my @X03 = (
M, 0, K,
+ P, "", "/", "",
A, "", "+F", "+F",
B, "+F", "+F", "",
C, "", "+FS", "+S",
E, "", ">+T", "/",
F, "+T", ">+T", "/",
+ O, "", ">", "/",
+ Q, "", "/", "/",
G, "+T", ">", "",
H, "", ">+T", "/",
I, "", "/", "/",
@@ -1014,9 +1025,11 @@ test("full + expunge near side", \@x01, \@X03, \@O03);
my @O04 = ("", "", "Sync Pull\n");
my @X04 = (
K, 0, I,
+ P, "", "/", "", # Only because test uses Maildir driver
A, "", "+F", "+F",
C, "", "+FS", "+S",
E, "", "+T", "+T",
+ Q, "", "<", "",
H, "", "+FT", "+FT",
I, "", "<", "+T",
J, "", "*T", "*T",
@@ -1027,11 +1040,13 @@ test("pull", \@x01, \@X04, \@O04);
my @O05 = ("", "", "Sync Flags\n");
my @X05 = (
I, 0, I,
+ P, "", "/", "",
A, "", "+F", "+F",
B, "+F", "+F", "",
C, "", "+FS", "+S",
E, "", "+T", "+T",
F, "+T", "+T", "",
+ Q, "", "<", "",
H, "", "+FT", "+FT",
);
test("flags", \@x01, \@X05, \@O05);
@@ -1039,7 +1054,9 @@ test("flags", \@x01, \@X05, \@O05);
my @O06 = ("", "", "Sync Delete\n");
my @X06 = (
I, 0, I,
+ P, "", "/", "",
G, "+T", ">", "",
+ Q, "", "<", "",
I, "", "<", "+T",
);
test("deletions", \@x01, \@X06, \@O06);
@@ -1057,9 +1074,11 @@ test("new", \@x01, \@X07, \@O07);
my @O08 = ("", "", "Sync PushFlags PullDelete\n");
my @X08 = (
I, 0, I,
+ P, "", "/", "",
B, "+F", "+F", "",
C, "", "+F", "",
F, "+T", "+T", "",
+ Q, "", "<", "",
I, "", "<", "+T",
);
test("push flags + pull deletions", \@x01, \@X08, \@O08);
@@ -1067,8 +1086,11 @@ test("push flags + pull deletions", \@x01, \@X08, \@O08);
my @O09 = ("", "", "Sync None\nExpunge Both\n");
my @X09 = (
I, 0, I,
+ P, "", "/", "",
E, "/", "", "",
F, "", "", "/",
+ O, "/", "/", "/",
+ Q, "", "/", "/",
H, "/", "", "",
J, "/", "", "",
L, "", "", "/",
@@ -1080,6 +1102,8 @@ my @O0A = ("", "", "Sync None\nExpunge Near\n");
my @X0A = (
I, 0, I,
F, "", "", "/",
+ O, "", "", "/",
+ Q, "", "", "/",
L, "", "", "/",
);
test("noop + expunge near side", \@x01, \@X0A, \@O0A);
diff --git a/src/sync.c b/src/sync.c
@@ -1036,6 +1036,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
} else if (del[t]) {
// The target was newly expunged, so there is nothing to update.
// The deletion is propagated in the opposite iteration.
+ srec->status |= S_GONE(t);
} else if (!srec->uid[t]) {
// The target was never stored, or was previously expunged, so there
// is nothing to update.
@@ -1340,7 +1341,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
for (t = 0; t < 2; t++) {
if (!srec->uid[t])
continue;
- if (!srec->msg[t] && (svars->opts[t] & OPEN_OLD)) {
+ if (srec->status & S_GONE(t)) {
// The message was expunged. No need to call flags_set(), because:
// - for S_DELETE and S_PURGE, the entry will be pruned due to both sides being gone
// - for regular flag propagations, there is nothing to do
@@ -1571,10 +1572,7 @@ flags_set_p2( sync_vars_t *svars, sync_rec_t *srec, int t )
if (srec->status & S_PURGE) {
JLOG( "P %u %u", (srec->uid[F], srec->uid[N]), "deleted dummy" );
srec->status = (srec->status & ~S_PURGE) | S_PURGED;
- } else if (srec->status & S_DELETE) {
- JLOG( "%c %u %u 0", ("><"[t], srec->uid[F], srec->uid[N]), "%sed deletion", str_hl[t] );
- srec->uid[t^1] = 0;
- } else {
+ } else if (!(srec->status & S_DELETE)) {
uchar nflags = (srec->flags | srec->aflags[t]) & ~srec->dflags[t];
if (srec->flags != nflags) {
JLOG( "* %u %u %u", (srec->uid[F], srec->uid[N], nflags), "%sed flags %s; were %s",
@@ -1802,24 +1800,26 @@ box_closed_p2( sync_vars_t *svars, int t )
PC_JLOG( "N %d %u", (t, svars->maxuid[t]), "up maxuid of %s", str_fn[t] );
}
- if (((svars->state[F] | svars->state[N]) & ST_DID_EXPUNGE) || svars->chan->max_messages) {
- debug( "purging obsolete entries\n" );
- for (srec = svars->srecs; srec; srec = srec->next) {
- if (srec->status & S_DEAD)
- continue;
- if (!srec->uid[N] || ((srec->status & S_DEL(N)) && (svars->state[N] & ST_DID_EXPUNGE))) {
- if (!srec->uid[F] || ((srec->status & S_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE)) ||
- ((srec->status & S_EXPIRED) && svars->maxuid[F] >= srec->uid[F] && svars->maxxfuid >= srec->uid[F])) {
- PC_JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "killing" );
- srec->status = S_DEAD;
- } else if (srec->uid[N] && (srec->status & S_DEL(F))) {
- PC_JLOG( "> %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" );
- srec->uid[N] = 0;
- }
- } else if (srec->uid[F] && ((srec->status & S_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE)) && (srec->status & S_DEL(N))) {
- PC_JLOG( "< %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" );
- srec->uid[F] = 0;
+ debug( "purging obsolete entries\n" );
+ for (srec = svars->srecs; srec; srec = srec->next) {
+ if (srec->status & S_DEAD)
+ continue;
+ if ((srec->status & S_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE))
+ srec->status |= S_GONE(F);
+ if ((srec->status & S_DEL(N)) && (svars->state[N] & ST_DID_EXPUNGE))
+ srec->status |= S_GONE(N);
+ if (!srec->uid[N] || (srec->status & S_GONE(N))) {
+ if (!srec->uid[F] || (srec->status & S_GONE(F)) ||
+ ((srec->status & S_EXPIRED) && svars->maxuid[F] >= srec->uid[F] && svars->maxxfuid >= srec->uid[F])) {
+ PC_JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "killing" );
+ srec->status = S_DEAD;
+ } else if (srec->uid[N] && (srec->status & S_DEL(F))) {
+ PC_JLOG( "> %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" );
+ srec->uid[N] = 0;
}
+ } else if (srec->uid[F] && (srec->status & S_GONE(F)) && (srec->status & S_DEL(N))) {
+ PC_JLOG( "< %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" );
+ srec->uid[F] = 0;
}
}
diff --git a/src/sync_p.h b/src/sync_p.h
@@ -17,6 +17,7 @@ BIT_ENUM(
S_PENDING, // the entry is new and awaits propagation (possibly a retry)
S_DUMMY(2), // f/n message is only a placeholder
S_SKIPPED, // pre-1.4 legacy: the entry was not propagated (message is too big)
+ S_GONE(2), // ephemeral: f/n message has been expunged
S_DEL(2), // ephemeral: f/n message would be subject to expunge
S_DELETE, // ephemeral: flags propagation is a deletion
S_UPGRADE, // ephemeral: upgrading placeholder, do not apply MaxSize