imap-search.c revision c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-common.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "ostream.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "str.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "seq-range-array.h"
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen#include "time-util.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-resp-code.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-quote.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-seqset.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-util.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "mail-search-build.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-commands.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-search-args.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-search.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic int imap_search_deinit(struct imap_search_context *ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic int
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenimap_partial_range_parse(struct imap_search_context *ctx, const char *str)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->partial1 = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->partial2 = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (; *str >= '0' && *str <= '9'; str++)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->partial1 = ctx->partial1 * 10 + *str-'0';
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*str != ':' || ctx->partial1 == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (str++; *str >= '0' && *str <= '9'; str++)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->partial2 = ctx->partial2 * 10 + *str-'0';
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*str != '\0' || ctx->partial2 == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->partial1 > ctx->partial2) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen uint32_t temp = ctx->partial2;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->partial2 = ctx->partial1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->partial1 = temp;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic bool
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainensearch_parse_return_options(struct imap_search_context *ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct imap_arg *args)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct client_command_context *cmd = ctx->cmd;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *name, *str;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen unsigned int idx;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen while (!IMAP_ARG_IS_EOL(args)) {
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen if (!imap_arg_get_atom(args, &name)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_command_error(cmd,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "SEARCH return options contain non-atoms.");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen name = t_str_ucase(name);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen args++;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (strcmp(name, "MIN") == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_MIN;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else if (strcmp(name, "MAX") == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_MAX;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else if (strcmp(name, "ALL") == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_ALL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else if (strcmp(name, "COUNT") == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_COUNT;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else if (strcmp(name, "SAVE") == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_SAVE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else if (strcmp(name, "UPDATE") == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_UPDATE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else if (strcmp(name, "PARTIAL") == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->partial1 != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_command_error(cmd,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "PARTIAL can be used only once.");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_PARTIAL;
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen if (!imap_arg_get_atom(args, &str)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_command_error(cmd,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "PARTIAL range missing.");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (imap_partial_range_parse(ctx, str) < 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_command_error(cmd,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "PARTIAL range broken.");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen args++;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_command_error(cmd,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "Unknown SEARCH return option");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_UPDATE) != 0 &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_search_update_lookup(cmd->client, cmd->tag, &idx) != NULL) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_command_error(cmd, "Duplicate search update tag");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_PARTIAL) != 0 &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (ctx->return_options & SEARCH_RETURN_ALL) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_command_error(cmd, "PARTIAL conflicts with ALL");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->return_options == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options = SEARCH_RETURN_ALL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_ESEARCH;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void imap_search_args_check(struct imap_search_context *ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct mail_search_arg *sargs)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (; sargs != NULL; sargs = sargs->next) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen switch (sargs->type) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case SEARCH_SEQSET:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->have_seqsets = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case SEARCH_MODSEQ:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->have_modseqs = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case SEARCH_OR:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case SEARCH_SUB:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_search_args_check(ctx, sargs->value.subargs);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen default:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void imap_search_result_save(struct imap_search_context *ctx)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct client *client = ctx->cmd->client;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mail_search_result *result;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct imap_search_update *update;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!array_is_created(&client->search_updates))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_array_init(&client->search_updates, 32);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else if (array_count(&client->search_updates) >=
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen CLIENT_MAX_SEARCH_UPDATES) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* too many updates */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen string_t *str = t_str_new(256);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, "* NO [NOUPDATE ");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_quote_append_string(str, ctx->cmd->tag, FALSE);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append_c(str, ']');
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_line(client, str_c(str));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options &= ~SEARCH_RETURN_UPDATE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen result = mailbox_search_result_save(ctx->search_ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen MAILBOX_SEARCH_RESULT_FLAG_UPDATE |
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen update = array_append_space(&client->search_updates);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen update->tag = i_strdup(ctx->cmd->tag);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen update->result = result;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen update->return_uids = ctx->cmd->uid;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void imap_search_send_result_standard(struct imap_search_context *ctx)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct seq_range *range;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen string_t *str;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen uint32_t seq;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str = t_str_new(1024);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, ctx->sorting ? "* SORT" : "* SEARCH");
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&ctx->result, range) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen for (seq = range->seq1; seq <= range->seq2; seq++)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_printfa(str, " %u", seq);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (str_len(str) >= 1024-32) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen o_stream_send(ctx->cmd->client->output,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_data(str), str_len(str));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_truncate(str, 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->highest_seen_modseq != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_printfa(str, " (MODSEQ %llu)",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (unsigned long long)ctx->highest_seen_modseq);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, "\r\n");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen o_stream_send(ctx->cmd->client->output,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_data(str), str_len(str));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenimap_search_send_partial(struct imap_search_context *ctx, string_t *str)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct seq_range *range;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen uint32_t n, diff;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen unsigned int i, count, delete_count;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_printfa(str, " PARTIAL (%u:%u ", ctx->partial1, ctx->partial2);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->partial1--;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->partial2--;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we need to be able to handle non-sorted seq ranges, so do this
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ourself instead of using seq_range_array_*() functions. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range = array_get_modifiable(&ctx->result, &count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen delete_count = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (i = n = 0; i < count; i++) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen diff = range[i].seq2 - range[i].seq1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (n + diff >= ctx->partial1) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range[i].seq1 += ctx->partial1 - n;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen delete_count = i;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen n += diff + 1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (n = ctx->partial1; i < count; i++) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen diff = range[i].seq2 - range[i].seq1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (n + diff >= ctx->partial2) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range[i].seq2 = range[i].seq1 + (ctx->partial2 - n);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen array_delete(&ctx->result, i + 1, count-(i+1));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen n += diff + 1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen array_delete(&ctx->result, 0, delete_count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (array_count(&ctx->result) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* no results (in range) */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, "NIL");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_write_seq_range(str, &ctx->result);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append_c(str, ')');
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void imap_search_send_result(struct imap_search_context *ctx)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct client *client = ctx->cmd->client;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct seq_range *range;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen unsigned int count;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen string_t *str;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_ESEARCH) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_search_send_result_standard(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->return_options ==
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (SEARCH_RETURN_ESEARCH | SEARCH_RETURN_SAVE)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we only wanted to save the result, don't return
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ESEARCH result. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str = str_new(default_pool, 1024);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, "* ESEARCH (TAG ");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_quote_append_string(str, ctx->cmd->tag, FALSE);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append_c(str, ')');
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->cmd->uid)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, " UID");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range = array_get(&ctx->result, &count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (count > 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_MIN) != 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_printfa(str, " MIN %u", range[0].seq1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_MAX) != 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_printfa(str, " MAX %u", range[count-1].seq2);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_ALL) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, " ALL ");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_write_seq_range(str, &ctx->result);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_PARTIAL) != 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_search_send_partial(ctx, str);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_COUNT) != 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_printfa(str, " COUNT %u", ctx->result_count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->highest_seen_modseq != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_printfa(str, " MODSEQ %llu",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (unsigned long long)ctx->highest_seen_modseq);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, "\r\n");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void search_update_mail(struct imap_search_context *ctx)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen uint64_t modseq;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_MODSEQ) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen modseq = mail_get_modseq(ctx->mail);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->highest_seen_modseq < modseq)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->highest_seen_modseq = modseq;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen seq_range_array_add(&ctx->cmd->client->search_saved_uidset,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen 0, ctx->mail->uid);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void search_add_result_id(struct imap_search_context *ctx, uint32_t id)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct seq_range *range;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen unsigned int count;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* only append the data. this is especially important when we're
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen returning a sort result. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range = array_get_modifiable(&ctx->result, &count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (count > 0 && id == range[count-1].seq2 + 1) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range[count-1].seq2++;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range = array_append_space(&ctx->result);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range->seq1 = range->seq2 = id;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic bool cmd_search_more(struct client_command_context *cmd)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct imap_search_context *ctx = cmd->context;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enum search_return_options opts = ctx->return_options;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enum mailbox_sync_flags sync_flags;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct timeval end_time;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct seq_range *range;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen unsigned int count;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen uint32_t id, id_min, id_max;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *ok_reply;
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen int time_msecs;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen bool tryagain, minmax, lost_data;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (cmd->cancel) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (void)imap_search_deinit(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen range = array_get(&ctx->result, &count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (count == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen id_min = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen id_max = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen id_min = range[0].seq1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen id_max = range[count-1].seq2;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen minmax = (opts & (SEARCH_RETURN_MIN | SEARCH_RETURN_MAX)) != 0 &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (opts & ~(SEARCH_RETURN_NORESULTS |
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen SEARCH_RETURN_MIN | SEARCH_RETURN_MAX)) == 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen while (mailbox_search_next_nonblock(ctx->search_ctx, ctx->mail,
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen &tryagain)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen id = cmd->uid ? ctx->mail->uid : ctx->mail->seq;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->result_count++;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (minmax) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we only care about min/max */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (id_min == 0 && (opts & SEARCH_RETURN_MIN) != 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen id_min = id;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((opts & SEARCH_RETURN_MAX) != 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen id_max = id;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (id == id_min || id == id_max) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* return option updates are delayed until
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen we know the actual min/max values */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen search_add_result_id(ctx, id);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen continue;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen search_update_mail(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((opts & ~(SEARCH_RETURN_NORESULTS |
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen SEARCH_RETURN_COUNT)) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we only want to count (and get modseqs) */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen continue;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen search_add_result_id(ctx, id);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (tryagain)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (minmax && array_count(&ctx->result) > 0 &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (opts & (SEARCH_RETURN_MODSEQ | SEARCH_RETURN_SAVE)) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* handle MIN/MAX modseq/save updates */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((opts & SEARCH_RETURN_MIN) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(id_min != 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (cmd->uid) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!mail_set_uid(ctx->mail, id_min))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_unreached();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_set_seq(ctx->mail, id_min);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen search_update_mail(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((opts & SEARCH_RETURN_MAX) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(id_max != 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (cmd->uid) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!mail_set_uid(ctx->mail, id_max))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_unreached();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_set_seq(ctx->mail, id_max);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen search_update_mail(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen lost_data = mailbox_search_seen_lost_data(ctx->search_ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (imap_search_deinit(ctx) < 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_storage_error(cmd,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mailbox_get_storage(cmd->client->mailbox));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (gettimeofday(&end_time, NULL) < 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen memset(&end_time, 0, sizeof(end_time));
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen time_msecs = timeval_diff_msecs(&end_time, &ctx->start_time);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen sync_flags = MAILBOX_SYNC_FLAG_FAST;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!cmd->uid || ctx->have_seqsets)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen sync_flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ok_reply = t_strdup_printf("OK %s%s completed (%d.%03d secs).",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen lost_data ? "["IMAP_RESP_CODE_EXPUNGEISSUED"] " : "",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen !ctx->sorting ? "Search" : "Sort",
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen time_msecs/1000, time_msecs%1000);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return cmd_sync(cmd, sync_flags, 0, ok_reply);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void cmd_search_more_callback(struct client_command_context *cmd)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct client *client = cmd->client;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen bool finished;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen o_stream_cork(client->output);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen finished = cmd_search_more(cmd);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen o_stream_uncork(client->output);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!finished)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (void)client_handle_unfinished_cmd(cmd);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_command_free(&cmd);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (void)cmd_sync_delayed(client);
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen if (client->disconnected)
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen client_destroy(client, NULL);
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen else
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen client_continue_pending_input(client);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenint cmd_search_parse_return_if_found(struct imap_search_context *ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct imap_arg **_args)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen const struct imap_arg *list_args, *args = *_args;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct client_command_context *cmd = ctx->cmd;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen if (!imap_arg_atom_equals(&args[0], "RETURN") ||
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen !imap_arg_get_list(&args[1], &list_args)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options = SEARCH_RETURN_ALL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen if (!search_parse_return_options(ctx, list_args))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* wait if there is another SEARCH SAVE command running. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen cmd->search_save_result = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (client_handle_search_save_ambiguity(cmd))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* make sure the search result gets cleared if SEARCH fails */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (array_is_created(&cmd->client->search_saved_uidset))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen array_clear(&cmd->client->search_saved_uidset);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_array_init(&cmd->client->search_saved_uidset, 128);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen *_args = args + 2;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void wanted_fields_get(struct mailbox *box,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const enum mail_sort_type *sort_program,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enum mail_fetch_field *wanted_fields_r,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mailbox_header_lookup_ctx **headers_ctx_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *headers[2];
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *wanted_fields_r = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *headers_ctx_r = NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (sort_program == NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen headers[0] = headers[1] = NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen switch (sort_program[0] & MAIL_SORT_MASK) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case MAIL_SORT_ARRIVAL:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *wanted_fields_r = MAIL_FETCH_RECEIVED_DATE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case MAIL_SORT_CC:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen headers[0] = "Cc";
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case MAIL_SORT_DATE:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *wanted_fields_r = MAIL_FETCH_DATE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case MAIL_SORT_FROM:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen headers[0] = "From";
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case MAIL_SORT_SIZE:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *wanted_fields_r = MAIL_FETCH_VIRTUAL_SIZE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case MAIL_SORT_SUBJECT:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen headers[0] = "Subject";
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case MAIL_SORT_TO:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen headers[0] = "To";
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (headers[0] != NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *headers_ctx_r = mailbox_header_lookup_init(box, headers);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenbool imap_search_start(struct imap_search_context *ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mail_search_args *sargs,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const enum mail_sort_type *sort_program)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct client_command_context *cmd = ctx->cmd;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enum mail_fetch_field wanted_fields;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_search_args_check(ctx, sargs->args);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->have_modseqs) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_MODSEQ;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
3a508ab3b10ff08889f3046a6bbf8553b55e3d44Timo Sirainen ctx->box = cmd->client->mailbox;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen wanted_fields_get(ctx->box, sort_program,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen &wanted_fields, &wanted_headers);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box, 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->sargs = sargs;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->search_ctx = mailbox_search_init(ctx->trans, sargs, sort_program);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->mail = mail_alloc(ctx->trans, wanted_fields, wanted_headers);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->sorting = sort_program != NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (void)gettimeofday(&ctx->start_time, NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_array_init(&ctx->result, 128);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_UPDATE) != 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_search_result_save(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen cmd->func = cmd_search_more;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen cmd->context = ctx;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (cmd_search_more(cmd))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we may have moved onto syncing by now */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (cmd->func == cmd_search_more)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->to = timeout_add(0, cmd_search_more_callback, cmd);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic int imap_search_deinit(struct imap_search_context *ctx)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen int ret = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_free(&ctx->mail);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ret == 0 && !ctx->cmd->cancel)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_search_send_result(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* search failed */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen array_clear(&ctx->cmd->client->search_saved_uidset);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (void)mailbox_transaction_commit(&ctx->trans);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->to != NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen timeout_remove(&ctx->to);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen array_free(&ctx->result);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_search_args_deinit(ctx->sargs);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_search_args_unref(&ctx->sargs);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->cmd->context = NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return ret;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}