From 2fa75cf159d18c5705a877690b62f9e5de160c81 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sun, 11 Jan 2015 14:29:19 +0100 Subject: [PATCH] fix UID assignment with some non-UIDPLUS servers the seznam.cz IMAP server seems very eager to send UIDNEXT responses despite not supporting UIDPLUS. this doesn't appear to be a particularly sensible combination, but it's valid nonetheless. however, that means that we need to save the UIDNEXT value before we start storing messages, lest imap_find_new_msgs() will simply overlook them. we do that outside the driver, in an already present field - this actually makes the main path more consistent with the journal recovery path. analysis by Tomas Tintera . REFMAIL: 20141220215032.GA10115@kyvadlo.trosos.seznam.cz --- src/driver.h | 2 +- src/drv_imap.c | 21 ++++++++++++++------- src/drv_maildir.c | 2 +- src/sync.c | 5 +++-- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/driver.h b/src/driver.h index 31ee1bf..4557aa6 100644 --- a/src/driver.h +++ b/src/driver.h @@ -192,7 +192,7 @@ struct driver { /* Index the messages which have newly appeared in the mailbox, including their * temporary UID headers. This is needed if store_msg() does not guarantee returning * a UID; otherwise the driver needs to implement only the OPEN_FIND flag. */ - void (*find_new_msgs)( store_t *ctx, + void (*find_new_msgs)( store_t *ctx, int newuid, void (*cb)( int sts, void *aux ), void *aux ); /* Add/remove the named flags to/from the given message. The message may be either diff --git a/src/drv_imap.c b/src/drv_imap.c index e6d93ee..f58736d 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -153,6 +153,11 @@ struct imap_cmd_out_uid { int out_uid; }; +struct imap_cmd_find_new { + struct imap_cmd_simple gen; + int uid; +}; + struct imap_cmd_refcounted_state { void (*callback)( int sts, void *aux ); void *callback_aux; @@ -2158,28 +2163,30 @@ imap_store_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int resp static void imap_find_new_msgs_p2( imap_store_t *, struct imap_cmd *, int ); static void -imap_find_new_msgs( store_t *gctx, +imap_find_new_msgs( store_t *gctx, int newuid, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; - struct imap_cmd_simple *cmd; + struct imap_cmd_find_new *cmd; - INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux) - imap_exec( (imap_store_t *)ctx, &cmd->gen, imap_find_new_msgs_p2, "CHECK" ); + INIT_IMAP_CMD_X(imap_cmd_find_new, cmd, cb, aux) + cmd->uid = newuid; + imap_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_find_new_msgs_p2, "CHECK" ); } static void imap_find_new_msgs_p2( imap_store_t *ctx, struct imap_cmd *gcmd, int response ) { - struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)gcmd, *cmd; + struct imap_cmd_find_new *cmdp = (struct imap_cmd_find_new *)gcmd; + struct imap_cmd_simple *cmd; if (response != RESP_OK) { imap_done_simple_box( ctx, gcmd, response ); return; } - INIT_IMAP_CMD(imap_cmd_simple, cmd, cmdp->callback, cmdp->callback_aux) + INIT_IMAP_CMD(imap_cmd_simple, cmd, cmdp->gen.callback, cmdp->gen.callback_aux) imap_exec( (imap_store_t *)ctx, &cmd->gen, imap_done_simple_box, - "UID FETCH %d:1000000000 (UID BODY.PEEK[HEADER.FIELDS (X-TUID)])", ctx->gen.uidnext ); + "UID FETCH %d:1000000000 (UID BODY.PEEK[HEADER.FIELDS (X-TUID)])", cmdp->uid ); } /******************* imap_list *******************/ diff --git a/src/drv_maildir.c b/src/drv_maildir.c index f936938..f151b5b 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -1292,7 +1292,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, } static void -maildir_find_new_msgs( store_t *gctx ATTR_UNUSED, +maildir_find_new_msgs( store_t *gctx ATTR_UNUSED, int newuid ATTR_UNUSED, void (*cb)( int sts, void *aux ) ATTR_UNUSED, void *aux ATTR_UNUSED ) { assert( !"maildir_find_new_msgs is not supposed to be called" ); diff --git a/src/sync.c b/src/sync.c index 99f3895..443da1b 100644 --- a/src/sync.c +++ b/src/sync.c @@ -1506,7 +1506,8 @@ box_loaded( int sts, void *aux ) if (UseFSync) fdatasync( fileno( svars->jfp ) ); for (t = 0; t < 2; t++) { - Fprintf( svars->jfp, "%c %d\n", "{}"[t], svars->ctx[t]->uidnext ); + svars->newuid[t] = svars->ctx[t]->uidnext; + Fprintf( svars->jfp, "%c %d\n", "{}"[t], svars->newuid[t] ); for (tmsg = svars->ctx[1-t]->msgs; tmsg; tmsg = tmsg->next) { if ((srec = tmsg->srec) && srec->tuid[0]) { svars->new_total[t]++; @@ -1604,7 +1605,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_ms[t] ); - svars->drv[t]->find_new_msgs( svars->ctx[t], msgs_found_new, AUX ); + svars->drv[t]->find_new_msgs( svars->ctx[t], svars->newuid[t], msgs_found_new, AUX ); } else { msgs_new_done( svars, t ); }