imap-fetch.c revision 6f84506cf692d4f4f1ac69498e936b27dabdb60c
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-common.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "array.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "buffer.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "istream.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "ostream.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "str.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "message-send.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "message-size.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-date.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-utf7.h"
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen#include "mail-search-build.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-commands.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-quote.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-fetch.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-util.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <stdlib.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <ctype.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#define BODY_NIL_REPLY \
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#define ENVELOPE_NIL_REPLY \
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic ARRAY_DEFINE(fetch_handlers, struct imap_fetch_handler);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_handler *h2)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return strcmp(h1->name, h2->name);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t count)
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen{
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen array_append(&fetch_handlers, handlers, count);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen array_sort(&fetch_handlers, imap_fetch_handler_cmp);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen}
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen
942302b0247403645394d848b3c620ead262a2a5Timo Sirainenstatic int
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenimap_fetch_handler_bsearch(const char *name, const struct imap_fetch_handler *h)
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen{
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen return strcmp(name, h->name);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
942302b0247403645394d848b3c620ead262a2a5Timo Sirainenbool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx)
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen{
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen const struct imap_fetch_handler *handler;
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen const char *lookup_name, *p;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (p = init_ctx->name; i_isalnum(*p) || *p == '-'; p++) ;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen lookup_name = t_strdup_until(init_ctx->name, p);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen handler = array_bsearch(&fetch_handlers, lookup_name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_handler_bsearch);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (handler == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen init_ctx->error = t_strdup_printf("Unknown parameter: %s",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen init_ctx->name);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!handler->init(init_ctx)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(init_ctx->error != NULL);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return FALSE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return TRUE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen bool (*init)(struct imap_fetch_init_context *))
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct imap_fetch_init_context init_ctx;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen memset(&init_ctx, 0, sizeof(init_ctx));
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen init_ctx.fetch_ctx = ctx;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen init_ctx.pool = ctx->ctx_pool;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!init(&init_ctx))
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_unreached();
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstruct imap_fetch_context *
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenimap_fetch_alloc(struct client *client, pool_t pool)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct imap_fetch_context *ctx;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx = p_new(pool, struct imap_fetch_context, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->client = client;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->ctx_pool = pool;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pool_ref(pool);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_array_init(&ctx->all_headers, pool, 64);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_array_init(&ctx->handlers, pool, 16);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_array_init(&ctx->tmp_keywords, pool,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen client->keywords.announce_count + 8);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return ctx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid imap_fetch_add_changed_since(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uint64_t modseq)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_search_arg *search_arg;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen search_arg = p_new(ctx->search_args->pool, struct mail_search_arg, 1);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen search_arg->type = SEARCH_MODSEQ;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen search_arg->value.modseq =
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen p_new(ctx->search_args->pool, struct mail_search_modseq, 1);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen search_arg->value.modseq->modseq = modseq + 1;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen search_arg->next = ctx->search_args->args->next;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen ctx->search_args->args->next = search_arg;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen imap_fetch_init_nofail_handler(ctx, imap_fetch_modseq_init);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen}
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen#undef imap_fetch_add_handler
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_init_context *ctx,
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen enum imap_fetch_handler_flags flags,
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen const char *nil_reply,
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen imap_fetch_handler_t *handler, void *context)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* partially because of broken clients, but also partially because
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen it potentially can make client implementations faster, we have a
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen buffered parameter which basically means that the handler promises
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen to write the output in fetch_ctx->state.cur_str. The cur_str is then
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen sent to client before calling any non-buffered handlers.
90f29b3af0a645a4ef71889640f6eb6daac8c310Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen We try to keep the handler registration order the same as the
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen client requested them. This is especially useful to get UID
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen returned first, which some clients rely on..
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen */
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen const struct imap_fetch_context_handler *ctx_handler;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen struct imap_fetch_context_handler h;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen if (context == NULL) {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen /* don't allow duplicate handlers */
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen array_foreach(&ctx->fetch_ctx->handlers, ctx_handler) {
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen if (ctx_handler->handler == handler &&
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen ctx_handler->context == NULL)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen return;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen }
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen }
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen memset(&h, 0, sizeof(h));
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen h.handler = handler;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen h.context = context;
09773218272c490c3ad1572a6579703d7c35344cTimo Sirainen h.buffered = (flags & IMAP_FETCH_HANDLER_FLAG_BUFFERED) != 0;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen h.want_deinit = (flags & IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT) != 0;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen h.name = p_strdup(ctx->pool, ctx->name);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen h.nil_reply = p_strdup(ctx->pool, nil_reply);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen if (!h.buffered)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen array_append(&ctx->fetch_ctx->handlers, &h, 1);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen else {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen array_insert(&ctx->fetch_ctx->handlers,
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen ctx->fetch_ctx->buffered_handlers_count, &h, 1);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen ctx->fetch_ctx->buffered_handlers_count++;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen }
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen}
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainenstatic void
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainenexpunges_drop_known(struct mailbox *box,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_qresync_args *qresync_args,
7f3b826a89bcb7a72759912e99f574b28309fe1bTimo Sirainen struct mailbox_transaction_context *trans,
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen ARRAY_TYPE(seq_range) *expunged_uids)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen{
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen struct mailbox_status status;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen struct mail *mail;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen const uint32_t *seqs, *uids;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen unsigned int i, count;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen seqs = array_get(qresync_args->qresync_sample_seqset, &count);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen uids = array_idx(qresync_args->qresync_sample_uidset, 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(array_count(qresync_args->qresync_sample_uidset) == count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(count > 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_get_open_status(box, STATUS_MESSAGES, &status);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail = mail_alloc(trans, 0, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* FIXME: we could do removals from the middle as well */
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen for (i = 0; i < count && seqs[i] <= status.messages; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_set_seq(mail, seqs[i]);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (uids[i] != mail->uid)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen break;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (i > 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen seq_range_array_remove_range(expunged_uids, 1, uids[i-1]);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_free(&mail);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen}
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic int
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenget_expunges_fallback(struct mailbox *box,
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen const struct imap_fetch_qresync_args *qresync_args,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const ARRAY_TYPE(seq_range) *uid_filter_arr,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ARRAY_TYPE(seq_range) *expunged_uids)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_transaction_context *trans;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_search_args *search_args;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mail_search_context *search_ctx;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mail *mail;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen const struct seq_range *uid_filter;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mailbox_status status;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen unsigned int i, count;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen uint32_t next_uid;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen int ret = 0;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uid_filter = array_get(uid_filter_arr, &count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(count > 0);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i = 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen next_uid = uid_filter[0].seq1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* search UIDs only in given range */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen search_args = mail_search_build_init();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen search_args->args->type = SEARCH_UIDSET;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_array_init(&search_args->args->value.seqset, count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_append_array(&search_args->args->value.seqset, uid_filter_arr);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen trans = mailbox_transaction_begin(box, 0);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_search_args_unref(&search_args);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (mail->uid == next_uid) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (next_uid < uid_filter[i].seq2)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen next_uid++;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen else if (++i < count)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen next_uid = uid_filter[i].seq1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen else
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen break;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* next_uid .. mail->uid-1 are expunged */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_assert(mail->uid > next_uid);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen while (mail->uid > uid_filter[i].seq2) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen seq_range_array_add_range(expunged_uids,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen next_uid,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen uid_filter[i].seq2);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i++;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_assert(i < count);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen next_uid = uid_filter[i].seq1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (next_uid != mail->uid) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen seq_range_array_add_range(expunged_uids,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen next_uid,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mail->uid - 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (uid_filter[i].seq2 != mail->uid)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen next_uid = mail->uid + 1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen else if (++i < count)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen next_uid = uid_filter[i].seq1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen else
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen break;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (i < count) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_assert(next_uid <= uid_filter[i].seq2);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen seq_range_array_add_range(expunged_uids, next_uid,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uid_filter[i].seq2);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i++;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (; i < count; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen seq_range_array_add_range(expunged_uids, uid_filter[i].seq1,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uid_filter[i].seq2);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen mailbox_get_open_status(box, STATUS_UIDNEXT, &status);
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen seq_range_array_remove_range(expunged_uids, status.uidnext,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (uint32_t)-1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
c399b462ce6b81c78eaf0fa9c7c35bca157daa1aTimo Sirainen if (mailbox_search_deinit(&search_ctx) < 0)
c399b462ce6b81c78eaf0fa9c7c35bca157daa1aTimo Sirainen ret = -1;
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen if (ret == 0 && qresync_args->qresync_sample_seqset != NULL &&
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen array_is_created(qresync_args->qresync_sample_seqset))
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen expunges_drop_known(box, qresync_args, trans, expunged_uids);
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen (void)mailbox_transaction_commit(&trans);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint imap_fetch_send_vanished(struct client *client, struct mailbox *box,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mail_search_args *search_args,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen const struct imap_fetch_qresync_args *qresync_args)
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen const struct mail_search_arg *uidarg = search_args->args;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mail_search_arg *modseqarg = uidarg->next;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const ARRAY_TYPE(seq_range) *uid_filter;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen uint64_t modseq;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ARRAY_TYPE(seq_range) expunged_uids_range;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen string_t *str;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen int ret = 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen i_assert(uidarg->type == SEARCH_UIDSET);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(modseqarg->type == SEARCH_MODSEQ);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uid_filter = &uidarg->value.seqset;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen modseq = modseqarg->value.modseq->modseq - 1;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen i_array_init(&expunged_uids_range, array_count(uid_filter));
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (!mailbox_get_expunged_uids(box, modseq, uid_filter, &expunged_uids_range)) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen /* return all expunged UIDs */
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (get_expunges_fallback(box, qresync_args, uid_filter,
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen &expunged_uids_range) < 0) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen array_clear(&expunged_uids_range);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ret = -1;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (array_count(&expunged_uids_range) > 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str = str_new(default_pool, 128);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_append(str, "* VANISHED (EARLIER) ");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_write_seq_range(str, &expunged_uids_range);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_append(str, "\r\n");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_free(&str);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_free(&expunged_uids_range);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void imap_fetch_init(struct imap_fetch_context *ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ctx->initialized)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->initialized = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ctx->flags_update_seen && !ctx->flags_have_handler) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->flags_show_only_seen_changes = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_init_nofail_handler(ctx, imap_fetch_flags_init);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((ctx->fetch_data &
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->fetch_data |= MAIL_FETCH_NUL_STATE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenimap_fetch_begin_full(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox *box, bool once)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_header_lookup_ctx *wanted_headers = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_search_args *search_args;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *headers;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(!ctx->state.fetching);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_init(ctx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen memset(&ctx->state, 0, sizeof(ctx->state));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (array_count(&ctx->all_headers) > 0 &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen MAIL_FETCH_STREAM_BODY)) == 0)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_append_zero(&ctx->all_headers);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen headers = array_idx(&ctx->all_headers, 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen wanted_headers = mailbox_header_lookup_init(box, headers);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_delete(&ctx->all_headers,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_count(&ctx->all_headers)-1, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.trans = mailbox_transaction_begin(box,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen MAILBOX_TRANSACTION_FLAG_HIDE |
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen MAILBOX_TRANSACTION_FLAG_REFRESH);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!once) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* fetch can be executed multiple times.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen clone the search args for this fetch */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen search_args = mail_search_args_dup(ctx->search_args);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen search_args = ctx->search_args;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->search_args = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_search_args_init(search_args, box, TRUE,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen &ctx->client->search_saved_uidset);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.search_ctx =
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_search_init(ctx->state.trans, search_args, NULL,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->fetch_data, wanted_headers);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.cur_str = str_new(default_pool, 8192);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.fetching = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.line_finished = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (wanted_headers != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_header_lookup_unref(&wanted_headers);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_search_args_unref(&search_args);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx, struct mailbox *box)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_begin_full(ctx, box, FALSE);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid imap_fetch_begin_once(struct imap_fetch_context *ctx, struct mailbox *box)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_begin_full(ctx, box, TRUE);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const unsigned char *data;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t len;
e345faa28311a949d01ed9088e64b231de0829deTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen data = str_data(ctx->state.cur_str);
e345faa28311a949d01ed9088e64b231de0829deTimo Sirainen len = str_len(ctx->state.cur_str);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (len == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* there's an extra space at the end if we added any fetch items
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen to buffer */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (data[len-1] == ' ') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen len--;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.cur_first = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_truncate(ctx->state.cur_str, 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_context_handler *handler;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!ctx->state.cur_first)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_append_c(ctx->state.cur_str, ' ');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen handler = array_idx(&ctx->handlers, ctx->state.cur_handler);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(ctx->state.cur_str, "%s %s ",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen handler->name, handler->nil_reply);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!handler->buffered) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int imap_fetch_more_int(struct imap_fetch_context *ctx, bool cancel)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_fetch_state *state = &ctx->state;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct client *client = ctx->client;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_context_handler *handlers;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (state->cont_handler != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = state->cont_handler(ctx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ret == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ret < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (client->output->closed)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (state->cur_mail->expunged) {
c48f32afa608cb0aeef8f34bc2c61271ff394364Timo Sirainen /* not an error, just lost it. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen state->skipped_expunged_msgs = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen }
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen state->cont_handler = NULL;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen state->cur_offset = 0;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen state->cur_handler++;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (state->cur_input != NULL)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_stream_unref(&state->cur_input);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen handlers = array_get(&ctx->handlers, &count);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen for (;;) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen CLIENT_OUTPUT_OPTIMAL_SIZE) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen ret = o_stream_flush(client->output);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (ret <= 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return ret;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (state->cur_mail == NULL) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (cancel)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return 1;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (!mailbox_search_next(state->search_ctx,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen &state->cur_mail))
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen break;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen str_printfa(state->cur_str, "* %u FETCH (",
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen state->cur_mail->seq);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen state->cur_first = TRUE;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen state->line_finished = FALSE;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen for (; state->cur_handler < count; state->cur_handler++) {
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen if (str_len(state->cur_str) > 0 &&
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen !handlers[state->cur_handler].buffered) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen /* first non-buffered handler.
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen flush the buffer. */
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen state->line_partial = TRUE;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return -1;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_assert(state->cur_input == NULL);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen T_BEGIN {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen const struct imap_fetch_context_handler *h =
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen &handlers[state->cur_handler];
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ret = h->handler(ctx, state->cur_mail,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen h->context);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen } T_END;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (ret == 0)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return 0;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (ret < 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (state->cur_mail->expunged) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* not an error, just lost it. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen state->skipped_expunged_msgs = TRUE;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen return -1;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen } else {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_assert(ret < 0 ||
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen state->cont_handler != NULL);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return -1;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen state->cont_handler = NULL;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen state->cur_offset = 0;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (state->cur_input != NULL)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen i_stream_unref(&state->cur_input);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen }
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (str_len(state->cur_str) > 0) {
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen /* no non-buffered handlers */
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return -1;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen }
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen state->line_finished = TRUE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen state->line_partial = FALSE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen o_stream_nsend(client->output, ")\r\n", 3);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen client->last_output = ioloop_time;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen state->cur_mail = NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen state->cur_handler = 0;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen }
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return 1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint imap_fetch_more(struct imap_fetch_context *ctx,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct client_command_context *cmd)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int ret;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(ctx->client->output_lock == NULL ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->client->output_lock == cmd);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ret = imap_fetch_more_int(ctx, cmd->cancel);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (ret < 0)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen ctx->state.failed = TRUE;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (ctx->state.line_partial) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen /* nothing can be sent until FETCH is finished */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->client->output_lock = cmd;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return ret;
34f4c7610b846a945779b6be78d1ef575c7d0ca8Timo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint imap_fetch_end(struct imap_fetch_context *ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_fetch_state *state = &ctx->state;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ctx->state.fetching) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.fetching = FALSE;
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen if (!state->line_finished) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen state->failed = TRUE;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen state->failed = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (state->cur_str != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_free(&state->cur_str);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (state->cur_input != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_unref(&state->cur_input);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen if (state->search_ctx != NULL) {
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen if (mailbox_search_deinit(&state->search_ctx) < 0)
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen state->failed = TRUE;
c1526c9903d3aaae653e6f173c7084ac62b8e76bTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
2f1a8d2d0008c63241143b67698cf1d523560bf9Timo Sirainen if (state->trans != NULL) {
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen /* even if something failed, we want to commit changes to
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen cache, as well as possible \Seen flag changes for FETCH
6c40fee25bda974c0502e32ca70ca8ebb1c88a76Timo Sirainen replies we returned so far. */
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen if (mailbox_transaction_commit(&state->trans) < 0)
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen state->failed = TRUE;
80a1558bc44206376c3d55442179676d42f54584Timo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return state->failed ? -1 : 0;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid imap_fetch_free(struct imap_fetch_context **_ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
de58be41126e5d68008d2ea706d62ccdc1f29337Timo Sirainen struct imap_fetch_context *ctx = *_ctx;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen const struct imap_fetch_context_handler *handler;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen *_ctx = NULL;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen (void)imap_fetch_end(ctx);
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen array_foreach(&ctx->handlers, handler) {
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen if (handler->want_deinit)
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen handler->handler(ctx, NULL, handler->context);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (ctx->search_args != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_search_args_unref(&ctx->search_args);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pool_unref(&ctx->ctx_pool);
}
static int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
const char *body;
if (mail_get_special(mail, MAIL_FETCH_IMAP_BODY, &body) < 0)
return -1;
if (ctx->state.cur_first)
ctx->state.cur_first = FALSE;
else {
if (o_stream_send(ctx->client->output, " ", 1) < 0)
return -1;
}
if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
o_stream_send_str(ctx->client->output, body) < 0 ||
o_stream_send(ctx->client->output, ")", 1) < 0)
return -1;
return 1;
}
static bool fetch_body_init(struct imap_fetch_init_context *ctx)
{
if (ctx->name[4] == '\0') {
ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY")",
fetch_body, NULL);
return TRUE;
}
return imap_fetch_body_section_init(ctx);
}
static int fetch_bodystructure(struct imap_fetch_context *ctx,
struct mail *mail, void *context ATTR_UNUSED)
{
const char *bodystructure;
if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
&bodystructure) < 0)
return -1;
if (ctx->state.cur_first)
ctx->state.cur_first = FALSE;
else {
if (o_stream_send(ctx->client->output, " ", 1) < 0)
return -1;
}
if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
o_stream_send(ctx->client->output, ")", 1) < 0)
return -1;
return 1;
}
static bool fetch_bodystructure_init(struct imap_fetch_init_context *ctx)
{
ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY" NIL NIL NIL NIL)",
fetch_bodystructure, NULL);
return TRUE;
}
static int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
const char *envelope;
if (mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE, &envelope) < 0)
return -1;
if (ctx->state.cur_first)
ctx->state.cur_first = FALSE;
else {
if (o_stream_send(ctx->client->output, " ", 1) < 0)
return -1;
}
if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
o_stream_send_str(ctx->client->output, envelope) < 0 ||
o_stream_send(ctx->client->output, ")", 1) < 0)
return -1;
return 1;
}
static bool fetch_envelope_init(struct imap_fetch_init_context *ctx)
{
ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
imap_fetch_add_handler(ctx, 0, ENVELOPE_NIL_REPLY,
fetch_envelope, NULL);
return TRUE;
}
static int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
enum mail_flags flags;
const char *const *keywords;
flags = mail_get_flags(mail);
if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0 &&
!mailbox_is_readonly(mail->box)) {
/* Add \Seen flag */
ctx->state.seen_flags_changed = TRUE;
flags |= MAIL_SEEN;
mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
} else if (ctx->flags_show_only_seen_changes) {
return 1;
}
keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
mail_get_keyword_indexes(mail));
str_append(ctx->state.cur_str, "FLAGS (");
imap_write_flags(ctx->state.cur_str, flags, keywords);
str_append(ctx->state.cur_str, ") ");
return 1;
}
bool imap_fetch_flags_init(struct imap_fetch_init_context *ctx)
{
ctx->fetch_ctx->flags_have_handler = TRUE;
ctx->fetch_ctx->fetch_data |= MAIL_FETCH_FLAGS;
imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
"()", fetch_flags, NULL);
return TRUE;
}
static int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
time_t date;
if (mail_get_received_date(mail, &date) < 0)
return -1;
str_printfa(ctx->state.cur_str, "INTERNALDATE \"%s\" ",
imap_to_datetime(date));
return 1;
}
static bool fetch_internaldate_init(struct imap_fetch_init_context *ctx)
{
ctx->fetch_ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
"\"01-Jan-1970 00:00:00 +0000\"",
fetch_internaldate, NULL);
return TRUE;
}
static int fetch_modseq(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
uint64_t modseq;
modseq = mail_get_modseq(mail);
if (ctx->client->highest_fetch_modseq < modseq)
ctx->client->highest_fetch_modseq = modseq;
str_printfa(ctx->state.cur_str, "MODSEQ (%llu) ",
(unsigned long long)modseq);
return 1;
}
bool imap_fetch_modseq_init(struct imap_fetch_init_context *ctx)
{
(void)client_enable(ctx->fetch_ctx->client, MAILBOX_FEATURE_CONDSTORE);
imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
NULL, fetch_modseq, NULL);
return TRUE;
}
static int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
str_printfa(ctx->state.cur_str, "UID %u ", mail->uid);
return 1;
}
bool imap_fetch_uid_init(struct imap_fetch_init_context *ctx)
{
imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
NULL, fetch_uid, NULL);
return TRUE;
}
static int fetch_guid(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
const char *value;
if (mail_get_special(mail, MAIL_FETCH_GUID, &value) < 0)
return -1;
str_append(ctx->state.cur_str, "X-GUID ");
imap_quote_append_string(ctx->state.cur_str, value, FALSE);
str_append_c(ctx->state.cur_str, ' ');
return 1;
}
static bool fetch_guid_init(struct imap_fetch_init_context *ctx)
{
ctx->fetch_ctx->fetch_data |= MAIL_FETCH_GUID;
imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
"", fetch_guid, NULL);
return TRUE;
}
static int fetch_x_mailbox(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
const char *name;
string_t *mutf7_name;
if (mail_get_special(mail, MAIL_FETCH_MAILBOX_NAME, &name) < 0)
i_panic("mailbox name not returned");
mutf7_name = t_str_new(strlen(name)*2);
if (imap_utf8_to_utf7(name, mutf7_name) < 0)
i_panic("FETCH: Mailbox name not UTF-8: %s", name);
str_append(ctx->state.cur_str, "X-MAILBOX ");
imap_quote_append_string(ctx->state.cur_str, str_c(mutf7_name), FALSE);
str_append_c(ctx->state.cur_str, ' ');
return 1;
}
static bool fetch_x_mailbox_init(struct imap_fetch_init_context *ctx)
{
imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
NULL, fetch_x_mailbox, NULL);
return TRUE;
}
static int fetch_x_real_uid(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
str_printfa(ctx->state.cur_str, "X-REAL-UID %u ",
mail_get_real_mail(mail)->uid);
return 1;
}
static bool fetch_x_real_uid_init(struct imap_fetch_init_context *ctx)
{
imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
NULL, fetch_x_real_uid, NULL);
return TRUE;
}
static int fetch_x_savedate(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
time_t date;
if (mail_get_save_date(mail, &date) < 0)
return -1;
str_printfa(ctx->state.cur_str, "X-SAVEDATE \"%s\" ",
imap_to_datetime(date));
return 1;
}
static bool fetch_x_savedate_init(struct imap_fetch_init_context *ctx)
{
ctx->fetch_ctx->fetch_data |= MAIL_FETCH_SAVE_DATE;
imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
"\"01-Jan-1970 00:00:00 +0000\"",
fetch_x_savedate, NULL);
return TRUE;
}
static const struct imap_fetch_handler
imap_fetch_default_handlers[] = {
{ "BINARY", imap_fetch_binary_init },
{ "BODY", fetch_body_init },
{ "BODYSTRUCTURE", fetch_bodystructure_init },
{ "ENVELOPE", fetch_envelope_init },
{ "FLAGS", imap_fetch_flags_init },
{ "INTERNALDATE", fetch_internaldate_init },
{ "MODSEQ", imap_fetch_modseq_init },
{ "RFC822", imap_fetch_rfc822_init },
{ "UID", imap_fetch_uid_init },
{ "X-GUID", fetch_guid_init },
{ "X-MAILBOX", fetch_x_mailbox_init },
{ "X-REAL-UID", fetch_x_real_uid_init },
{ "X-SAVEDATE", fetch_x_savedate_init }
};
void imap_fetch_handlers_init(void)
{
i_array_init(&fetch_handlers, 32);
imap_fetch_handlers_register(imap_fetch_default_handlers,
N_ELEMENTS(imap_fetch_default_handlers));
}
void imap_fetch_handlers_deinit(void)
{
array_free(&fetch_handlers);
}