From: Timo Sirainen Date: Mon, 9 Jun 2008 02:11:18 +0000 (+0300) Subject: Merged latest v1.1 changes. X-Git-Tag: 1.2.alpha1~363 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=93b52c89d07b56908b0ac222c3dc1eb0dbb1e93a;p=thirdparty%2Fdovecot%2Fcore.git Merged latest v1.1 changes. --HG-- branch : HEAD --- 93b52c89d07b56908b0ac222c3dc1eb0dbb1e93a diff --cc src/imap/client.c index 8dafdbba40,615268ec24..d80b01b5d4 --- a/src/imap/client.c +++ b/src/imap/client.c @@@ -127,16 -147,20 +147,22 @@@ void client_destroy(struct client *clie /* finish off all the queued commands. */ if (client->output_lock != NULL) - client_command_cancel(client->output_lock); + client_command_cancel(&client->output_lock); + while (client->command_queue != NULL) { + cmd = client->command_queue; + client_command_cancel(&cmd); + } + /* handle the input_lock command last. it might have been waiting on + other queued commands (although we probably should just drop the + command at that point since it hasn't started running. but this may + change in future). */ if (client->input_lock != NULL) - client_command_cancel(client->input_lock); - while (client->command_queue != NULL) - client_command_cancel(client->command_queue); + client_command_cancel(&client->input_lock); - if (client->mailbox != NULL) + if (client->mailbox != NULL) { + client_search_updates_free(client); mailbox_close(&client->mailbox); + } mail_namespaces_deinit(&client->namespaces); if (client->free_parser != NULL) diff --cc src/imap/cmd-store.c index 4ae413339c,44f3c2cde9..54f5f0695e --- a/src/imap/cmd-store.c +++ b/src/imap/cmd-store.c @@@ -121,13 -49,8 +121,13 @@@ bool cmd_store(struct client_command_co struct mail_search_context *search_ctx; struct mailbox_transaction_context *t; struct mail *mail; - const char *messageset, *item; - bool silent, failed; + struct imap_store_context ctx; + ARRAY_TYPE(seq_range) modified_set = ARRAY_INIT; + enum mailbox_transaction_flags flags = 0; + enum imap_sync_flags imap_sync_flags = 0; - const char *tagged_reply; ++ const char *reply, *tagged_reply; + string_t *str; + int ret; if (!client_read_args(cmd, 0, 0, &args)) return FALSE; @@@ -139,41 -66,50 +139,52 @@@ client_send_command_error(cmd, "Invalid arguments."); return TRUE; } - - if (!get_modify_type(cmd, item, &modify_type, &silent)) - return TRUE; - - if (args[2].type == IMAP_ARG_LIST) { - if (!client_parse_mail_flags(cmd, - IMAP_ARG_LIST_ARGS(&args[2]), - &flags, &keywords_list)) - return TRUE; - } else { - if (!client_parse_mail_flags(cmd, args+2, - &flags, &keywords_list)) - return TRUE; - } - - box = client->mailbox; - search_arg = imap_search_get_arg(cmd, messageset, cmd->uid); - if (search_arg == NULL) + ret = imap_search_get_seqset(cmd, IMAP_ARG_STR_NONULL(args), + cmd->uid, &search_args); + if (ret <= 0) + return ret < 0; + + memset(&ctx, 0, sizeof(ctx)); + ctx.cmd = cmd; + if (!store_parse_args(&ctx, ++args)) return TRUE; - if (mailbox_is_readonly(box)) { ++ if (mailbox_is_readonly(client->mailbox)) { ++ if (ctx.max_modseq < (uint64_t)-1) ++ reply = "NO CONDSTORE failed: Mailbox is read-only."; ++ else ++ reply = "OK Store ignored with read-only mailbox."; + return cmd_sync(cmd, MAILBOX_SYNC_FLAG_FAST | + (cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES), - 0, "OK Store ignored with read-only mailbox."); ++ 0, reply); + } + - t = mailbox_transaction_begin(box, !silent ? 0 : - MAILBOX_TRANSACTION_FLAG_HIDE); - if (keywords_list == NULL && modify_type != MODIFY_REPLACE) - keywords = NULL; - else if (mailbox_keywords_create(box, keywords_list, &keywords) < 0) { - /* invalid keywords */ - mailbox_transaction_rollback(&t); - client_send_storage_error(cmd, mailbox_get_storage(box)); - return TRUE; - } - search_ctx = mailbox_search_init(t, NULL, search_arg, NULL); + if (ctx.silent) + flags |= MAILBOX_TRANSACTION_FLAG_HIDE; + if (ctx.max_modseq < (uint64_t)-1) + flags |= MAILBOX_TRANSACTION_FLAG_REFRESH; ++ + t = mailbox_transaction_begin(client->mailbox, flags); + search_ctx = mailbox_search_init(t, search_args, NULL); + mail_search_args_unref(&search_args); + /* FIXME: UNCHANGEDSINCE should be atomic, but this requires support + from mail-storage API. So for now we fake it. */ mail = mail_alloc(t, MAIL_FETCH_FLAGS, NULL); while (mailbox_search_next(search_ctx, mail) > 0) { - if (modify_type == MODIFY_REPLACE || flags != 0) - mail_update_flags(mail, modify_type, flags); - if (modify_type == MODIFY_REPLACE || keywords != NULL) - mail_update_keywords(mail, modify_type, keywords); + if (ctx.max_modseq < (uint64_t)-1) { + if (mail_get_modseq(mail) > ctx.max_modseq) { + seq_range_array_add(&modified_set, 64, + cmd->uid ? mail->uid : mail->seq); + continue; + } + } + if (ctx.modify_type == MODIFY_REPLACE || ctx.flags != 0) + mail_update_flags(mail, ctx.modify_type, ctx.flags); + if (ctx.modify_type == MODIFY_REPLACE || ctx.keywords != NULL) { + mail_update_keywords(mail, ctx.modify_type, + ctx.keywords); + } } mail_free(&mail); diff --cc src/imap/imap-search.c index c567f35631,d3b3636c6f..0b93aff485 --- a/src/imap/imap-search.c +++ b/src/imap/imap-search.c @@@ -15,56 -16,546 +15,61 @@@ struct search_build_data const char *error; }; -static int -imap_uidset_parse(pool_t pool, struct mailbox *box, const char *uidset, - struct mail_search_seqset **seqset_r, const char **error_r) +static bool search_args_have_searchres(struct mail_search_arg *sargs) { - struct mail_search_seqset *seqset, **p; - bool last; - - *seqset_r = imap_messageset_parse(pool, uidset); - if (*seqset_r == NULL) { - *error_r = "Invalid UID messageset"; - return -1; - } - - p = seqset_r; - for (seqset = *seqset_r; seqset != NULL; seqset = seqset->next) { - if (seqset->seq1 == (uint32_t)-1) { - /* last message, stays same */ - continue; + for (; sargs != NULL; sargs = sargs->next) { + switch (sargs->type) { + case SEARCH_UIDSET: + if (strcmp(sargs->value.str, "$") == 0) + return TRUE; + break; + case SEARCH_SUB: + case SEARCH_OR: + if (search_args_have_searchres(sargs->value.subargs)) + return TRUE; + break; + default: + break; } - - last = seqset->seq2 == (uint32_t)-1; - mailbox_get_uids(box, seqset->seq1, seqset->seq2, - &seqset->seq1, &seqset->seq2); - if (seqset->seq1 == 0 && last) { - /* we need special case for too_high_uid:* case */ - seqset->seq1 = seqset->seq2 = (uint32_t)-1; - } - - if (seqset->seq1 != 0) - p = &seqset->next; - else - *p = seqset->next; } - - *error_r = NULL; - return 0; + return FALSE; } -static struct mail_search_arg * -search_arg_new(pool_t pool, enum mail_search_arg_type type) +int imap_search_args_build(struct client_command_context *cmd, + const struct imap_arg *args, const char *charset, + struct mail_search_args **search_args_r) { - struct mail_search_arg *arg; - - arg = p_new(pool, struct mail_search_arg, 1); - arg->type = type; - - return arg; -} + struct mail_search_args *sargs; + const char *error; -static bool -arg_get_next(struct search_build_data *data, const struct imap_arg **args, - const char **value_r) -{ - if ((*args)->type == IMAP_ARG_EOL) { - data->error = "Missing parameter for argument"; - return FALSE; - } - if ((*args)->type != IMAP_ARG_ATOM && - (*args)->type != IMAP_ARG_STRING) { - data->error = "Invalid parameter for argument"; - return FALSE; ++ if (args->type == IMAP_ARG_EOL) { ++ client_send_command_error(cmd, "Missing search parameters"); ++ return -1; + } + - *value_r = IMAP_ARG_STR(*args); - *args += 1; - return TRUE; -} - -#define ARG_NEW_SINGLE(type) \ - arg_new_single(data, next_sarg, type) -static bool -arg_new_single(struct search_build_data *data, - struct mail_search_arg **next_sarg, - enum mail_search_arg_type type) -{ - *next_sarg = search_arg_new(data->pool, type); - return TRUE; -} - -#define ARG_NEW_STR(type) \ - arg_new_str(data, args, next_sarg, type) -static bool -arg_new_str(struct search_build_data *data, - const struct imap_arg **args, struct mail_search_arg **next_sarg, - enum mail_search_arg_type type) -{ - struct mail_search_arg *sarg; - const char *value; - - *next_sarg = sarg = search_arg_new(data->pool, type); - if (!arg_get_next(data, args, &value)) - return FALSE; - sarg->value.str = p_strdup(data->pool, value); - return TRUE; -} - -#define ARG_NEW_FLAGS(flags) \ - arg_new_flags(data, next_sarg, flags) -static bool -arg_new_flags(struct search_build_data *data, - struct mail_search_arg **next_sarg, enum mail_flags flags) -{ - struct mail_search_arg *sarg; - - *next_sarg = sarg = search_arg_new(data->pool, SEARCH_FLAGS); - sarg->value.flags = flags; - return TRUE; -} - -static bool -arg_new_keyword(struct search_build_data *data, - const struct imap_arg **args, - struct mail_search_arg **next_sarg) -{ - struct mail_search_arg *sarg; - const char *value, *keywords[2]; - struct mail_storage *storage; - enum mail_error error; - - *next_sarg = sarg = search_arg_new(data->pool, SEARCH_KEYWORDS); - if (!arg_get_next(data, args, &value)) - return FALSE; - - keywords[0] = value; - keywords[1] = NULL; - - if (mailbox_keywords_create(data->box, keywords, - &sarg->value.keywords) < 0) { - storage = mailbox_get_storage(data->box); - data->error = mail_storage_get_last_error(storage, &error); - return FALSE; + if (mail_search_build_from_imap_args(args, charset, + &sargs, &error) < 0) { + client_send_command_error(cmd, error); + return -1; } - return TRUE; -} - -#define ARG_NEW_SIZE(type) \ - arg_new_size(data, args, next_sarg, type) -static bool -arg_new_size(struct search_build_data *data, - const struct imap_arg **args, struct mail_search_arg **next_sarg, - enum mail_search_arg_type type) -{ - struct mail_search_arg *sarg; - const char *value; - char *p; - - *next_sarg = sarg = search_arg_new(data->pool, type); - if (!arg_get_next(data, args, &value)) - return FALSE; - sarg->value.size = strtoull(value, &p, 10); - if (*p != '\0') { - data->error = "Invalid search size parameter"; - return FALSE; + if (search_args_have_searchres(sargs->args)) { + if (client_handle_search_save_ambiguity(cmd)) + return 0; } - return TRUE; -} - -#define ARG_NEW_DATE(type) \ - arg_new_date(data, args, next_sarg, type) -static bool -arg_new_date(struct search_build_data *data, - const struct imap_arg **args, struct mail_search_arg **next_sarg, - enum mail_search_arg_type type) -{ - struct mail_search_arg *sarg; - const char *value; - *next_sarg = sarg = search_arg_new(data->pool, type); - if (!arg_get_next(data, args, &value)) - return FALSE; - if (!imap_parse_date(value, &sarg->value.time)) { - data->error = "Invalid search date parameter"; - return FALSE; - } - return TRUE; + mail_search_args_init(sargs, cmd->client->mailbox, TRUE, + &cmd->client->search_saved_uidset); + *search_args_r = sargs; + return 1; } -#define ARG_NEW_HEADER(type, hdr_name) \ - arg_new_header(data, args, next_sarg, type, hdr_name) static bool -arg_new_header(struct search_build_data *data, - const struct imap_arg **args, struct mail_search_arg **next_sarg, - enum mail_search_arg_type type, const char *hdr_name) +msgset_is_valid(ARRAY_TYPE(seq_range) *seqset, uint32_t messages_count) { - struct mail_search_arg *sarg; - const char *value; + const struct seq_range *range; + unsigned int count; - *next_sarg = sarg = search_arg_new(data->pool, type); - if (!arg_get_next(data, args, &value)) - return FALSE; - - sarg->hdr_field_name = p_strdup(data->pool, hdr_name); - sarg->value.str = p_strdup(data->pool, value); - return TRUE; -} - -static bool search_arg_build(struct search_build_data *data, - const struct imap_arg **args, - struct mail_search_arg **next_sarg) -{ - struct mail_search_seqset *seqset; - struct mail_search_arg **subargs; - const struct imap_arg *arg; - const char *str; - - if ((*args)->type == IMAP_ARG_EOL) { - data->error = "Missing argument"; - return FALSE; - } - - arg = *args; - - if (arg->type == IMAP_ARG_NIL) { - /* NIL not allowed */ - data->error = "NIL not allowed"; - return FALSE; - } - - if (arg->type == IMAP_ARG_LIST) { - const struct imap_arg *listargs = IMAP_ARG_LIST_ARGS(arg); - - if (listargs->type == IMAP_ARG_EOL) { - data->error = "Empty list not allowed"; - return FALSE; - } - - *next_sarg = search_arg_new(data->pool, SEARCH_SUB); - subargs = &(*next_sarg)->value.subargs; - while (listargs->type != IMAP_ARG_EOL) { - if (!search_arg_build(data, &listargs, subargs)) - return FALSE; - subargs = &(*subargs)->next; - } - - *args += 1; - return TRUE; - } - - i_assert(arg->type == IMAP_ARG_ATOM || - arg->type == IMAP_ARG_STRING); - - /* string argument - get the name and jump to next */ - str = IMAP_ARG_STR(arg); - *args += 1; - str = t_str_ucase(str); - - switch (*str) { - case 'A': - if (strcmp(str, "ANSWERED") == 0) - return ARG_NEW_FLAGS(MAIL_ANSWERED); - else if (strcmp(str, "ALL") == 0) - return ARG_NEW_SINGLE(SEARCH_ALL); - break; - case 'B': - if (strcmp(str, "BODY") == 0) { - /* */ - if (IMAP_ARG_TYPE_IS_STRING((*args)->type) && - *IMAP_ARG_STR(*args) == '\0') { - *args += 1; - return ARG_NEW_SINGLE(SEARCH_ALL); - } - return ARG_NEW_STR(SEARCH_BODY); - } else if (strcmp(str, "BEFORE") == 0) { - /* */ - return ARG_NEW_DATE(SEARCH_BEFORE); - } else if (strcmp(str, "BCC") == 0) { - /* */ - return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str); - } - break; - case 'C': - if (strcmp(str, "CC") == 0) { - /* */ - return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str); - } - break; - case 'D': - if (strcmp(str, "DELETED") == 0) - return ARG_NEW_FLAGS(MAIL_DELETED); - else if (strcmp(str, "DRAFT") == 0) - return ARG_NEW_FLAGS(MAIL_DRAFT); - break; - case 'F': - if (strcmp(str, "FLAGGED") == 0) - return ARG_NEW_FLAGS(MAIL_FLAGGED); - else if (strcmp(str, "FROM") == 0) { - /* */ - return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str); - } - break; - case 'H': - if (strcmp(str, "HEADER") == 0) { - /* */ - const char *key; - - if ((*args)->type == IMAP_ARG_EOL) { - data->error = "Missing parameter for HEADER"; - return FALSE; - } - if ((*args)->type != IMAP_ARG_ATOM && - (*args)->type != IMAP_ARG_STRING) { - data->error = "Invalid parameter for HEADER"; - return FALSE; - } - - key = t_str_ucase(IMAP_ARG_STR(*args)); - *args += 1; - return ARG_NEW_HEADER(SEARCH_HEADER, key); - } - break; - case 'K': - if (strcmp(str, "KEYWORD") == 0) { - /* */ - return arg_new_keyword(data, args, next_sarg); - } - break; - case 'L': - if (strcmp(str, "LARGER") == 0) { - /* */ - return ARG_NEW_SIZE(SEARCH_LARGER); - } - break; - case 'N': - if (strcmp(str, "NOT") == 0) { - if (!search_arg_build(data, args, next_sarg)) - return FALSE; - (*next_sarg)->not = !(*next_sarg)->not; - return TRUE; - } else if (strcmp(str, "NEW") == 0) { - /* NEW == (RECENT UNSEEN) */ - *next_sarg = search_arg_new(data->pool, SEARCH_SUB); - - subargs = &(*next_sarg)->value.subargs; - *subargs = search_arg_new(data->pool, SEARCH_FLAGS); - (*subargs)->value.flags = MAIL_RECENT; - (*subargs)->next = search_arg_new(data->pool, - SEARCH_FLAGS); - (*subargs)->next->value.flags = MAIL_SEEN; - (*subargs)->next->not = TRUE; - return TRUE; - } - break; - case 'O': - if (strcmp(str, "OR") == 0) { - /* */ - *next_sarg = search_arg_new(data->pool, SEARCH_OR); - - subargs = &(*next_sarg)->value.subargs; - for (;;) { - if (!search_arg_build(data, args, subargs)) - return FALSE; - - subargs = &(*subargs)->next; - - /* OR OR ... - put them all - under one SEARCH_OR list. */ - if ((*args)->type == IMAP_ARG_EOL) - break; - - if ((*args)->type != IMAP_ARG_ATOM || - strcasecmp(IMAP_ARG_STR_NONULL(*args), - "OR") != 0) - break; - - *args += 1; - } - - if (!search_arg_build(data, args, subargs)) - return FALSE; - return TRUE; - } if (strcmp(str, "ON") == 0) { - /* */ - return ARG_NEW_DATE(SEARCH_ON); - } if (strcmp(str, "OLD") == 0) { - /* OLD == NOT RECENT */ - if (!ARG_NEW_FLAGS(MAIL_RECENT)) - return FALSE; - - (*next_sarg)->not = TRUE; - return TRUE; - } - break; - case 'R': - if (strcmp(str, "RECENT") == 0) - return ARG_NEW_FLAGS(MAIL_RECENT); - break; - case 'S': - if (strcmp(str, "SEEN") == 0) - return ARG_NEW_FLAGS(MAIL_SEEN); - else if (strcmp(str, "SUBJECT") == 0) { - /* */ - return ARG_NEW_HEADER(SEARCH_HEADER_COMPRESS_LWSP, str); - } else if (strcmp(str, "SENTBEFORE") == 0) { - /* */ - return ARG_NEW_DATE(SEARCH_SENTBEFORE); - } else if (strcmp(str, "SENTON") == 0) { - /* */ - return ARG_NEW_DATE(SEARCH_SENTON); - } else if (strcmp(str, "SENTSINCE") == 0) { - /* */ - return ARG_NEW_DATE(SEARCH_SENTSINCE); - } else if (strcmp(str, "SINCE") == 0) { - /* */ - return ARG_NEW_DATE(SEARCH_SINCE); - } else if (strcmp(str, "SMALLER") == 0) { - /* */ - return ARG_NEW_SIZE(SEARCH_SMALLER); - } - break; - case 'T': - if (strcmp(str, "TEXT") == 0) { - /* */ - if (IMAP_ARG_TYPE_IS_STRING((*args)->type) && - *IMAP_ARG_STR(*args) == '\0') { - *args += 1; - return ARG_NEW_SINGLE(SEARCH_ALL); - } - return ARG_NEW_STR(SEARCH_TEXT); - } else if (strcmp(str, "TO") == 0) { - /* */ - return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str); - } - break; - case 'U': - if (strcmp(str, "UID") == 0) { - /* */ - if (!ARG_NEW_STR(SEARCH_SEQSET)) - return FALSE; - - return imap_uidset_parse(data->pool, data->box, - (*next_sarg)->value.str, - &(*next_sarg)->value.seqset, - &data->error) == 0; - } else if (strcmp(str, "UNANSWERED") == 0) { - if (!ARG_NEW_FLAGS(MAIL_ANSWERED)) - return FALSE; - (*next_sarg)->not = TRUE; - return TRUE; - } else if (strcmp(str, "UNDELETED") == 0) { - if (!ARG_NEW_FLAGS(MAIL_DELETED)) - return FALSE; - (*next_sarg)->not = TRUE; - return TRUE; - } else if (strcmp(str, "UNDRAFT") == 0) { - if (!ARG_NEW_FLAGS(MAIL_DRAFT)) - return FALSE; - (*next_sarg)->not = TRUE; - return TRUE; - } else if (strcmp(str, "UNFLAGGED") == 0) { - if (!ARG_NEW_FLAGS(MAIL_FLAGGED)) - return FALSE; - (*next_sarg)->not = TRUE; - return TRUE; - } else if (strcmp(str, "UNKEYWORD") == 0) { - /* */ - if (!arg_new_keyword(data, args, next_sarg)) - return FALSE; - (*next_sarg)->not = TRUE; - return TRUE; - } else if (strcmp(str, "UNSEEN") == 0) { - if (!ARG_NEW_FLAGS(MAIL_SEEN)) - return FALSE; - (*next_sarg)->not = TRUE; - return TRUE; - } - break; - case 'X': - if (strcmp(str, "X-BODY-FAST") == 0) { - /* */ - if (IMAP_ARG_TYPE_IS_STRING((*args)->type) && - *IMAP_ARG_STR(*args) == '\0') { - *args += 1; - return ARG_NEW_SINGLE(SEARCH_ALL); - } - return ARG_NEW_STR(SEARCH_BODY_FAST); - } else if (strcmp(str, "X-TEXT-FAST") == 0) { - /* */ - if (IMAP_ARG_TYPE_IS_STRING((*args)->type) && - *IMAP_ARG_STR(*args) == '\0') { - *args += 1; - return ARG_NEW_SINGLE(SEARCH_ALL); - } - return ARG_NEW_STR(SEARCH_TEXT_FAST); - } - break; - default: - if (*str == '*' || (*str >= '0' && *str <= '9')) { - /* */ - seqset = imap_messageset_parse(data->pool, str); - if (seqset == NULL) { - data->error = "Invalid messageset"; - return FALSE; - } - - if (!ARG_NEW_SINGLE(SEARCH_SEQSET)) - return FALSE; - - (*next_sarg)->value.seqset = seqset; - return TRUE; - } - break; - } - - data->error = t_strconcat("Unknown argument ", str, NULL); - return FALSE; -} - -struct mail_search_arg * -imap_search_args_build(pool_t pool, struct mailbox *box, - const struct imap_arg *args, const char **error_r) -{ - struct search_build_data data; - struct mail_search_arg *first_sarg, **sargs; - - *error_r = NULL; - - data.box = box; - data.pool = pool; - data.error = NULL; - - /* get the first arg */ - first_sarg = NULL; sargs = &first_sarg; - while (args->type != IMAP_ARG_EOL) { - if (!search_arg_build(&data, &args, sargs)) { - imap_search_args_free(box, first_sarg); - *error_r = data.error; - return NULL; - } - sargs = &(*sargs)->next; - } - - if (first_sarg == NULL) - *error_r = "Missing search parameters"; - return first_sarg; -} - -static bool -msgset_is_valid(const struct mail_search_seqset *set, uint32_t messages_count) -{ /* when there are no messages, all messagesets are invalid. if there's at least one message: - * gives seq1 = seq2 = (uint32_t)-1 diff --cc src/lib-index/mail-index-private.h index b6c9db7879,42b928a455..e5845df336 --- a/src/lib-index/mail-index-private.h +++ b/src/lib-index/mail-index-private.h @@@ -220,7 -218,7 +220,8 @@@ struct mail_index unsigned int mapping:1; unsigned int syncing:1; unsigned int need_recreate:1; + unsigned int modseqs_enabled:1; + unsigned int initial_create:1; }; extern struct mail_index_module_register mail_index_module_register; diff --cc src/lib-storage/index/Makefile.am index b4217cfa8e,086d324031..25a434f617 --- a/src/lib-storage/index/Makefile.am +++ b/src/lib-storage/index/Makefile.am @@@ -29,10 -26,9 +30,11 @@@ libstorage_index_a_SOURCES = headers = \ index-mail.h \ index-sort.h \ + index-sort-private.h \ index-storage.h \ - index-sync-changes.h + index-sync-changes.h \ + index-sync-private.h \ + index-thread-private.h if INSTALL_HEADERS pkginc_libdir=$(pkgincludedir)/src/lib-storage/index diff --cc src/lib-storage/index/index-search.c index ec1153c896,feafec1c4f..a26eef39a4 --- a/src/lib-storage/index/index-search.c +++ b/src/lib-storage/index/index-search.c @@@ -140,10 -144,10 +140,12 @@@ static int search_arg_match_index(struc int ret; switch (arg->type) { + case SEARCH_UIDSET: + return seq_range_exists(&arg->value.seqset, rec->uid); case SEARCH_FLAGS: - flags = rec->flags; + /* recent flag shouldn't be set, but indexes from v1.0.x + may contain it. */ + flags = rec->flags & ~MAIL_RECENT; if ((arg->value.flags & MAIL_RECENT) != 0 && index_mailbox_is_recent(ctx->ibox, rec->uid)) flags |= MAIL_RECENT; diff --cc src/lib-storage/index/index-sync.c index 7a4435a8be,1262dd23e1..2a722c8962 --- a/src/lib-storage/index/index-sync.c +++ b/src/lib-storage/index/index-sync.c @@@ -99,10 -122,8 +108,10 @@@ static void index_view_sync_recs_get(st uint32_t seq1, seq2; i_array_init(&ctx->flag_updates, 128); + if ((ctx->ibox->box.enabled_features & MAILBOX_FEATURE_CONDSTORE) != 0) + i_array_init(&ctx->modseq_updates, 32); - while (mail_index_view_sync_next(ctx->sync_ctx, &sync)) { - switch (sync.type) { + while (mail_index_view_sync_next(ctx->sync_ctx, &sync_rec)) { + switch (sync_rec.type) { case MAIL_INDEX_SYNC_TYPE_APPEND: /* not interested */ break; @@@ -113,17 -134,12 +122,17 @@@ case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD: case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE: case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET: - if (mail_index_lookup_seq_range(ctx->ibox->view, - sync_rec.uid1, - sync_rec.uid2, - &seq1, &seq2)) { + if (!mail_index_lookup_seq_range(ctx->ibox->view, - sync.uid1, sync.uid2, ++ sync_rec.uid1, sync_rec.uid2, + &seq1, &seq2)) + break; + - if (!sync.hidden) { ++ if (!sync_rec.hidden) { seq_range_array_add_range(&ctx->flag_updates, seq1, seq2); + } else if (array_is_created(&ctx->modseq_updates)) { + seq_range_array_add_range(&ctx->modseq_updates, + seq1, seq2); } break; } @@@ -225,24 -231,14 +234,24 @@@ bool index_mailbox_sync_next(struct mai if (ctx->failed) return FALSE; - flag_updates = array_get(&ctx->flag_updates, &count); - if (ctx->flag_update_pos < count) { + range = array_get(&ctx->flag_updates, &count); + if (ctx->flag_update_idx < count) { sync_rec_r->type = MAILBOX_SYNC_TYPE_FLAGS; - sync_rec_r->seq1 = flag_updates[ctx->flag_update_pos].seq1; - sync_rec_r->seq2 = flag_updates[ctx->flag_update_pos].seq2; - ctx->flag_update_pos++; + sync_rec_r->seq1 = range[ctx->flag_update_idx].seq1; + sync_rec_r->seq2 = range[ctx->flag_update_idx].seq2; + ctx->flag_update_idx++; - return 1; + return TRUE; } + if (array_is_created(&ctx->modseq_updates)) { + range = array_get(&ctx->modseq_updates, &count); + if (ctx->modseq_update_idx < count) { + sync_rec_r->type = MAILBOX_SYNC_TYPE_MODSEQ; + sync_rec_r->seq1 = range[ctx->modseq_update_idx].seq1; + sync_rec_r->seq2 = range[ctx->modseq_update_idx].seq2; + ctx->modseq_update_idx++; - return 1; ++ return TRUE; + } + } return index_mailbox_sync_next_expunge(ctx, sync_rec_r); } diff --cc src/lib-storage/mail-storage.c index addc92e09f,9dc401ca08..b48cf769c9 --- a/src/lib-storage/mail-storage.c +++ b/src/lib-storage/mail-storage.c @@@ -542,17 -530,12 +542,14 @@@ int mailbox_sync(struct mailbox *box, e struct mailbox_status *status_r) { struct mailbox_sync_context *ctx; - struct mailbox_sync_rec sync_rec; - /* we don't care about mailbox's current state, so we might as well - fix inconsistency state */ - flags |= MAILBOX_SYNC_FLAG_FIX_INCONSISTENT; + if (array_count(&box->search_results) == 0) { + /* we don't care about mailbox's current state, so we might + as well fix inconsistency state */ + flags |= MAILBOX_SYNC_FLAG_FIX_INCONSISTENT; + } ctx = mailbox_sync_init(box, flags); - while (mailbox_sync_next(ctx, &sync_rec)) - ; return mailbox_sync_deinit(&ctx, status_items, status_r); } diff --cc src/pop3/commands.c index 99470eff65,76fc7999ae..a0528f4a22 --- a/src/pop3/commands.c +++ b/src/pop3/commands.c @@@ -505,8 -503,52 +505,51 @@@ struct cmd_uidl_context unsigned int message; struct mail_search_arg search_arg; - struct mail_search_seqset seqset; }; + static void pop3_get_uid(struct cmd_uidl_context *ctx, + struct var_expand_table *tab, string_t *str) + { + char uid_str[MAX_INT_STRLEN]; + const char *uidl; + + if (mail_get_special(ctx->mail, MAIL_FETCH_UIDL_BACKEND, &uidl) == 0 && + *uidl != '\0') { + str_append(str, uidl); + return; + } + + if (reuse_xuidl && + mail_get_first_header(ctx->mail, "X-UIDL", &uidl) > 0) { + str_append(str, uidl); + return; + } + + if ((uidl_keymask & UIDL_UID) != 0) { + i_snprintf(uid_str, sizeof(uid_str), "%u", + ctx->mail->uid); + tab[1].value = uid_str; + } + if ((uidl_keymask & UIDL_MD5) != 0) { + if (mail_get_special(ctx->mail, MAIL_FETCH_HEADER_MD5, + &tab[2].value) < 0 || + *tab[2].value == '\0') { + /* broken */ + i_fatal("UIDL: Header MD5 not found"); + } + } + if ((uidl_keymask & UIDL_FILE_NAME) != 0) { + if (mail_get_special(ctx->mail, + MAIL_FETCH_UIDL_FILE_NAME, + &tab[3].value) < 0 || + *tab[3].value == '\0') { + /* broken */ + i_fatal("UIDL: File name not found"); + } + } + var_expand(str, uidl_format, tab); + } + static bool list_uids_iter(struct client *client, struct cmd_uidl_context *ctx) { static struct var_expand_table static_tab[] = {