bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 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"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "imap-fetch.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-commands.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-search-args.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-search.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo 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
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic bool
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainensearch_parse_fetch_att(struct imap_search_context *ctx,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct imap_arg *update_args)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *error;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->fetch_pool = pool_alloconly_create("search update fetch", 512);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (imap_fetch_att_list_parse(ctx->cmd->client, ctx->fetch_pool,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen update_args, &ctx->fetch_ctx, &error) < 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_send_command_error(ctx->cmd, t_strconcat(
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen "SEARCH UPDATE fetch-att: ", error, NULL));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pool_unref(&ctx->fetch_pool);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return TRUE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo 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;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct imap_arg *update_args;
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;
b104354c4a829e828c361e4a167bf7106d124174Timo Sirainen else if (strcmp(name, "CONTEXT") == 0) {
b104354c4a829e828c361e4a167bf7106d124174Timo Sirainen /* no-op */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else if (strcmp(name, "UPDATE") == 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_UPDATE) != 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_send_command_error(cmd,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen "SEARCH return options have duplicate UPDATE.");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options |= SEARCH_RETURN_UPDATE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (imap_arg_get_list(args, &update_args)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!search_parse_fetch_att(ctx, update_args))
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen args++;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else if (strcmp(name, "RELEVANCY") == 0)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen ctx->return_options |= SEARCH_RETURN_RELEVANCY;
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 ");
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen imap_append_quoted(str, ctx->cmd->tag);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append_c(str, ']');
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen client_send_line(client, str_c(str));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->return_options &= ~SEARCH_RETURN_UPDATE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_search_context_free(ctx);
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;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen update->fetch_pool = ctx->fetch_pool;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen update->fetch_ctx = ctx->fetch_ctx;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->fetch_pool = NULL;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->fetch_ctx = NULL;
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) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(ctx->cmd->client->output,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo 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) {
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(str, " (MODSEQ %"PRIu64")",
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi ctx->highest_seen_modseq);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, "\r\n");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(ctx->cmd->client->output, 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{
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen struct seq_range *range;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen uint32_t n, diff;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen unsigned int i, count, delete_count;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_printfa(str, " PARTIAL (%u:%u ", ctx->partial1, ctx->partial2);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen ctx->partial1--;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen ctx->partial2--;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen /* we need to be able to handle non-sorted seq ranges (for SORT
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen replies), so do this ourself instead of using seq_range_array_*()
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen functions. */
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen range = array_get_modifiable(&ctx->result, &count);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen /* delete everything up to partial1 */
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen delete_count = 0;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen for (i = n = 0; i < count; i++) {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen diff = range[i].seq2 - range[i].seq1;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (n + diff >= ctx->partial1) {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen range[i].seq1 += ctx->partial1 - n;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen delete_count = i;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen break;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen n += diff + 1;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (i == count) {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen /* partial1 points past the result */
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen array_clear(&ctx->result);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen } else {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen /* delete everything after partial2 */
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen for (n = ctx->partial1; i < count; i++) {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen diff = range[i].seq2 - range[i].seq1;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (n + diff >= ctx->partial2) {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen range[i].seq2 = range[i].seq1 + (ctx->partial2 - n);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen array_delete(&ctx->result, i + 1, count-(i+1));
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen break;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen n += diff + 1;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen array_delete(&ctx->result, 0, delete_count);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
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
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainenstatic void
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainenimap_search_send_relevancy(struct imap_search_context *ctx, string_t *dest)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen{
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen const float *scores;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen unsigned int i, count;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen float diff, imap_score;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen scores = array_get(&ctx->relevancy_scores, &count);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (count == 0)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen return;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen /* we'll need to convert float scores to numbers 1..100
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen FIXME: would be a good idea to try to detect non-linear score
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen mappings and convert them better.. */
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen diff = ctx->max_relevancy - ctx->min_relevancy;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (diff == 0)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen diff = 1.0;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen for (i = 0; i < count; i++) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (i > 0)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen str_append_c(dest, ' ');
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen imap_score = (scores[i] - ctx->min_relevancy) / diff * 100.0;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (imap_score < 1)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen str_append(dest, "1");
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen else
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen str_printfa(dest, "%u", (unsigned int)imap_score);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen}
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo 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 ");
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen imap_append_string(str, ctx->cmd->tag);
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 }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if ((ctx->return_options & SEARCH_RETURN_RELEVANCY) != 0) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen str_append(str, " RELEVANCY (");
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen imap_search_send_relevancy(ctx, str);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen str_append_c(str, ')');
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo 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) {
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(str, " MODSEQ %"PRIu64,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi ctx->highest_seen_modseq);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append(str, "\r\n");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
31ed209b28f30bcc2ce20de07aaa43d432126e24Timo Sirainen str_free(&str);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainenstatic void
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainensearch_update_mail(struct imap_search_context *ctx, struct mail *mail)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen uint64_t modseq;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_MODSEQ) != 0) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen modseq = mail_get_modseq(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,
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen mail->uid);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if ((ctx->return_options & SEARCH_RETURN_RELEVANCY) != 0) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen const char *str;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen float score;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_SEARCH_RELEVANCY, &str) < 0)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen score = 0;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen else
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen score = strtod(str, NULL);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen array_append(&ctx->relevancy_scores, &score, 1);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (ctx->min_relevancy > score)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen ctx->min_relevancy = score;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (ctx->max_relevancy < score)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen ctx->max_relevancy = score;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo 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;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct mail *mail;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enum mailbox_sync_flags sync_flags;
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;
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;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen while (mailbox_search_next_nonblock(ctx->search_ctx,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen &mail, &tryagain)) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen id = cmd->uid ? mail->uid : 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
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen search_update_mail(ctx, mail);
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 */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mail = mail_alloc(ctx->trans, 0, NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((opts & SEARCH_RETURN_MIN) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(id_min != 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (cmd->uid) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen if (!mail_set_uid(mail, id_min))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_unreached();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mail_set_seq(mail, id_min);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen search_update_mail(ctx, mail);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((opts & SEARCH_RETURN_MAX) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(id_max != 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (cmd->uid) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen if (!mail_set_uid(mail, id_max))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_unreached();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mail_set_seq(mail, id_max);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen search_update_mail(ctx, mail);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mail_free(&mail);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen lost_data = mailbox_search_seen_lost_data(ctx->search_ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (imap_search_deinit(ctx) < 0) {
08837f59c1466ec0f533f120b167f2a3e87da738Timo Sirainen client_send_box_error(cmd, cmd->client->mailbox);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
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;
115cf0320f679e4e63db25e7f44f47977b8338deTimo Sirainen ok_reply = t_strdup_printf("OK %s%s completed",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen lost_data ? "["IMAP_RESP_CODE_EXPUNGEISSUED"] " : "",
115cf0320f679e4e63db25e7f44f47977b8338deTimo Sirainen !ctx->sorting ? "Search" : "Sort");
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);
b7c841fd6dc508d87db8b1b64ea1a8f4cb0b8971Timo Sirainen finished = command_exec(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);
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen 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
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!search_parse_return_options(ctx, list_args)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_search_context_free(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* wait if there is another SEARCH SAVE command running. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (client_handle_search_save_ambiguity(cmd)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_search_context_free(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
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);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen cmd->search_save_result = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen *_args = args + 2;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 1;
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
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;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen (void)client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
3a508ab3b10ff08889f3046a6bbf8553b55e3d44Timo Sirainen ctx->box = cmd->client->mailbox;
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi ctx->trans = mailbox_transaction_begin(ctx->box, 0,
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi imap_client_command_get_reason(cmd));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->sargs = sargs;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx->search_ctx =
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mailbox_search_init(ctx->trans, sargs, sort_program, 0, NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->sorting = sort_program != 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);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_assert(ctx->fetch_ctx == NULL);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if ((ctx->return_options & SEARCH_RETURN_RELEVANCY) != 0)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i_array_init(&ctx->relevancy_scores, 128);
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 */
5caf685b62a30b1f935b80a3f9f1bdcefb63a38cTimo Sirainen if (cmd->func == cmd_search_more) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->to = timeout_add(0, cmd_search_more_callback, cmd);
5caf685b62a30b1f935b80a3f9f1bdcefb63a38cTimo Sirainen cmd->state = CLIENT_COMMAND_STATE_WAIT_EXTERNAL;
5caf685b62a30b1f935b80a3f9f1bdcefb63a38cTimo Sirainen }
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 if (mailbox_search_deinit(&ctx->search_ctx) < 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen /* Send the result also after failing. It might have something useful,
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen even though it didn't fully succeed. The client should be able to
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen realize that there was some failure because NO is returned. */
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen if (!ctx->cmd->cancel &&
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen (ret == 0 || array_count(&ctx->result) > 0))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen imap_search_send_result(ctx);
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen if (ret < 0 || ctx->cmd->cancel) {
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
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&ctx->to);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (array_is_created(&ctx->relevancy_scores))
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen array_free(&ctx->relevancy_scores);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen array_free(&ctx->result);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_search_args_deinit(ctx->sargs);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_search_args_unref(&ctx->sargs);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_search_context_free(ctx);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->cmd->context = NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return ret;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid imap_search_context_free(struct imap_search_context *ctx)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->fetch_ctx != NULL) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_fetch_free(&ctx->fetch_ctx);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pool_unref(&ctx->fetch_pool);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid imap_search_update_free(struct imap_search_update *update)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (update->fetch_ctx != NULL) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_fetch_free(&update->fetch_ctx);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pool_unref(&update->fetch_pool);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mailbox_search_result_free(&update->result);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_free(update->tag);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}