Mercurial > dovecot > core-2.2
changeset 7650:edd180c77b99 HEAD
CONTEXT=SEARCH: Implemented SEARCH PARTIAL (non-optimized).
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 07 Jun 2008 00:22:17 +0300 |
parents | efbfe9344c14 |
children | 6fb9a58ad8c5 |
files | src/imap/cmd-search.c |
diffstat | 1 files changed, 96 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/src/imap/cmd-search.c Fri Jun 06 23:54:30 2008 +0300 +++ b/src/imap/cmd-search.c Sat Jun 07 00:22:17 2008 +0300 @@ -7,19 +7,22 @@ #include "commands.h" #include "mail-search-build.h" #include "imap-quote.h" +#include "imap-seqset.h" #include "imap-util.h" #include "imap-search.h" enum search_return_options { - SEARCH_RETURN_ESEARCH = 0x01, - SEARCH_RETURN_MIN = 0x02, - SEARCH_RETURN_MAX = 0x04, - SEARCH_RETURN_ALL = 0x08, - SEARCH_RETURN_COUNT = 0x10, - SEARCH_RETURN_MODSEQ = 0x20, - SEARCH_RETURN_SAVE = 0x40, - SEARCH_RETURN_UPDATE = 0x80 -#define SEARCH_RETURN_EXTRAS \ + SEARCH_RETURN_ESEARCH = 0x0001, + SEARCH_RETURN_MIN = 0x0002, + SEARCH_RETURN_MAX = 0x0004, + SEARCH_RETURN_ALL = 0x0008, + SEARCH_RETURN_COUNT = 0x0010, + SEARCH_RETURN_MODSEQ = 0x0020, + SEARCH_RETURN_SAVE = 0x0040, + SEARCH_RETURN_UPDATE = 0x0080, + SEARCH_RETURN_PARTIAL = 0x0100 +/* Options that don't return any seq/uid results */ +#define SEARCH_RETURN_NORESULTS \ (SEARCH_RETURN_ESEARCH | SEARCH_RETURN_MODSEQ | SEARCH_RETURN_SAVE | \ SEARCH_RETURN_UPDATE) }; @@ -30,8 +33,10 @@ struct mailbox_transaction_context *trans; struct mail_search_context *search_ctx; struct mail *mail; + struct mail_search_args *sargs; enum search_return_options return_options; + uint32_t seq1, seq2; struct timeout *to; ARRAY_TYPE(seq_range) result; @@ -42,13 +47,12 @@ }; static bool -search_parse_return_options(struct client_command_context *cmd, - const struct imap_arg *args, - enum search_return_options *return_options_r) +search_parse_return_options(struct imap_search_context *ctx, + const struct imap_arg *args) { - const char *name; - - *return_options_r = 0; + struct client_command_context *cmd = ctx->cmd; + const char *name, *str; + unsigned int idx; while (args->type != IMAP_ARG_EOL) { if (args->type != IMAP_ARG_ATOM) { @@ -56,30 +60,57 @@ "SEARCH return options contain non-atoms."); return FALSE; } - name = t_str_ucase(IMAP_ARG_STR(args)); + name = t_str_ucase(IMAP_ARG_STR_NONULL(args)); args++; if (strcmp(name, "MIN") == 0) - *return_options_r |= SEARCH_RETURN_MIN; + ctx->return_options |= SEARCH_RETURN_MIN; else if (strcmp(name, "MAX") == 0) - *return_options_r |= SEARCH_RETURN_MAX; + ctx->return_options |= SEARCH_RETURN_MAX; else if (strcmp(name, "ALL") == 0) - *return_options_r |= SEARCH_RETURN_ALL; + ctx->return_options |= SEARCH_RETURN_ALL; else if (strcmp(name, "COUNT") == 0) - *return_options_r |= SEARCH_RETURN_COUNT; + ctx->return_options |= SEARCH_RETURN_COUNT; else if (strcmp(name, "SAVE") == 0) - *return_options_r |= SEARCH_RETURN_SAVE; + ctx->return_options |= SEARCH_RETURN_SAVE; else if (strcmp(name, "UPDATE") == 0) - *return_options_r |= SEARCH_RETURN_UPDATE; - else { + ctx->return_options |= SEARCH_RETURN_UPDATE; + else if (strcmp(name, "PARTIAL") == 0) { + ctx->return_options |= SEARCH_RETURN_PARTIAL; + if (args->type != IMAP_ARG_ATOM) { + client_send_command_error(cmd, + "SEARCH PARTIAL range missing."); + return FALSE; + } + str = IMAP_ARG_STR_NONULL(args); + if (imap_seq_range_parse(str, &ctx->seq1, + &ctx->seq2) < 0) { + client_send_command_error(cmd, + "SEARCH PARTIAL range broken."); + return FALSE; + } + args++; + } else { client_send_command_error(cmd, "Unknown SEARCH return option"); return FALSE; } } - if (*return_options_r == 0) - *return_options_r = SEARCH_RETURN_ALL; - *return_options_r |= SEARCH_RETURN_ESEARCH; + if ((ctx->return_options & SEARCH_RETURN_UPDATE) != 0 && + client_search_update_lookup(cmd->client, cmd->tag, &idx) != NULL) { + client_send_command_error(cmd, "Duplicate search update tag"); + return FALSE; + } + if ((ctx->return_options & SEARCH_RETURN_PARTIAL) != 0 && + (ctx->return_options & SEARCH_RETURN_ALL) != 0) { + client_send_command_error(cmd, + "SEARCH PARTIAL conflicts with ALL"); + return FALSE; + } + + if (ctx->return_options == 0) + ctx->return_options = SEARCH_RETURN_ALL; + ctx->return_options |= SEARCH_RETURN_ESEARCH; return TRUE; } @@ -179,6 +210,33 @@ str_data(str), str_len(str)); } +static void +imap_search_send_partial(struct imap_search_context *ctx, string_t *str) +{ + struct seq_range_iter iter; + uint32_t seq1, seq2; + + str_printfa(str, " PARTIAL (%u:%u ", ctx->seq1, ctx->seq2); + seq_range_array_iter_init(&iter, &ctx->result); + if (!seq_range_array_iter_nth(&iter, ctx->seq1 - 1, &seq1)) { + /* no results (in range) */ + str_append(str, "NIL)"); + return; + } + if (!seq_range_array_iter_nth(&iter, ctx->seq2 - 1, &seq2)) + seq2 = (uint32_t)-1; + + /* FIXME: we should save the search result for later use */ + if (seq1 > 1) + seq_range_array_remove_range(&ctx->result, 1, seq1 - 1); + if (seq2 != (uint32_t)-1) { + seq_range_array_remove_range(&ctx->result, + seq2 + 1, (uint32_t)-1); + } + imap_write_seq_range(str, &ctx->result); + str_append_c(str, ')'); +} + static void imap_search_send_result(struct imap_search_context *ctx) { struct client *client = ctx->cmd->client; @@ -218,6 +276,9 @@ } } + if ((ctx->return_options & SEARCH_RETURN_PARTIAL) != 0) + imap_search_send_partial(ctx, str); + if ((ctx->return_options & SEARCH_RETURN_COUNT) != 0) str_printfa(str, " COUNT %u", ctx->result_count); if (ctx->highest_seen_modseq != 0) { @@ -296,7 +357,7 @@ } minmax = (opts & (SEARCH_RETURN_MIN | SEARCH_RETURN_MAX)) != 0 && - (opts & ~(SEARCH_RETURN_EXTRAS | + (opts & ~(SEARCH_RETURN_NORESULTS | SEARCH_RETURN_MIN | SEARCH_RETURN_MAX)) == 0; while (mailbox_search_next_nonblock(ctx->search_ctx, ctx->mail, &tryagain) > 0) { @@ -318,7 +379,7 @@ } search_update_mail(ctx); - if ((opts & ~(SEARCH_RETURN_EXTRAS | + if ((opts & ~(SEARCH_RETURN_NORESULTS | SEARCH_RETURN_COUNT)) == 0) { /* we only want to count (and get modseqs) */ continue; @@ -398,9 +459,7 @@ struct imap_search_context *ctx; struct mail_search_args *sargs; const struct imap_arg *args; - enum search_return_options return_options; int ret, args_count; - unsigned int idx; const char *charset; args_count = imap_parser_read_args(cmd->parser, 0, 0, &args); @@ -417,15 +476,17 @@ if (!client_verify_open_mailbox(cmd)) return TRUE; + ctx = p_new(cmd->pool, struct imap_search_context, 1); + ctx->cmd = cmd; + if (args->type == IMAP_ARG_ATOM && args[1].type == IMAP_ARG_LIST && strcasecmp(IMAP_ARG_STR_NONULL(args), "RETURN") == 0) { args++; - if (!search_parse_return_options(cmd, IMAP_ARG_LIST_ARGS(args), - &return_options)) + if (!search_parse_return_options(ctx, IMAP_ARG_LIST_ARGS(args))) return TRUE; args++; - if ((return_options & SEARCH_RETURN_SAVE) != 0) { + if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0) { /* wait if there is another SEARCH SAVE command running. */ cmd->search_save_result = TRUE; @@ -433,10 +494,10 @@ return FALSE; } } else { - return_options = SEARCH_RETURN_ALL; + ctx->return_options = SEARCH_RETURN_ALL; } - if ((return_options & SEARCH_RETURN_SAVE) != 0) { + if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0) { /* make sure the search result gets cleared if SEARCH fails */ if (array_is_created(&client->search_saved_uidset)) array_clear(&client->search_saved_uidset); @@ -444,16 +505,6 @@ i_array_init(&client->search_saved_uidset, 128); } - if ((return_options & SEARCH_RETURN_UPDATE) != 0 && - client_search_update_lookup(client, cmd->tag, &idx) != NULL) { - client_send_command_error(cmd, "Duplicate search update tag"); - return TRUE; - } - - ctx = p_new(cmd->pool, struct imap_search_context, 1); - ctx->cmd = cmd; - ctx->return_options = return_options; - if (args->type == IMAP_ARG_ATOM && strcasecmp(IMAP_ARG_STR_NONULL(args), "CHARSET") == 0) { /* CHARSET specified */