isync

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

commit 395f8025003c080203ecb8680e9d84d0d8bb2f1b
parent c8f402e43f9c6a3c685fe0f716ffda741beeac13
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Sun, 29 Dec 2019 11:52:26 +0100

fix loading of some messages' sizes in some partial sync scenarios

we need to pass a different "boundary" UID to driver_t::load_box() for
every OPEN_* flag that queries a partial range:
- OPEN_FIND refers to messages newer than all we know about
- OPEN_OLD_IDS refers to messages which are paired
- OPEN_{OLD,NEW}_SIZE refers to messages (not) above the committed
  boundary of already propagated messages

we treated the 3rd like the 2nd, which was just wrong - the actual
boundary may be lower or higher, so we'd produce wrong results when
MaxSize was set and only one of New and ReNew was requested.

Diffstat:
Msrc/driver.h | 10+++++-----
Msrc/drv_imap.c | 8++++----
Msrc/drv_maildir.c | 15++++++++-------
Msrc/drv_proxy.c | 4++--
Msrc/sync.c | 28++++++++++------------------
5 files changed, 29 insertions(+), 36 deletions(-)

diff --git a/src/driver.h b/src/driver.h @@ -206,12 +206,12 @@ struct driver { * Consider only messages with UIDs between minuid and maxuid (inclusive) * and those named in the excs array (smaller than minuid). * The driver takes ownership of the excs array. - * Messages starting with newuid need to have the TUID populated when OPEN_FIND is set. - * Messages up to seenuid need to have the Message-Id populated when OPEN_OLD_IDS is set. - * Messages up to seenuid need to have the size populated when OPEN_OLD_SIZE is set; - * likewise messages above seenuid when OPEN_NEW_SIZE is set. + * Messages starting with finduid need to have the TUID populated when OPEN_FIND is set. + * Messages up to pairuid need to have the Message-Id populated when OPEN_OLD_IDS is set. + * Messages up to newuid need to have the size populated when OPEN_OLD_SIZE is set; + * likewise messages above newuid when OPEN_NEW_SIZE is set. * The returned message list remains owned by the driver. */ - void (*load_box)( store_t *ctx, uint minuid, uint maxuid, uint newuid, uint seenuid, uint_array_t excs, + void (*load_box)( store_t *ctx, uint minuid, uint maxuid, uint finduid, uint pairuid, uint newuid, uint_array_t excs, void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ); /* Fetch the contents and flags of the given message from the current mailbox. */ diff --git a/src/drv_imap.c b/src/drv_imap.c @@ -2683,7 +2683,7 @@ static void imap_submit_load( imap_store_t *, const char *, int, imap_load_box_s static void imap_submit_load_p3( imap_store_t *ctx, imap_load_box_state_t * ); static void -imap_load_box( store_t *gctx, uint minuid, uint maxuid, uint newuid, uint seenuid, uint_array_t excs, +imap_load_box( store_t *gctx, uint minuid, uint maxuid, uint finduid, uint pairuid, uint newuid, uint_array_t excs, void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; @@ -2716,11 +2716,11 @@ imap_load_box( store_t *gctx, uint minuid, uint maxuid, uint newuid, uint seenui uint nranges = 1; if (ctx->opts & (OPEN_OLD_SIZE | OPEN_NEW_SIZE)) imap_set_range( ranges, &nranges, shifted_bit( ctx->opts, OPEN_OLD_SIZE, WantSize), - shifted_bit( ctx->opts, OPEN_NEW_SIZE, WantSize), seenuid ); + shifted_bit( ctx->opts, OPEN_NEW_SIZE, WantSize), newuid ); if (ctx->opts & OPEN_FIND) - imap_set_range( ranges, &nranges, 0, WantTuids, newuid - 1 ); + imap_set_range( ranges, &nranges, 0, WantTuids, finduid - 1 ); if (ctx->opts & OPEN_OLD_IDS) - imap_set_range( ranges, &nranges, WantMsgids, 0, seenuid ); + imap_set_range( ranges, &nranges, WantMsgids, 0, pairuid ); for (uint r = 0; r < nranges; r++) { sprintf( buf, "%u:%u", ranges[r].first, ranges[r].last ); imap_submit_load( ctx, buf, ranges[r].flags, sts ); diff --git a/src/drv_maildir.c b/src/drv_maildir.c @@ -70,7 +70,7 @@ typedef struct { typedef struct { store_t gen; int uvfd, uvok, is_inbox, fresh[3]; - uint opts, minuid, maxuid, newuid, seenuid, uidvalidity, nuid; + uint opts, minuid, maxuid, finduid, pairuid, newuid, uidvalidity, nuid; uint_array_t excs; char *path; /* own */ char *trash; @@ -1139,9 +1139,9 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) free( entry->base ); entry->base = nfstrndup( buf + bl + 4, (size_t)fnl ); } - int want_size = (uid > ctx->seenuid) ? (ctx->opts & OPEN_NEW_SIZE) : (ctx->opts & OPEN_OLD_SIZE); - int want_tuid = ((ctx->opts & OPEN_FIND) && uid >= ctx->newuid); - int want_msgid = ((ctx->opts & OPEN_OLD_IDS) && uid <= ctx->seenuid); + int want_size = (uid > ctx->newuid) ? (ctx->opts & OPEN_NEW_SIZE) : (ctx->opts & OPEN_OLD_SIZE); + int want_tuid = ((ctx->opts & OPEN_FIND) && uid >= ctx->finduid); + int want_msgid = ((ctx->opts & OPEN_OLD_IDS) && uid <= ctx->pairuid); if (!want_size && !want_tuid && !want_msgid) continue; if (!fnl) @@ -1357,7 +1357,7 @@ maildir_confirm_box_empty( store_t *gctx ) maildir_store_t *ctx = (maildir_store_t *)gctx; msg_t_array_alloc_t msglist; - ctx->excs.size = ctx->minuid = ctx->maxuid = ctx->newuid = 0; + ctx->excs.size = ctx->minuid = ctx->maxuid = ctx->finduid = 0; if (maildir_scan( ctx, &msglist ) != DRV_OK) return DRV_BOX_BAD; @@ -1435,7 +1435,7 @@ maildir_prepare_load_box( store_t *gctx, uint opts ) } static void -maildir_load_box( store_t *gctx, uint minuid, uint maxuid, uint newuid, uint seenuid, uint_array_t excs, +maildir_load_box( store_t *gctx, uint minuid, uint maxuid, uint finduid, uint pairuid, uint newuid, uint_array_t excs, void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; @@ -1445,8 +1445,9 @@ maildir_load_box( store_t *gctx, uint minuid, uint maxuid, uint newuid, uint see ctx->minuid = minuid; ctx->maxuid = maxuid; + ctx->finduid = finduid; + ctx->pairuid = pairuid; ctx->newuid = newuid; - ctx->seenuid = seenuid; ARRAY_SQUEEZE( &excs ); ctx->excs = excs; diff --git a/src/drv_proxy.c b/src/drv_proxy.c @@ -198,8 +198,8 @@ proxy_@name@( store_t *gctx@decl_args@, void (*cb)( @decl_cb_args@void *aux ), v //# DEFINE load_box_pre_print_args static char ubuf[12]; //# END -//# DEFINE load_box_print_fmt_args , [%u,%s] (new >= %u, seen <= %u) -//# DEFINE load_box_print_pass_args , minuid, (maxuid == UINT_MAX) ? "inf" : (nfsnprintf( ubuf, sizeof(ubuf), "%u", maxuid ), ubuf), newuid, seenuid +//# DEFINE load_box_print_fmt_args , [%u,%s] (find >= %u, paired <= %u, new > %u) +//# DEFINE load_box_print_pass_args , minuid, (maxuid == UINT_MAX) ? "inf" : (nfsnprintf( ubuf, sizeof(ubuf), "%u", maxuid ), ubuf), finduid, pairuid, newuid //# DEFINE load_box_print_args if (excs.size) { debugn( " excs:" ); diff --git a/src/sync.c b/src/sync.c @@ -170,7 +170,7 @@ typedef struct { uint newmaxuid[2]; // highest UID that is currently being propagated uint uidval[2]; // UID validity value uint newuidval[2]; // UID validity obtained from driver - uint newuid[2]; // TUID lookup makes sense only for UIDs >= this + uint finduid[2]; // TUID lookup makes sense only for UIDs >= this uint maxxfuid; // highest expired UID on far side uchar good_flags[2], bad_flags[2]; } sync_vars_t; @@ -896,7 +896,7 @@ load_state( sync_vars_t *svars ) if (c == 'S') svars->maxuid[t1] = svars->newmaxuid[t1]; else if (c == 'F') - svars->newuid[t1] = t2; + svars->finduid[t1] = t2; else if (c == 'T') *uint_array_append( &svars->trashed_msgs[t1] ) = t2; else if (c == '!') @@ -1350,27 +1350,19 @@ static void box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msg static void load_box( sync_vars_t *svars, int t, uint minwuid, uint_array_t mexcs ) { - uint maxwuid, seenuid; + uint maxwuid = 0, pairuid = UINT_MAX; if (svars->opts[t] & OPEN_NEW) { if (minwuid > svars->maxuid[t] + 1) minwuid = svars->maxuid[t] + 1; maxwuid = UINT_MAX; - if (svars->opts[t] & (OPEN_OLD_IDS|OPEN_OLD_SIZE)) - seenuid = get_seenuid( svars, t ); - else - seenuid = 0; + if (svars->opts[t] & OPEN_OLD_IDS) // Implies OPEN_OLD + pairuid = get_seenuid( svars, t ); } else if (svars->opts[t] & OPEN_OLD) { - maxwuid = seenuid = get_seenuid( svars, t ); - } else - maxwuid = seenuid = 0; - if (seenuid < svars->maxuid[t]) { - /* We cannot rely on the maxuid, as uni-directional syncing does not update it. - * But if it is there, use it to avoid a possible gap in the fetched range. */ - seenuid = svars->maxuid[t]; + maxwuid = get_seenuid( svars, t ); } info( "Loading %s box...\n", str_fn[t] ); - svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], seenuid, mexcs, box_loaded, AUX ); + svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->finduid[t], pairuid, svars->maxuid[t], mexcs, box_loaded, AUX ); } typedef struct { @@ -1814,8 +1806,8 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux if (UseFSync) fdatasync( fileno( svars->jfp ) ); for (t = 0; t < 2; t++) { - svars->newuid[t] = svars->drv[t]->get_uidnext( svars->ctx[t] ); - JLOG( "F %d %u", (t, svars->newuid[t]), "save UIDNEXT of %s", str_fn[t] ); + svars->finduid[t] = svars->drv[t]->get_uidnext( svars->ctx[t] ); + JLOG( "F %d %u", (t, svars->finduid[t]), "save UIDNEXT of %s", str_fn[t] ); svars->new_msgs[t] = svars->msgs[1-t]; msgs_copied( svars, t ); if (check_cancel( svars )) @@ -1921,7 +1913,7 @@ msgs_copied( sync_vars_t *svars, int t ) if (svars->state[t] & ST_FIND_NEW) { debug( "finding just copied messages on %s\n", str_fn[t] ); - svars->drv[t]->find_new_msgs( svars->ctx[t], svars->newuid[t], msgs_found_new, AUX ); + svars->drv[t]->find_new_msgs( svars->ctx[t], svars->finduid[t], msgs_found_new, AUX ); } else { msgs_new_done( svars, t ); }