From: Timo Sirainen Date: Mon, 16 Mar 2020 11:33:55 +0000 (+0200) Subject: imap: Fix SEARCH PARTIAL handling with other options X-Git-Tag: 2.3.11.2~521 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c64b337ca08ab04530dbecc23a3fad9b22ab08a8;p=thirdparty%2Fdovecot%2Fcore.git imap: Fix SEARCH PARTIAL handling with other options Especially SAVE and RELEVANCY should use only the partial results, not all results. --- diff --git a/src/imap/imap-search.c b/src/imap/imap-search.c index 25b16551bf..9344695a3c 100644 --- a/src/imap/imap-search.c +++ b/src/imap/imap-search.c @@ -228,46 +228,7 @@ static void imap_search_send_result_standard(struct imap_search_context *ctx) static void imap_search_send_partial(struct imap_search_context *ctx, string_t *str) { - struct seq_range *range; - uint32_t n, diff; - unsigned int i, count, delete_count; - str_printfa(str, " PARTIAL (%u:%u ", ctx->partial1, ctx->partial2); - ctx->partial1--; - ctx->partial2--; - - /* we need to be able to handle non-sorted seq ranges (for SORT - replies), so do this ourself instead of using seq_range_array_*() - functions. */ - range = array_get_modifiable(&ctx->result, &count); - /* delete everything up to partial1 */ - delete_count = 0; - for (i = n = 0; i < count; i++) { - diff = range[i].seq2 - range[i].seq1; - if (n + diff >= ctx->partial1) { - range[i].seq1 += ctx->partial1 - n; - delete_count = i; - break; - } - n += diff + 1; - } - if (i == count) { - /* partial1 points past the result */ - array_clear(&ctx->result); - } else { - /* delete everything after partial2 */ - for (n = ctx->partial1; i < count; i++) { - diff = range[i].seq2 - range[i].seq1; - if (n + diff >= ctx->partial2) { - range[i].seq2 = range[i].seq1 + (ctx->partial2 - n); - array_delete(&ctx->result, i + 1, count-(i+1)); - break; - } - n += diff + 1; - } - array_delete(&ctx->result, 0, delete_count); - } - if (array_count(&ctx->result) == 0) { /* no results (in range) */ str_append(str, "NIL"); @@ -442,9 +403,29 @@ static bool cmd_search_more(struct client_command_context *cmd) ctx->min_id = id; search_update_mail(ctx, mail); } - if (HAS_ANY_BITS(opts, SEARCH_RETURN_ALL)) + if (HAS_ANY_BITS(opts, SEARCH_RETURN_ALL)) { + /* ALL and PARTIAL are mutually exclusive */ + i_assert(HAS_NO_BITS(opts, SEARCH_RETURN_PARTIAL)); search_add_result_id(ctx, id); - else if (HAS_ANY_BITS(opts, SEARCH_RETURN_COUNT)) { + } else if ((opts & SEARCH_RETURN_PARTIAL) != 0) { + /* only update if it's within range */ + i_assert(HAS_NO_BITS(opts, SEARCH_RETURN_ALL)); + if (ctx->partial1 <= ctx->result_count && + ctx->partial2 >= ctx->result_count) + search_add_result_id(ctx, id); + else if (HAS_ALL_BITS(opts, SEARCH_RETURN_COUNT | + SEARCH_RETURN_SAVE)) { + /* (SAVE COUNT PARTIAL n:m) must include all + results in SAVE, but not include mails + outside the PARTIAL range in MODSEQ or + RELEVANCY */ + seq_range_array_add(&cmd->client->search_saved_uidset, + mail->uid); + continue; + } else { + continue; + } + } else if (HAS_ANY_BITS(opts, SEARCH_RETURN_COUNT)) { /* with COUNT don't add it to results, but handle SAVE and MODSEQ */ } else if (HAS_ANY_BITS(opts, SEARCH_RETURN_MIN |