isync

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

commit f7458a96d30cef20e8b4cb85b622d4eabaee41ae
parent 4c141231447cba66c38f1a47768c153753fe7811
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Mon, 16 May 2022 12:01:18 +0200

handle copying/trashing failures more carefully

report them as errors (not warnings), let them cause a non-zero exit
code, and in the case of trashing, prevent the subsequent expunge. the
exception are messages that just disappeared below our feet.

Diffstat:
Msrc/sync.c | 56++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 44 insertions(+), 12 deletions(-)

diff --git a/src/sync.c b/src/sync.c @@ -57,6 +57,7 @@ BIT_ENUM( ST_FIND_NEW, ST_FOUND_NEW, ST_SENT_TRASH, + ST_TRASH_BAD, ST_CLOSING, ST_CLOSED, ST_SENT_CANCEL, @@ -82,6 +83,7 @@ sanitize_flags( uchar tflags, sync_vars_t *svars, int t ) enum { COPY_OK, + COPY_GONE, COPY_NOGOOD, COPY_CANCELED, COPY_FAIL, @@ -144,7 +146,8 @@ msg_fetched( int sts, void *aux ) if (srec || scr != tcr) { const char *err; if ((err = copy_msg_convert( scr, tcr, vars ))) { - warn( "Warning: message %u from %s %s; skipping.\n", vars->msg->uid, str_fn[t^1], err ); + error( "Error: message %u from %s %s; skipping.\n", vars->msg->uid, str_fn[t^1], err ); + svars->ret |= SYNC_FAIL; vars->cb( COPY_NOGOOD, 0, vars ); return; } @@ -156,7 +159,15 @@ msg_fetched( int sts, void *aux ) vars->cb( COPY_CANCELED, 0, vars ); break; case DRV_MSG_BAD: - vars->cb( COPY_NOGOOD, 0, vars ); + if (vars->msg->status & M_DEAD) { + // The message was expunged under our feet; this is no error. + vars->cb( COPY_GONE, 0, vars ); + } else { + INIT_SVARS(vars->aux); + // Driver already reported error. + svars->ret |= SYNC_FAIL; + vars->cb( COPY_NOGOOD, 0, vars ); + } break; default: // DRV_BOX_BAD vars->cb( COPY_FAIL, 0, vars ); @@ -179,9 +190,10 @@ msg_stored( int sts, uint uid, void *aux ) break; case DRV_MSG_BAD: INIT_SVARS(vars->aux); - (void)svars; - warn( "Warning: %s refuses to store message %u from %s.\n", - str_fn[t], vars->msg->uid, str_fn[t^1] ); + // Driver already reported error, but we still need to report the source. + error( "Error: %s refuses to store message %u from %s.\n", + str_fn[t], vars->msg->uid, str_fn[t^1] ); + svars->ret |= SYNC_FAIL; vars->cb( COPY_NOGOOD, 0, vars ); break; default: // DRV_BOX_BAD @@ -1404,6 +1416,7 @@ msg_copied( int sts, uint uid, copy_vars_t *vars ) ASSIGN_UID( srec, t, uid, "%sed message", str_hl[t] ); break; case COPY_NOGOOD: + case COPY_GONE: srec->status = S_DEAD; JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "%s failed", str_hl[t] ); break; @@ -1715,10 +1728,22 @@ msgs_flags_set( sync_vars_t *svars, int t ) static void msg_trashed( int sts, void *aux ) { - if (sts == DRV_MSG_BAD) - sts = DRV_BOX_BAD; SVARS_CHECK_RET_VARS(trash_vars_t); - JLOG( "T %d %u", (t, vars->msg->uid), "trashed on %s", str_fn[t] ); + switch (sts) { + case DRV_OK: + JLOG( "T %d %u", (t, vars->msg->uid), "trashed on %s", str_fn[t] ); + break; + case DRV_MSG_BAD: + if (vars->msg->status & M_DEAD) + break; + // Driver already reported error. + svars->ret |= SYNC_FAIL; + if (svars->opts[t] & OPEN_UID_EXPUNGE) + vars->msg->status &= ~M_EXPUNGE; + else + svars->state[t] |= ST_TRASH_BAD; + break; + } free( vars ); trash_done[t]++; stats(); @@ -1732,9 +1757,18 @@ static void msg_rtrashed( int sts, uint uid ATTR_UNUSED, copy_vars_t *vars ) { DECL_INIT_SVARS(vars->aux); + t ^= 1; switch (sts) { case COPY_OK: - case COPY_NOGOOD: /* the message is gone or heavily busted */ + JLOG( "T %d %u", (t, vars->msg->uid), "trashed remotely on %s", str_fn[t^1] ); + break; + case COPY_GONE: + break; + case COPY_NOGOOD: + if (svars->opts[t] & OPEN_UID_EXPUNGE) + vars->msg->status &= ~M_EXPUNGE; + else + svars->state[t] |= ST_TRASH_BAD; break; default: // COPY_FAIL cancel_sync( svars ); @@ -1743,8 +1777,6 @@ msg_rtrashed( int sts, uint uid ATTR_UNUSED, copy_vars_t *vars ) free( vars ); return; } - t ^= 1; - JLOG( "T %d %u", (t, vars->msg->uid), "trashed remotely on %s", str_fn[t^1] ); free( vars ); trash_done[t]++; stats(); @@ -1769,7 +1801,7 @@ sync_close( sync_vars_t *svars, int t ) svars->state[t] |= ST_CLOSING; if ((svars->chan->ops[t] & (OP_EXPUNGE | OP_EXPUNGE_SOLO)) && !(DFlags & FAKEEXPUNGE) - /*&& !(svars->state[t] & ST_TRASH_BAD)*/) { + && !(svars->state[t] & ST_TRASH_BAD)) { if (Verbosity >= TERSE || (DFlags & EXT_EXIT)) { if (svars->opts[t] & OPEN_UID_EXPUNGE) { for (message_t *tmsg = svars->msgs[t]; tmsg; tmsg = tmsg->next) {