# HG changeset patch # User Timo Sirainen # Date 1150816594 -10800 # Node ID 2461061327ed4b5081ccbd8b13d339b5ec2848ff # Parent 94b3bb847f39dcbc2698088c78fa2b36e7c65a99 NOT condition wasn't handled correctly in SEARCH. diff -r 94b3bb847f39 -r 2461061327ed src/lib-storage/index/index-search.c --- a/src/lib-storage/index/index-search.c Tue Jun 20 16:59:05 2006 +0300 +++ b/src/lib-storage/index/index-search.c Tue Jun 20 18:16:34 2006 +0300 @@ -57,6 +57,12 @@ const struct message_part *part; }; +static int search_parse_msgset_args(struct index_mailbox *ibox, + const struct mail_index_header *hdr, + struct mail_search_arg *args, + uint32_t *seq1_r, uint32_t *seq2_r, + bool not); + static int seqset_contains(struct mail_search_seqset *set, uint32_t seq) { while (set != NULL) { @@ -574,17 +580,51 @@ return TRUE; } +static void update_seqs(const struct mail_search_seqset *set, + const struct mail_index_header *hdr, + uint32_t *seq1_r, uint32_t *seq2_r, bool not) +{ + if (!not) { + /* seq1..seq2 */ + if (*seq1_r < set->seq1 || *seq1_r == 0) + *seq1_r = set->seq1; + if (*seq2_r > set->seq2) + *seq2_r = set->seq2; + } else { + if (set->seq1 == 1) { + /* seq2+1..count */ + if (set->seq2 == hdr->messages_count) { + /* completely outside our range */ + *seq1_r = (uint32_t)-1; + *seq2_r = 0; + } else { + if (*seq1_r < set->seq2 + 1) + *seq1_r = set->seq2 + 1; + } + } else if (set->seq2 == hdr->messages_count) { + /* 1..seq1-1 */ + if (*seq2_r > set->seq1 - 1) + *seq2_r = set->seq1 - 1; + } + } +} + static int search_msgset_fix(struct index_mailbox *ibox, const struct mail_index_header *hdr, struct mail_search_seqset *set, - uint32_t *seq1_r, uint32_t *seq2_r) + uint32_t *seq1_r, uint32_t *seq2_r, bool not) { for (; set != NULL; set = set->next) { if (set->seq1 > hdr->messages_count) { if (set->seq1 != (uint32_t)-1 && set->seq2 != (uint32_t)-1) { + set->seq1 = set->seq2 = 0; + if (not) + continue; + /* completely outside our range */ - set->seq1 = set->seq2 = 0; + *seq1_r = (uint32_t)-1; + *seq2_r = 0; return 0; } /* either seq1 or seq2 is '*', so the last message is @@ -600,50 +640,92 @@ return -1; } - if (*seq1_r > set->seq1 || *seq1_r == 0) - *seq1_r = set->seq1; - if (*seq2_r < set->seq2) - *seq2_r = set->seq2; + update_seqs(set, hdr, seq1_r, seq2_r, not); } return 0; } +static int search_or_parse_msgset_args(struct index_mailbox *ibox, + const struct mail_index_header *hdr, + struct mail_search_arg *args, + uint32_t *seq1_r, uint32_t *seq2_r, + bool not) +{ + uint32_t seq1, seq2, min_seq1 = 0, max_seq2 = 0; + + for (; args != NULL; args = args->next) { + bool cur_not = args->not; + + if (not) + cur_not = !cur_not; + seq1 = 1; seq2 = hdr->messages_count; + + if (args->type == SEARCH_SUB) { + if (search_parse_msgset_args(ibox, hdr, + args->value.subargs, + &seq1, &seq2, cur_not) < 0) + return -1; + } else if (args->type == SEARCH_OR) { + if (search_or_parse_msgset_args(ibox, hdr, + args->value.subargs, + &seq1, &seq2, + cur_not) < 0) + return -1; + } else if (args->type == SEARCH_SEQSET) { + if (search_msgset_fix(ibox, hdr, args->value.seqset, + &seq1, &seq2, cur_not) < 0) + return -1; + } + + if (min_seq1 == 0) { + min_seq1 = seq1; + max_seq2 = seq2; + } else { + if (seq1 < min_seq1) + min_seq1 = seq1; + if (seq2 > max_seq2) + max_seq2 = seq2; + } + } + i_assert(min_seq1 != 0); + + if (min_seq1 > *seq1_r) + *seq1_r = min_seq1; + if (max_seq2 < *seq2_r) + *seq2_r = max_seq2; + return 0; +} + static int search_parse_msgset_args(struct index_mailbox *ibox, const struct mail_index_header *hdr, struct mail_search_arg *args, - uint32_t *seq1_r, uint32_t *seq2_r) + uint32_t *seq1_r, uint32_t *seq2_r, + bool not) { - *seq1_r = *seq2_r = 0; + for (; args != NULL; args = args->next) { + bool cur_not = args->not; - for (; args != NULL; args = args->next) { + if (not) + cur_not = !cur_not; + if (args->type == SEARCH_SUB) { if (search_parse_msgset_args(ibox, hdr, args->value.subargs, - seq1_r, seq2_r) < 0) + seq1_r, seq2_r, + cur_not) < 0) return -1; } else if (args->type == SEARCH_OR) { - /* FIXME: in cases like "SEEN OR 5 7" we shouldn't - limit the range, but in cases like "1 OR 5 7" we - should expand the range. A bit tricky, we'll - just go through everything now to make it work - right. */ - *seq1_r = 1; - *seq2_r = hdr->messages_count; - - /* We still have to fix potential seqsets though */ - if (search_parse_msgset_args(ibox, hdr, - args->value.subargs, - seq1_r, seq2_r) < 0) + /* go through our children and use the widest seqset + range */ + if (search_or_parse_msgset_args(ibox, hdr, + args->value.subargs, + seq1_r, seq2_r, + cur_not) < 0) return -1; } else if (args->type == SEARCH_SEQSET) { if (search_msgset_fix(ibox, hdr, args->value.seqset, - seq1_r, seq2_r) < 0) + seq1_r, seq2_r, cur_not) < 0) return -1; - } else if (args->type == SEARCH_ALL) { - /* go through everything. don't stop, have to fix - seqsets. */ - *seq1_r = 1; - *seq2_r = hdr->messages_count; } } return 0; @@ -744,8 +826,11 @@ return 0; } + ctx->seq1 = 1; + ctx->seq2 = hdr->messages_count; + if (search_parse_msgset_args(ctx->ibox, hdr, args, - &ctx->seq1, &ctx->seq2) < 0) + &ctx->seq1, &ctx->seq2, FALSE) < 0) return -1; if (ctx->seq1 == 0) { diff -r 94b3bb847f39 -r 2461061327ed src/lib-storage/mail-search.c --- a/src/lib-storage/mail-search.c Tue Jun 20 16:59:05 2006 +0300 +++ b/src/lib-storage/mail-search.c Tue Jun 20 18:16:34 2006 +0300 @@ -46,7 +46,7 @@ if (subarg->result == -1) arg->result = -1; - else if (subarg->result == arg->not) { + else if (subarg->result == 0) { /* didn't match */ arg->result = 0; break; @@ -54,6 +54,8 @@ subarg = subarg->next; } + if (arg->not && arg->result != -1) + arg->result = !arg->result; } else if (arg->type == SEARCH_OR) { /* OR-list of conditions */ i_assert(arg->value.subargs != NULL); @@ -64,18 +66,18 @@ if (subarg->result == -1) search_arg_foreach(subarg, callback, context); - if (subarg->result != -1) { - if (subarg->result == !arg->not) { - /* matched */ - arg->result = 1; - break; - } - } else { + if (subarg->result == -1) arg->result = -1; + else if (subarg->result > 0) { + /* matched */ + arg->result = 1; + break; } subarg = subarg->next; } + if (arg->not && arg->result != -1) + arg->result = !arg->result; } else { /* just a single condition */ callback(arg, context);