fix UIDNEXT query vs. concurrent imap_fetch_msg()
the uidnext query following message stores can be interleaved with message fetches. that means that we cannot rely on the 1st command in flight being that query. but instead of iterating over all commands in flight, move the uidnext query flag to imap_store (and make sure to check for the presence of a message body before testing it) - this avoids the loop and an extra byte in every command. this also makes it clear that the query is mutually exclusive with loading messages (the untagged responses are not distinguishable).
This commit is contained in:
parent
f099141e42
commit
42f165ecf7
|
@ -113,6 +113,8 @@ struct imap_store {
|
||||||
enum { SST_BAD, SST_HALF, SST_GOOD } state;
|
enum { SST_BAD, SST_HALF, SST_GOOD } state;
|
||||||
/* trash folder's existence is not confirmed yet */
|
/* trash folder's existence is not confirmed yet */
|
||||||
enum { TrashUnknown, TrashChecking, TrashKnown } trashnc;
|
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 got_namespace:1;
|
||||||
uint has_forwarded:1;
|
uint has_forwarded:1;
|
||||||
char delimiter[2]; /* hierarchy delimiter */
|
char delimiter[2]; /* hierarchy delimiter */
|
||||||
|
@ -174,7 +176,6 @@ struct imap_cmd {
|
||||||
char to_trash; /* we are storing to trash, not current. */
|
char to_trash; /* we are storing to trash, not current. */
|
||||||
char create; /* create the mailbox if we get an error which suggests so. */
|
char create; /* create the mailbox if we get an error which suggests so. */
|
||||||
char failok; /* Don't complain about NO response. */
|
char failok; /* Don't complain about NO response. */
|
||||||
char lastuid; /* querying the last UID in the mailbox. */
|
|
||||||
} param;
|
} param;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1144,15 +1145,11 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
|
||||||
if (!uid) {
|
if (!uid) {
|
||||||
// Ignore async flag updates for now.
|
// Ignore async flag updates for now.
|
||||||
status &= ~(M_FLAGS | M_RECENT);
|
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) {
|
} else if (status & M_BODY) {
|
||||||
for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next)
|
for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next)
|
||||||
if (cmdp->param.uid == uid)
|
if (cmdp->param.uid == uid)
|
||||||
goto gotuid;
|
goto gotuid;
|
||||||
error( "IMAP error: unexpected FETCH response (UID %u)\n", uid );
|
goto badrsp;
|
||||||
return LIST_BAD;
|
|
||||||
gotuid:
|
gotuid:
|
||||||
msgdata = ((imap_cmd_fetch_msg_t *)cmdp)->msg_data;
|
msgdata = ((imap_cmd_fetch_msg_t *)cmdp)->msg_data;
|
||||||
msgdata->data = body->val;
|
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)
|
if (status & M_FLAGS)
|
||||||
msgdata->flags = mask;
|
msgdata->flags = mask;
|
||||||
status &= ~(M_FLAGS | M_RECENT | M_BODY | M_DATE);
|
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) );
|
cur = nfcalloc( sizeof(*cur) );
|
||||||
*ctx->msgapp = &cur->gen;
|
*ctx->msgapp = &cur->gen;
|
||||||
ctx->msgapp = &cur->gen.next;
|
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)
|
if (tuid)
|
||||||
memcpy( cur->gen.tuid, tuid, TUIDL );
|
memcpy( cur->gen.tuid, tuid, TUIDL );
|
||||||
status &= ~(M_FLAGS | M_RECENT | M_SIZE | M_HEADER);
|
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) {
|
if (status) {
|
||||||
|
@ -2536,8 +2540,9 @@ imap_open_box_p2( imap_store_t *ctx, imap_cmd_t *gcmd, int response )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert( ctx->fetch_sts == FetchNone );
|
||||||
|
ctx->fetch_sts = FetchUidNext;
|
||||||
INIT_IMAP_CMD(imap_cmd_open_box_t, cmd, cmdp->callback, cmdp->callback_aux)
|
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,
|
imap_exec( ctx, &cmd->gen, imap_open_box_p3,
|
||||||
"UID FETCH * (UID)" );
|
"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;
|
imap_cmd_open_box_t *cmdp = (imap_cmd_open_box_t *)gcmd;
|
||||||
|
|
||||||
|
ctx->fetch_sts = FetchNone;
|
||||||
if (!ctx->uidnext) {
|
if (!ctx->uidnext) {
|
||||||
if (ctx->total_msgs) {
|
if (ctx->total_msgs) {
|
||||||
error( "IMAP error: querying server for highest UID failed\n" );
|
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 );
|
free( excs.data );
|
||||||
cb( DRV_OK, NULL, 0, 0, aux );
|
cb( DRV_OK, NULL, 0, 0, aux );
|
||||||
} else {
|
} else {
|
||||||
|
assert( ctx->fetch_sts == FetchNone );
|
||||||
|
ctx->fetch_sts = FetchMsgs;
|
||||||
|
|
||||||
INIT_REFCOUNTED_STATE(imap_load_box_state_t, sts, cb, aux)
|
INIT_REFCOUNTED_STATE(imap_load_box_state_t, sts, cb, aux)
|
||||||
for (uint i = 0; i < excs.size; ) {
|
for (uint i = 0; i < excs.size; ) {
|
||||||
for (int bl = 0; i < excs.size && bl < 960; i++) {
|
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 )
|
imap_submit_load_p3( imap_store_t *ctx, imap_load_box_state_t *sts )
|
||||||
{
|
{
|
||||||
DONE_REFCOUNTED_STATE_ARGS(sts, {
|
DONE_REFCOUNTED_STATE_ARGS(sts, {
|
||||||
|
ctx->fetch_sts = FetchNone;
|
||||||
if (sts->gen.ret_val == DRV_OK)
|
if (sts->gen.ret_val == DRV_OK)
|
||||||
imap_sort_msgs( ctx );
|
imap_sort_msgs( ctx );
|
||||||
}, ctx->msgs, ctx->total_msgs, ctx->recent_msgs)
|
}, 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.
|
// We appended messages, so we need to re-query UIDNEXT.
|
||||||
ctx->uidnext = 0;
|
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)
|
INIT_IMAP_CMD(imap_cmd_find_new_t, cmd, cmdp->callback, cmdp->callback_aux)
|
||||||
cmd->out_msgs = cmdp->out_msgs;
|
cmd->out_msgs = cmdp->out_msgs;
|
||||||
cmd->uid = cmdp->uid;
|
cmd->uid = cmdp->uid;
|
||||||
cmd->gen.param.lastuid = 1;
|
|
||||||
imap_exec( ctx, &cmd->gen, imap_find_new_msgs_p3,
|
imap_exec( ctx, &cmd->gen, imap_find_new_msgs_p3,
|
||||||
"UID FETCH * (UID)" );
|
"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 *cmdp = (imap_cmd_find_new_t *)gcmd;
|
||||||
imap_cmd_find_new_t *cmd;
|
imap_cmd_find_new_t *cmd;
|
||||||
|
|
||||||
|
ctx->fetch_sts = FetchNone;
|
||||||
if (response != RESP_OK) {
|
if (response != RESP_OK) {
|
||||||
imap_find_new_msgs_p4( ctx, gcmd, response );
|
imap_find_new_msgs_p4( ctx, gcmd, response );
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user