cmd-search.c revision 002e5f30f206552059cb087f77c715bbdcbf5ffe
1N/A/* Copyright (C) 2002 Timo Sirainen */
1N/A
1N/A#include "common.h"
1N/A#include "ostream.h"
1N/A#include "str.h"
1N/A#include "commands.h"
1N/A#include "imap-search.h"
1N/A
1N/A#define OUTBUF_SIZE 65536
1N/A
1N/Astruct imap_search_context {
1N/A struct mailbox_transaction_context *trans;
1N/A struct mail_search_context *search_ctx;
1N/A struct mail *mail;
1N/A
1N/A struct timeout *to;
1N/A string_t *output_buf;
1N/A
1N/A unsigned int output_sent:1;
1N/A};
1N/A
1N/Astatic struct imap_search_context *
1N/Aimap_search_init(struct client_command_context *cmd, const char *charset,
1N/A struct mail_search_arg *sargs)
1N/A{
1N/A struct imap_search_context *ctx;
1N/A
1N/A ctx = p_new(cmd->pool, struct imap_search_context, 1);
1N/A ctx->trans = mailbox_transaction_begin(cmd->client->mailbox, 0);
1N/A ctx->search_ctx = mailbox_search_init(ctx->trans, charset, sargs, NULL);
1N/A ctx->mail = mail_alloc(ctx->trans, 0, NULL);
1N/A
1N/A ctx->output_buf = str_new(default_pool, OUTBUF_SIZE);
1N/A str_append(ctx->output_buf, "* SEARCH");
1N/A return ctx;
1N/A}
1N/A
1N/Astatic int imap_search_deinit(struct client_command_context *cmd,
1N/A struct imap_search_context *ctx)
1N/A{
1N/A int ret;
1N/A
1N/A mail_free(&ctx->mail);
1N/A ret = mailbox_search_deinit(&ctx->search_ctx);
1N/A
1N/A if (mailbox_transaction_commit(&ctx->trans, 0) < 0)
1N/A ret = -1;
1N/A
1N/A if (ctx->output_sent || (ret == 0 && !cmd->cancel)) {
1N/A str_append(ctx->output_buf, "\r\n");
1N/A o_stream_send(cmd->client->output,
1N/A str_data(ctx->output_buf),
1N/A str_len(ctx->output_buf));
1N/A }
1N/A if (ctx->to != NULL)
1N/A timeout_remove(&ctx->to);
1N/A str_free(&ctx->output_buf);
1N/A
1N/A cmd->context = NULL;
1N/A return ret;
1N/A}
1N/A
1N/Astatic bool cmd_search_more(struct client_command_context *cmd)
1N/A{
2N/A struct imap_search_context *ctx = cmd->context;
2N/A bool tryagain;
2N/A int ret;
2N/A
1N/A if (cmd->cancel) {
1N/A (void)imap_search_deinit(cmd, ctx);
1N/A return TRUE;
1N/A }
1N/A
1N/A while ((ret = mailbox_search_next_nonblock(ctx->search_ctx, ctx->mail,
1N/A &tryagain)) > 0) {
1N/A if (str_len(ctx->output_buf) >= OUTBUF_SIZE - MAX_INT_STRLEN) {
1N/A /* flush. this also causes us to lock the output. */
1N/A cmd->client->output_lock = cmd;
1N/A o_stream_send(cmd->client->output,
1N/A str_data(ctx->output_buf),
1N/A str_len(ctx->output_buf));
1N/A str_truncate(ctx->output_buf, 0);
1N/A ctx->output_sent = TRUE;
1N/A }
1N/A
1N/A str_printfa(ctx->output_buf, " %u",
1N/A cmd->uid ? ctx->mail->uid : ctx->mail->seq);
1N/A }
1N/A if (tryagain)
1N/A return FALSE;
1N/A
1N/A if (imap_search_deinit(cmd, ctx) < 0)
1N/A ret = -1;
1N/A
1N/A if (ret < 0) {
1N/A client_send_storage_error(cmd,
1N/A mailbox_get_storage(cmd->client->mailbox));
1N/A return TRUE;
1N/A } else {
1N/A return cmd_sync(cmd, MAILBOX_SYNC_FLAG_FAST |
1N/A (cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES),
1N/A 0, "OK Search completed.");
1N/A }
1N/A}
1N/A
1N/Astatic void cmd_search_more_callback(struct client_command_context *cmd)
1N/A{
1N/A struct client *client = cmd->client;
1N/A
1N/A if (cmd_search_more(cmd)) {
1N/A client_command_free(cmd);
1N/A client_continue_pending_input(client);
1N/A } else {
1N/A if (cmd->output_pending)
1N/A o_stream_set_flush_pending(client->output, TRUE);
1N/A }
1N/A}
1N/A
1N/Abool cmd_search(struct client_command_context *cmd)
1N/A{
1N/A struct imap_search_context *ctx;
1N/A struct mail_search_arg *sargs;
1N/A struct imap_arg *args;
1N/A int args_count;
1N/A const char *error, *charset;
1N/A
1N/A args_count = imap_parser_read_args(cmd->parser, 0, 0, &args);
1N/A if (args_count < 1) {
1N/A if (args_count == -2)
1N/A return FALSE;
1N/A
1N/A client_send_command_error(cmd, args_count < 0 ? NULL :
1N/A "Missing SEARCH arguments.");
1N/A return TRUE;
1N/A }
1N/A cmd->client->input_lock = NULL;
1N/A
1N/A if (!client_verify_open_mailbox(cmd))
1N/A return TRUE;
1N/A
1N/A if (args->type == IMAP_ARG_ATOM &&
1N/A strcasecmp(IMAP_ARG_STR_NONULL(args), "CHARSET") == 0) {
1N/A /* CHARSET specified */
1N/A args++;
1N/A if (args->type != IMAP_ARG_ATOM &&
1N/A args->type != IMAP_ARG_STRING) {
1N/A client_send_command_error(cmd,
1N/A "Invalid charset argument.");
1N/A return TRUE;
1N/A }
1N/A
1N/A charset = IMAP_ARG_STR(args);
1N/A args++;
1N/A } else {
1N/A charset = NULL;
1N/A }
1N/A
1N/A sargs = imap_search_args_build(cmd->pool, cmd->client->mailbox,
1N/A args, &error);
1N/A if (sargs == NULL) {
1N/A /* error in search arguments */
1N/A client_send_tagline(cmd, t_strconcat("NO ", error, NULL));
1N/A return TRUE;
1N/A }
1N/A
1N/A ctx = imap_search_init(cmd, charset, sargs);
1N/A cmd->func = cmd_search_more;
1N/A cmd->context = ctx;
1N/A
1N/A if (cmd_search_more(cmd))
1N/A return TRUE;
1N/A
1N/A /* we could have moved onto syncing by now */
1N/A if (cmd->func == cmd_search_more)
1N/A ctx->to = timeout_add(0, cmd_search_more_callback, cmd);
1N/A return FALSE;
1N/A}
1N/A