cmd-search.c revision b70c95140cf9abef23cb1c303f6f6ce110679e4f
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "common.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ostream.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "str.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "seq-range-array.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-resp-code.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-quote.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-seqset.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-util.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-search-build.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "commands.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-search-args.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainenenum search_return_options {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen SEARCH_RETURN_ESEARCH = 0x0001,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SEARCH_RETURN_MIN = 0x0002,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SEARCH_RETURN_MAX = 0x0004,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SEARCH_RETURN_ALL = 0x0008,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SEARCH_RETURN_COUNT = 0x0010,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SEARCH_RETURN_MODSEQ = 0x0020,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SEARCH_RETURN_SAVE = 0x0040,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SEARCH_RETURN_UPDATE = 0x0080,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SEARCH_RETURN_PARTIAL = 0x0100
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* Options that don't return any seq/uid results */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define SEARCH_RETURN_NORESULTS \
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (SEARCH_RETURN_ESEARCH | SEARCH_RETURN_MODSEQ | SEARCH_RETURN_SAVE | \
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen SEARCH_RETURN_UPDATE)
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct imap_search_context {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct client_command_context *cmd;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen struct mailbox *box;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_transaction_context *trans;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_search_context *search_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail *mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_search_args *sargs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen enum search_return_options return_options;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t partial1, partial2;
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct timeout *to;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ARRAY_TYPE(seq_range) result;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int result_count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint64_t highest_seen_modseq;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct timeval start_time;
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int have_seqsets:1;
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen unsigned int have_modseqs:1;
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen};
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenimap_partial_range_parse(struct imap_search_context *ctx, const char *str)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->partial1 = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->partial2 = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (; *str >= '0' && *str <= '9'; str++)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->partial1 = ctx->partial1 * 10 + *str-'0';
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*str != ':')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (str++; *str >= '0' && *str <= '9'; str++)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->partial2 = ctx->partial2 * 10 + *str-'0';
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return *str == '\0' ? 0 : -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainenstatic bool
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainensearch_parse_return_options(struct imap_search_context *ctx,
2f5954db411ea9d63e831a01dd57211e55448463Timo Sirainen const struct imap_arg *args)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct client_command_context *cmd = ctx->cmd;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *name, *str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen while (args->type != IMAP_ARG_EOL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (args->type != IMAP_ARG_ATOM) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_command_error(cmd,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "SEARCH return options contain non-atoms.");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen name = t_str_ucase(IMAP_ARG_STR_NONULL(args));
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen args++;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (strcmp(name, "MIN") == 0)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen ctx->return_options |= SEARCH_RETURN_MIN;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen else if (strcmp(name, "MAX") == 0)
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen ctx->return_options |= SEARCH_RETURN_MAX;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen else if (strcmp(name, "ALL") == 0)
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainen ctx->return_options |= SEARCH_RETURN_ALL;
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainen else if (strcmp(name, "COUNT") == 0)
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen ctx->return_options |= SEARCH_RETURN_COUNT;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen else if (strcmp(name, "SAVE") == 0)
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen ctx->return_options |= SEARCH_RETURN_SAVE;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen else if (strcmp(name, "UPDATE") == 0)
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen ctx->return_options |= SEARCH_RETURN_UPDATE;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen else if (strcmp(name, "PARTIAL") == 0) {
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen if (ctx->partial1 != 0) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen client_send_command_error(cmd,
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen "PARTIAL can be used only once.");
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->return_options |= SEARCH_RETURN_PARTIAL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (args->type != IMAP_ARG_ATOM) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_command_error(cmd,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "PARTIAL range missing.");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str = IMAP_ARG_STR_NONULL(args);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (imap_partial_range_parse(ctx, str) < 0) {
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen client_send_command_error(cmd,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "PARTIAL range broken.");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen args++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_command_error(cmd,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Unknown SEARCH return option");
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_UPDATE) != 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_search_update_lookup(cmd->client, cmd->tag, &idx) != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_command_error(cmd, "Duplicate search update tag");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_PARTIAL) != 0 &&
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (ctx->return_options & SEARCH_RETURN_ALL) != 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen client_send_command_error(cmd, "PARTIAL conflicts with ALL");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen if (ctx->return_options == 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx->return_options = SEARCH_RETURN_ALL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->return_options |= SEARCH_RETURN_ESEARCH;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void imap_search_args_check(struct imap_search_context *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mail_search_arg *sargs)
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen{
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen for (; sargs != NULL; sargs = sargs->next) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen switch (sargs->type) {
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen case SEARCH_SEQSET:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->have_seqsets = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case SEARCH_MODSEQ:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->have_modseqs = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen case SEARCH_OR:
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case SEARCH_SUB:
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen imap_search_args_check(ctx, sargs->value.subargs);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen default:
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic void imap_search_result_save(struct imap_search_context *ctx)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct client *client = ctx->cmd->client;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct mail_search_result *result;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct imap_search_update *update;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (!array_is_created(&client->search_updates))
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_array_init(&client->search_updates, 32);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else if (array_count(&client->search_updates) >=
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen CLIENT_MAX_SEARCH_UPDATES) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* too many updates */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *str = t_str_new(256);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "* NO [NOUPDATE ");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_quote_append_string(str, ctx->cmd->tag, FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append_c(str, ']');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_line(client, str_c(str));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->return_options &= ~SEARCH_RETURN_UPDATE;
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen result = mailbox_search_result_save(ctx->search_ctx,
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen MAILBOX_SEARCH_RESULT_FLAG_UPDATE |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen update = array_append_space(&client->search_updates);
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen update->tag = i_strdup(ctx->cmd->tag);
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen update->result = result;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen update->return_uids = ctx->cmd->uid;
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen}
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainenstatic void
c3d9da3955043aef88c17b71f2081e894186aa6bTimo Sirainenimap_search_init(struct imap_search_context *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_search_args *sargs)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_search_args_check(ctx, sargs->args);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->have_modseqs) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->return_options |= SEARCH_RETURN_MODSEQ;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_enable(ctx->cmd->client, MAILBOX_FEATURE_CONDSTORE);
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainen }
f776b9a125c59a96de6807e9558942cf7b7ab079Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->box = ctx->cmd->client->mailbox;
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box, 0);
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen ctx->sargs = sargs;
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen ctx->search_ctx = mailbox_search_init(ctx->trans, sargs, NULL);
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainen ctx->mail = mail_alloc(ctx->trans, 0, NULL);
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen (void)gettimeofday(&ctx->start_time, NULL);
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen i_array_init(&ctx->result, 128);
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_UPDATE) != 0)
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen imap_search_result_save(ctx);
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void imap_search_send_result_standard(struct imap_search_context *ctx)
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct seq_range *range;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t seq;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str = t_str_new(1024);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen range = array_get(&ctx->result, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "* SEARCH");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (seq = range[i].seq1; seq <= range[i].seq2; seq++)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, " %u", seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (str_len(str) >= 1024-32) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen o_stream_send(ctx->cmd->client->output,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_data(str), str_len(str));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_truncate(str, 0);
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->highest_seen_modseq != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, " (MODSEQ %llu)",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (unsigned long long)ctx->highest_seen_modseq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "\r\n");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen o_stream_send(ctx->cmd->client->output,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_data(str), str_len(str));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenimap_search_send_partial(struct imap_search_context *ctx, string_t *str)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct seq_range_iter iter;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t n1, n2;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, " PARTIAL (%u:%u ", ctx->partial1, ctx->partial2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen seq_range_array_iter_init(&iter, &ctx->result);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!seq_range_array_iter_nth(&iter, ctx->partial1 - 1, &n1)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* no results (in range) */
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen str_append(str, "NIL)");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen }
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (!seq_range_array_iter_nth(&iter, ctx->partial2 - 1, &n2))
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen n2 = (uint32_t)-1;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* FIXME: we should save the search result for later use */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (n1 > 1)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen seq_range_array_remove_range(&ctx->result, 1, n1 - 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (n2 != (uint32_t)-1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen seq_range_array_remove_range(&ctx->result,
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen n2 + 1, (uint32_t)-1);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen }
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen imap_write_seq_range(str, &ctx->result);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen str_append_c(str, ')');
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen}
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainenstatic void imap_search_send_result(struct imap_search_context *ctx)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen{
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen struct client *client = ctx->cmd->client;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen const struct seq_range *range;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen unsigned int count;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen string_t *str;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if ((ctx->return_options & SEARCH_RETURN_ESEARCH) == 0) {
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen imap_search_send_result_standard(ctx);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen }
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (ctx->return_options ==
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen (SEARCH_RETURN_ESEARCH | SEARCH_RETURN_SAVE)) {
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen /* we only wanted to save the result, don't return
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ESEARCH result. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str = str_new(default_pool, 1024);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "* ESEARCH (TAG ");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_quote_append_string(str, ctx->cmd->tag, FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append_c(str, ')');
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ctx->cmd->uid)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str_append(str, " UID");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen range = array_get(&ctx->result, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (count > 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_MIN) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, " MIN %u", range[0].seq1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_MAX) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, " MAX %u", range[count-1].seq2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_ALL) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, " ALL ");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_write_seq_range(str, &ctx->result);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_PARTIAL) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_search_send_partial(ctx, str);
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_COUNT) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, " COUNT %u", ctx->result_count);
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen if (ctx->highest_seen_modseq != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, " MODSEQ %llu",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (unsigned long long)ctx->highest_seen_modseq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "\r\n");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainenstatic int imap_search_deinit(struct imap_search_context *ctx)
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen{
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen int ret = 0;
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_free(&ctx->mail);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen ret = -1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (ret == 0 && !ctx->cmd->cancel)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen imap_search_send_result(ctx);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen else {
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen /* search failed */
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen array_clear(&ctx->cmd->client->search_saved_uidset);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen }
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen (void)mailbox_transaction_commit(&ctx->trans);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (ctx->to != NULL)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen timeout_remove(&ctx->to);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_free(&ctx->result);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_search_args_deinit(ctx->sargs);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_search_args_unref(&ctx->sargs);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->cmd->context = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen}
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void search_update_mail(struct imap_search_context *ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen uint64_t modseq;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_MODSEQ) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen modseq = mail_get_modseq(ctx->mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->highest_seen_modseq < modseq)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->highest_seen_modseq = modseq;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen seq_range_array_add(&ctx->cmd->client->search_saved_uidset,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen 0, ctx->mail->uid);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen }
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool cmd_search_more(struct client_command_context *cmd)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen struct imap_search_context *ctx = cmd->context;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen enum search_return_options opts = ctx->return_options;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen enum mailbox_sync_flags sync_flags;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen struct timeval end_time;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen const struct seq_range *range;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen unsigned int count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t id, id_min, id_max;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *ok_reply;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen bool tryagain, minmax, lost_data;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (cmd->cancel) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)imap_search_deinit(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen range = array_get(&ctx->result, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (count == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen id_min = (uint32_t)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen id_max = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen id_min = range[0].seq1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen id_max = range[count-1].seq2;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
minmax = (opts & (SEARCH_RETURN_MIN | SEARCH_RETURN_MAX)) != 0 &&
(opts & ~(SEARCH_RETURN_NORESULTS |
SEARCH_RETURN_MIN | SEARCH_RETURN_MAX)) == 0;
while (mailbox_search_next_nonblock(ctx->search_ctx, ctx->mail,
&tryagain) > 0) {
id = cmd->uid ? ctx->mail->uid : ctx->mail->seq;
ctx->result_count++;
if (minmax) {
/* we only care about min/max */
if (id < id_min && (opts & SEARCH_RETURN_MIN) != 0)
id_min = id;
if (id > id_max && (opts & SEARCH_RETURN_MAX) != 0)
id_max = id;
if (id == id_min || id == id_max) {
/* return option updates are delayed until
we know the actual min/max values */
seq_range_array_add(&ctx->result, 0, id);
}
continue;
}
search_update_mail(ctx);
if ((opts & ~(SEARCH_RETURN_NORESULTS |
SEARCH_RETURN_COUNT)) == 0) {
/* we only want to count (and get modseqs) */
continue;
}
seq_range_array_add(&ctx->result, 0, id);
}
if (tryagain)
return FALSE;
if (minmax && array_count(&ctx->result) > 0 &&
(opts & (SEARCH_RETURN_MODSEQ | SEARCH_RETURN_SAVE)) != 0) {
/* handle MIN/MAX modseq/save updates */
if ((opts & SEARCH_RETURN_MIN) != 0) {
i_assert(id_min != (uint32_t)-1);
if (cmd->uid) {
if (!mail_set_uid(ctx->mail, id_min))
i_unreached();
} else {
mail_set_seq(ctx->mail, id_min);
}
search_update_mail(ctx);
}
if ((opts & SEARCH_RETURN_MAX) != 0) {
i_assert(id_max != 0);
if (cmd->uid) {
if (!mail_set_uid(ctx->mail, id_max))
i_unreached();
} else {
mail_set_seq(ctx->mail, id_max);
}
search_update_mail(ctx);
}
}
lost_data = mailbox_search_seen_lost_data(ctx->search_ctx);
if (imap_search_deinit(ctx) < 0) {
client_send_storage_error(cmd,
mailbox_get_storage(cmd->client->mailbox));
return TRUE;
}
if (gettimeofday(&end_time, NULL) < 0)
memset(&end_time, 0, sizeof(end_time));
end_time.tv_sec -= ctx->start_time.tv_sec;
end_time.tv_usec -= ctx->start_time.tv_usec;
if (end_time.tv_usec < 0) {
end_time.tv_sec--;
end_time.tv_usec += 1000000;
}
sync_flags = MAILBOX_SYNC_FLAG_FAST;
if (!cmd->uid || ctx->have_seqsets)
sync_flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES;
ok_reply = t_strdup_printf("OK %sSearch completed (%d.%03d secs).",
lost_data ? "["IMAP_RESP_CODE_EXPUNGEISSUED"] " : "",
(int)end_time.tv_sec, (int)(end_time.tv_usec/1000));
return cmd_sync(cmd, sync_flags, 0, ok_reply);
}
static void cmd_search_more_callback(struct client_command_context *cmd)
{
struct client *client = cmd->client;
bool finished;
o_stream_cork(client->output);
finished = cmd_search_more(cmd);
o_stream_uncork(client->output);
if (!finished)
(void)client_handle_unfinished_cmd(cmd);
else
client_command_free(&cmd);
(void)cmd_sync_delayed(client);
client_continue_pending_input(&client);
}
bool cmd_search(struct client_command_context *cmd)
{
struct client *client = cmd->client;
struct imap_search_context *ctx;
struct mail_search_args *sargs;
const struct imap_arg *args;
int ret, args_count;
const char *charset;
args_count = imap_parser_read_args(cmd->parser, 0, 0, &args);
if (args_count < 1) {
if (args_count == -2)
return FALSE;
client_send_command_error(cmd, args_count < 0 ? NULL :
"Missing SEARCH arguments.");
return TRUE;
}
client->input_lock = NULL;
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(ctx, IMAP_ARG_LIST_ARGS(args)))
return TRUE;
args++;
if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0) {
/* wait if there is another SEARCH SAVE command
running. */
cmd->search_save_result = TRUE;
if (client_handle_search_save_ambiguity(cmd))
return FALSE;
}
} else {
ctx->return_options = SEARCH_RETURN_ALL;
}
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);
else
i_array_init(&client->search_saved_uidset, 128);
}
if (args->type == IMAP_ARG_ATOM &&
strcasecmp(IMAP_ARG_STR_NONULL(args), "CHARSET") == 0) {
/* CHARSET specified */
args++;
if (args->type != IMAP_ARG_ATOM &&
args->type != IMAP_ARG_STRING) {
client_send_command_error(cmd,
"Invalid charset argument.");
return TRUE;
}
charset = IMAP_ARG_STR(args);
args++;
} else {
charset = "UTF-8";
}
ret = imap_search_args_build(cmd, args, charset, &sargs);
if (ret <= 0)
return ret < 0;
imap_search_init(ctx, sargs);
cmd->func = cmd_search_more;
cmd->context = ctx;
if (cmd_search_more(cmd))
return TRUE;
/* we could have moved onto syncing by now */
if (cmd->func == cmd_search_more)
ctx->to = timeout_add(0, cmd_search_more_callback, cmd);
return FALSE;
}