isync

mailbox synchronization program
git clone https://git.code.sf.net/p/isync/isync
Log | Files | Refs | README | LICENSE

commit 8f39d06015c7491c81f40a35703cfe78529b868f
parent 882c9825cd41ce88ce22f3c3a37f679d61f200df
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Tue, 22 Feb 2022 16:42:22 +0100

fix mixing MaxMessages with MaxSize

this is actually a useful combination for resource-constrained devices.

Diffstat:
MNEWS | 2++
Msrc/run-tests.pl | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/sync.c | 28+++++++++++++++++++++++++---
3 files changed, 152 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS @@ -9,6 +9,8 @@ is now the file's containing directory. Placeholders will be now created for messages exceeding MaxSize even if they are flagged on the source side. +MaxMessages and MaxSize can be used together now. + The unfiltered list of mailboxes in each Store can be printed now. A proper summary is now printed prior to exiting. diff --git a/src/run-tests.pl b/src/run-tests.pl @@ -1313,6 +1313,131 @@ my @X38 = ( ); test("max messages + expunge", \@x38, \@X38, \@O38); +# Expiration with size restriction tests + +my @x40 = ( + P, 0, P, + + A, "**", "*>", "*?", + B, "**", "*>", "*S?", + C, "**", "*>S", "*S?", + D, "*S*", "*>S", "*S?", + E, "*S*", "*>", "*S?", + F, "*S*", "*>S", "*?", + G, "*S*", "*>", "*?", + H, "**", "*>S", "*?", + + I, "*F*", "*>", "*?", + J, "*F*", "*>", "*S?", + K, "*F*", "*>S", "*S?", + L, "*FS*", "*>S", "*S?", + M, "*FS*", "*>", "*S?", + N, "*FS*", "*>S", "*?", + O, "*FS*", "*>", "*?", + P, "*F*", "*>S", "*?", + + Q, "**", "", "", + R, "*FS*", "", "", + S, "*S*", "", "", + + T, "**", "", "", + U, "*FS*", "", "", + V, "*S*", "", "", +); + +my @O41 = ("", "", "MaxSize 1k\nMaxMessages 3\nExpireUnread no\n"); +my @X41 = ( + V, S, V, + + C, "", "-S", "-S", + D, "", "+~", "+T", + E, "", "+~S", "+T", + F, "-S", "-S", "", + G, "", "+~S", "+ST", + H, "", "-S", "", + + K, "", "-S", "-S", + M, "", "+S", "", + N, "-S", "-S", "", + O, "", "+S", "+S", + P, "", "-S", "", + + Q, "", "*>", "*?", + R, "", "*>S", "*S?", + + T, "", "*>", "*?", + U, "", "*>S", "*S?", + V, "", "*>S", "*S?", +); +test("max size without upgrade + max messages", \@x40, \@X41, \@O41); + +my @x42 = ( + T, Q, T, + + A, "**", "*>", "*F?", + B, "**", "*>", "*FS?", + C, "**", "*>S", "*FS?", + D, "*S*", "*>S", "*FS?", + E, "*S*", "*>", "*FS?", + F, "*S*", "*>S", "*F?", + G, "*S*", "*>", "*F?", + H, "**", "*>S", "*F?", + + I, "*F*", "*>", "*F?", + J, "*F*", "*>", "*FS?", + K, "*F*", "*>S", "*FS?", + L, "*FS*", "*>S", "*FS?", + M, "*FS*", "*>", "*FS?", + N, "*FS*", "*>S", "*F?", + O, "*FS*", "*>", "*F?", + P, "*F*", "*>S", "*F?", + + Q, "*S", "", "", + + R, "*", "*", "*", + S, "*", "*", "*", + T, "*", "*", "*", +); + +my @X43 = ( + T, Q, P, + + A, "", ">->", "^*", + A, "&", "^", "&1+T", + B, "", ">->", "^*", + B, "&", "^", "&1+T", + C, "", ">->S", "^*", + C, "&", "^", "&1+T", + D, "", "/", "", + D, "&", "^", "&1+T", + E, "", "/", "", + E, "&", "^", "&1+T", + F, "-S", ">->S", "^*", + F, "&", "^", "&1+T", + G, "", "/", "", + G, "&", "^", "&1+T", + H, "", ">->S", "^*", + H, "&", "^", "&1+T", + + I, "", ">->+F", "^F*", + I, "&", "^", "&1+T", + J, "", ">->+F", "^F*", + J, "&", "^", "&1+T", + K, "", ">->S+F", "^F*", + K, "&", "^", "&1+T", + L, "", ">->+F", "^FS*", + L, "&", "^", "&1+T", + M, "", ">->+FS", "^FS*", + M, "&", "^", "&1+T", + N, "-S", ">->S+F", "^F*", + N, "&", "^", "&1+T", + O, "", ">->+FS", "^FS*", + O, "&", "^", "&1+T", + P, "", ">->S+F", "^F*", + P, "&", "^", "&1+T", +); +test("max size with upgrade + max messages", \@x42, \@X43, \@O41); + # Test for legacy/tampered states with inaccurate maxuid tracking # Joined post-push & post-pull state to have just one test - diff --git a/src/sync.c b/src/sync.c @@ -799,7 +799,9 @@ box_opened2( sync_vars_t *svars, int t ) svars->any_expiring = 1; if (svars->any_expiring) { opts[N] |= OPEN_OLD | OPEN_FLAGS; - if (chan->ops[N] & (OP_NEW | OP_RENEW)) + if (any_dummies[N]) + opts[F] |= OPEN_OLD | OPEN_FLAGS; + else if (chan->ops[N] & (OP_NEW | OP_RENEW)) opts[F] |= OPEN_FLAGS; } svars->opts[F] = svars->drv[F]->prepare_load_box( ctx[F], opts[F] ); @@ -1284,9 +1286,29 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux // to expire in the first place. if (!srec->msg[N]) continue; - nflags = (srec->msg[N]->flags | srec->aflags[N]) & ~srec->dflags[N]; + nflags = srec->msg[N]->flags; + if (srec->status & S_DUMMY(N)) { + if (!srec->msg[F]) + continue; + // We need to pull in the real Flagged and Seen even if flag + // propagation was not requested, as the placeholder's ones are + // useless (except for un-seeing). + // This results in the somewhat weird situation that messages + // which are not visibly flagged remain unexpired. + sflags = srec->msg[F]->flags; + aflags = (sflags & ~srec->flags) & (F_SEEN | F_FLAGGED); + dflags = (~sflags & srec->flags) & F_SEEN; + nflags = (nflags & (~(F_SEEN | F_FLAGGED) | (srec->flags & F_SEEN)) & ~dflags) | aflags; + } + nflags = (nflags | srec->aflags[N]) & ~srec->dflags[N]; } else { - nflags = srec->msg[F]->flags; + if (srec->status & S_UPGRADE) { + // The dummy's F & S flags are mostly masked out anyway, + // but we may be pulling in the real ones. + nflags = (srec->pflags | srec->aflags[N]) & ~srec->dflags[N]; + } else { + nflags = srec->msg[F]->flags; + } } if (!(nflags & F_DELETED) || (srec->status & (S_EXPIRE | S_EXPIRED))) { // The message is not deleted, or it is, but only due to being expired.