diff --git a/src/drv_imap.c b/src/drv_imap.c index 27d43ec..054face 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -113,6 +113,8 @@ struct imap_store { enum { SST_BAD, SST_HALF, SST_GOOD } state; /* trash folder's existence is not confirmed yet */ enum { TrashUnknown, TrashChecking, TrashKnown } trashnc; + // What kind of BODY-less FETCH response we're expecting. + enum { FetchNone, FetchMsgs, FetchUidNext } fetch_sts; uint got_namespace:1; uint has_forwarded:1; char delimiter[2]; /* hierarchy delimiter */ @@ -174,7 +176,6 @@ struct imap_cmd { char to_trash; /* we are storing to trash, not current. */ char create; /* create the mailbox if we get an error which suggests so. */ char failok; /* Don't complain about NO response. */ - char lastuid; /* querying the last UID in the mailbox. */ } param; }; @@ -1144,15 +1145,11 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) if (!uid) { // Ignore async flag updates for now. status &= ~(M_FLAGS | M_RECENT); - } else if ((cmdp = ctx->in_progress) && cmdp->param.lastuid) { - // Workaround for server not sending UIDNEXT and/or APPENDUID. - ctx->uidnext = uid + 1; } else if (status & M_BODY) { for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next) if (cmdp->param.uid == uid) goto gotuid; - error( "IMAP error: unexpected FETCH response (UID %u)\n", uid ); - return LIST_BAD; + goto badrsp; gotuid: msgdata = ((imap_cmd_fetch_msg_t *)cmdp)->msg_data; msgdata->data = body->val; @@ -1162,7 +1159,10 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) if (status & M_FLAGS) msgdata->flags = mask; status &= ~(M_FLAGS | M_RECENT | M_BODY | M_DATE); - } else { + } else if (ctx->fetch_sts == FetchUidNext) { + // Workaround for server not sending UIDNEXT and/or APPENDUID. + ctx->uidnext = uid + 1; + } else if (ctx->fetch_sts == FetchMsgs) { cur = nfcalloc( sizeof(*cur) ); *ctx->msgapp = &cur->gen; ctx->msgapp = &cur->gen.next; @@ -1175,6 +1175,10 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) if (tuid) memcpy( cur->gen.tuid, tuid, TUIDL ); status &= ~(M_FLAGS | M_RECENT | M_SIZE | M_HEADER); + } else { + badrsp: + error( "IMAP error: unexpected FETCH response (UID %u)\n", uid ); + return LIST_BAD; } if (status) { @@ -2536,8 +2540,9 @@ imap_open_box_p2( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) return; } + assert( ctx->fetch_sts == FetchNone ); + ctx->fetch_sts = FetchUidNext; INIT_IMAP_CMD(imap_cmd_open_box_t, cmd, cmdp->callback, cmdp->callback_aux) - cmd->gen.param.lastuid = 1; imap_exec( ctx, &cmd->gen, imap_open_box_p3, "UID FETCH * (UID)" ); } @@ -2547,6 +2552,7 @@ imap_open_box_p3( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) { imap_cmd_open_box_t *cmdp = (imap_cmd_open_box_t *)gcmd; + ctx->fetch_sts = FetchNone; if (!ctx->uidnext) { if (ctx->total_msgs) { error( "IMAP error: querying server for highest UID failed\n" ); @@ -2714,6 +2720,9 @@ imap_load_box( store_t *gctx, uint minuid, uint maxuid, uint finduid, uint pairu free( excs.data ); cb( DRV_OK, NULL, 0, 0, aux ); } else { + assert( ctx->fetch_sts == FetchNone ); + ctx->fetch_sts = FetchMsgs; + INIT_REFCOUNTED_STATE(imap_load_box_state_t, sts, cb, aux) for (uint i = 0; i < excs.size; ) { for (int bl = 0; i < excs.size && bl < 960; i++) { @@ -2821,6 +2830,7 @@ static void imap_submit_load_p3( imap_store_t *ctx, imap_load_box_state_t *sts ) { DONE_REFCOUNTED_STATE_ARGS(sts, { + ctx->fetch_sts = FetchNone; if (sts->gen.ret_val == DRV_OK) imap_sort_msgs( ctx ); }, ctx->msgs, ctx->total_msgs, ctx->recent_msgs) @@ -3126,11 +3136,12 @@ imap_find_new_msgs_p2( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) // We appended messages, so we need to re-query UIDNEXT. ctx->uidnext = 0; + assert( ctx->fetch_sts == FetchNone ); + ctx->fetch_sts = FetchUidNext; INIT_IMAP_CMD(imap_cmd_find_new_t, cmd, cmdp->callback, cmdp->callback_aux) cmd->out_msgs = cmdp->out_msgs; cmd->uid = cmdp->uid; - cmd->gen.param.lastuid = 1; imap_exec( ctx, &cmd->gen, imap_find_new_msgs_p3, "UID FETCH * (UID)" ); } @@ -3141,6 +3152,7 @@ imap_find_new_msgs_p3( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) imap_cmd_find_new_t *cmdp = (imap_cmd_find_new_t *)gcmd; imap_cmd_find_new_t *cmd; + ctx->fetch_sts = FetchNone; if (response != RESP_OK) { imap_find_new_msgs_p4( ctx, gcmd, response ); return;