imap-fetch.c revision e9956754c88fcf31afe016c00a956cafb2c2864c
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2002-2010 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"
212e9e43a7d49242446331fd43ba519eda936d60Timo 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 "mail-search-build.h"
7a7d2aa11e46195e2d92d6c337d7e78052a5ce67Timo Sirainen#include "imap-commands.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-quote.h"
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo 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 \
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic ARRAY_DEFINE(fetch_handlers, struct imap_fetch_handler);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainenstatic int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_handler *h2)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return strcmp(h1->name, h2->name);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen size_t count)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen{
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen array_append(&fetch_handlers, handlers, count);
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen array_sort(&fetch_handlers, imap_fetch_handler_cmp);
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen}
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenstatic int
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenimap_fetch_handler_bsearch(const char *name, const struct imap_fetch_handler *h)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen{
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen return strcmp(name, h->name);
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenbool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen const struct imap_arg **args)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen{
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen const struct imap_fetch_handler *handler;
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen const char *lookup_name, *p;
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen for (p = name; i_isalnum(*p) || *p == '-'; p++) ;
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen lookup_name = t_strdup_until(name, p);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen handler = array_bsearch(&fetch_handlers, lookup_name,
11352dc3e4b29f3d2763c82f8ea4f99e8daf4fa3Timo Sirainen imap_fetch_handler_bsearch);
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen if (handler == NULL) {
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen client_send_command_error(ctx->cmd,
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen t_strconcat("Unknown parameter ", name, NULL));
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen return FALSE;
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return handler->init(ctx, name, args);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct imap_fetch_context *
cd8507179823de33d6e8242e10dbc15d136245b5Timo Sirainenimap_fetch_init(struct client_command_context *cmd, struct mailbox *box)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct client *client = cmd->client;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_fetch_context *ctx;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->client = client;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cmd = cmd;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->box = box;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->cur_str = str_new(default_pool, 8192);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen p_array_init(&ctx->all_headers, cmd->pool, 64);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen p_array_init(&ctx->handlers, cmd->pool, 16);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen p_array_init(&ctx->tmp_keywords, cmd->pool,
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen client->keywords.announce_count + 8);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->line_finished = TRUE;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen return ctx;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen}
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainenbool imap_fetch_add_changed_since(struct imap_fetch_context *ctx,
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen uint64_t modseq)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen{
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen struct mail_search_arg *search_arg;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen search_arg = p_new(ctx->search_args->pool, struct mail_search_arg, 1);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen search_arg->type = SEARCH_MODSEQ;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen search_arg->value.modseq =
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen p_new(ctx->cmd->pool, struct mail_search_modseq, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen search_arg->value.modseq->modseq = modseq + 1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen search_arg->next = ctx->search_args->args->next;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->search_args->args->next = search_arg;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return imap_fetch_init_handler(ctx, "MODSEQ", NULL);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#undef imap_fetch_add_handler
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_context *ctx,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen bool buffered, bool want_deinit,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const char *name, const char *nil_reply,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen imap_fetch_handler_t *handler, void *context)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* partially because of broken clients, but also partially because
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen it potentially can make client implementations faster, we have a
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen buffered parameter which basically means that the handler promises
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen to write the output in ctx->cur_str. The cur_str is then sent to
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen client before calling any non-buffered handlers.
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen We try to keep the handler registration order the same as the
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen client requested them. This is especially useful to get UID
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen returned first, which some clients rely on..
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_context_handler *ctx_handler;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_fetch_context_handler h;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (context == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* don't allow duplicate handlers */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_foreach(&ctx->handlers, ctx_handler) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ctx_handler->handler == handler &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx_handler->context == NULL)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen memset(&h, 0, sizeof(h));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen h.handler = handler;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen h.context = context;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen h.buffered = buffered;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen h.want_deinit = want_deinit;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen h.name = p_strdup(ctx->cmd->pool, name);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen h.nil_reply = p_strdup(ctx->cmd->pool, nil_reply);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen if (!buffered)
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen array_append(&ctx->handlers, &h, 1);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen else {
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen array_insert(&ctx->handlers, ctx->buffered_handlers_count,
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen &h, 1);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen ctx->buffered_handlers_count++;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen }
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen}
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenstatic void
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenexpunges_drop_known(struct imap_fetch_context *ctx, struct mail *mail,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen ARRAY_TYPE(seq_range) *expunged_uids)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen{
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen const uint32_t *seqs, *uids;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen unsigned int i, count;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen seqs = array_get(ctx->qresync_sample_seqset, &count);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen uids = array_idx(ctx->qresync_sample_uidset, 0);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen i_assert(array_count(ctx->qresync_sample_uidset) == count);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen i_assert(count > 0);
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen /* FIXME: we could do removals from the middle as well */
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen for (i = 0; i < count; i++) {
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen mail_set_seq(mail, seqs[i]);
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen if (uids[i] != mail->uid)
8305127d1074cf9a1e25dec9be2735276462079dTimo Sirainen break;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen }
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen if (i > 0)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen seq_range_array_remove_range(expunged_uids, 1, uids[i-1]);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen}
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainenstatic int get_expunges_fallback(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const ARRAY_TYPE(seq_range) *uid_filter_arr,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ARRAY_TYPE(seq_range) *expunged_uids)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen struct mailbox_transaction_context *trans;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen struct mail_search_args *search_args;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_search_context *search_ctx;
596433ccbca59ce2328dc1d029586154cd937155Timo Sirainen struct mail *mail;
596433ccbca59ce2328dc1d029586154cd937155Timo Sirainen const struct seq_range *uid_filter;
15b5076a239682277b44880e33ea23b55fff7e71Timo Sirainen struct mailbox_status status;
15b5076a239682277b44880e33ea23b55fff7e71Timo Sirainen unsigned int i, count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uint32_t next_uid;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen int ret = 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen uid_filter = array_get(uid_filter_arr, &count);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen i_assert(count > 0);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen i = 0;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen next_uid = uid_filter[0].seq1;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen /* search UIDs only in given range */
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen search_args = mail_search_build_init();
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen search_args->args->type = SEARCH_UIDSET;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen i_array_init(&search_args->args->value.seqset, count);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen array_append_array(&search_args->args->value.seqset, uid_filter_arr);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen trans = mailbox_transaction_begin(ctx->box, 0);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen mail = mail_alloc(trans, 0, NULL);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen mail_search_args_unref(&search_args);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen
074055dadbca01626437cc4724853a374acab6a8Timo Sirainen while (mailbox_search_next(search_ctx, mail)) {
074055dadbca01626437cc4724853a374acab6a8Timo Sirainen if (mail->uid == next_uid) {
074055dadbca01626437cc4724853a374acab6a8Timo Sirainen if (next_uid < uid_filter[i].seq2)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen next_uid++;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen else if (++i < count)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen next_uid = uid_filter[i].seq1;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen else
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen break;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen } else {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen /* next_uid .. mail->uid-1 are expunged */
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen i_assert(mail->uid > next_uid);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen while (mail->uid > uid_filter[i].seq2) {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen seq_range_array_add_range(expunged_uids,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen next_uid,
7f3b826a89bcb7a72759912e99f574b28309fe1bTimo Sirainen uid_filter[i].seq2);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen i++;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen i_assert(i < count);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen next_uid = uid_filter[i].seq1;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen }
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen if (next_uid != mail->uid) {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen seq_range_array_add_range(expunged_uids,
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen next_uid,
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen mail->uid - 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (uid_filter[i].seq2 != mail->uid)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen next_uid = mail->uid + 1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (++i < count)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen next_uid = uid_filter[i].seq1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen break;
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (i < count) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(next_uid <= uid_filter[i].seq2);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen seq_range_array_add_range(expunged_uids, next_uid,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uid_filter[i].seq2);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i++;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen for (; i < count; i++) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen seq_range_array_add_range(expunged_uids, uid_filter[i].seq1,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uid_filter[i].seq2);
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_get_status(ctx->box, STATUS_UIDNEXT, &status);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen seq_range_array_remove_range(expunged_uids, status.uidnext,
c529313e1cbc22244d4528e80aa3e485f8806cd3Timo Sirainen (uint32_t)-1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (mailbox_search_deinit(&search_ctx) < 0)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ret = -1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (ret == 0 && ctx->qresync_sample_seqset != NULL &&
d22301419109ed4a38351715e6760011421dadecTimo Sirainen array_is_created(ctx->qresync_sample_seqset))
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainen expunges_drop_known(ctx, mail, expunged_uids);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen mail_free(&mail);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (void)mailbox_transaction_commit(&trans);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return ret;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmailbox_expunge_to_range(const ARRAY_TYPE(mailbox_expunge_rec) *input,
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ARRAY_TYPE(seq_range) *output)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen{
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen const struct mailbox_expunge_rec *expunge;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen array_foreach(input, expunge)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen seq_range_array_add(output, 0, expunge->uid);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen}
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainenstatic int
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainenimap_fetch_send_vanished(struct imap_fetch_context *ctx)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen{
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen const struct mail_search_arg *uidarg = ctx->search_args->args;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen const struct mail_search_arg *modseqarg = uidarg->next;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen const ARRAY_TYPE(seq_range) *uid_filter = &uidarg->value.seqset;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen uint64_t modseq = modseqarg->value.modseq->modseq - 1;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen ARRAY_TYPE(mailbox_expunge_rec) expunged_uids;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen ARRAY_TYPE(seq_range) expunged_uids_range;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen string_t *str;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen int ret = 0;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen i_array_init(&expunged_uids, array_count(uid_filter));
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen i_array_init(&expunged_uids_range, array_count(uid_filter));
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen if (mailbox_get_expunges(ctx->box, modseq, uid_filter, &expunged_uids))
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen mailbox_expunge_to_range(&expunged_uids, &expunged_uids_range);
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen else {
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen /* return all expunged UIDs */
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (get_expunges_fallback(ctx, uid_filter,
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen &expunged_uids_range) < 0) {
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen array_clear(&expunged_uids_range);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ret = -1;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (array_count(&expunged_uids_range) > 0) {
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen str = str_new(default_pool, 128);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen str_append(str, "* VANISHED (EARLIER) ");
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen imap_write_seq_range(str, &expunged_uids_range);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen str_append(str, "\r\n");
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen o_stream_send(ctx->client->output, str_data(str), str_len(str));
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen str_free(&str);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen }
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen array_free(&expunged_uids);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen array_free(&expunged_uids_range);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen return ret;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen}
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainenint imap_fetch_begin(struct imap_fetch_context *ctx)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen{
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen const void *data;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (ctx->send_vanished) {
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (imap_fetch_send_vanished(ctx) < 0) {
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->failed = TRUE;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen return -1;
ce930f99c6a78f2c74b00df1ad2337095978a9dbTimo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (ctx->flags_update_seen) {
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (mailbox_is_readonly(ctx->box))
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->flags_update_seen = FALSE;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen else if (!ctx->flags_have_handler) {
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->flags_show_only_seen_changes = TRUE;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (array_count(&ctx->all_headers) > 0 &&
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen MAIL_FETCH_STREAM_BODY)) == 0)) {
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen (void)array_append_space(&ctx->all_headers);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen data = array_idx(&ctx->all_headers, 0);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->all_headers_ctx =
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen mailbox_header_lookup_init(ctx->box, data);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if ((ctx->fetch_data &
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->fetch_data |= MAIL_FETCH_NUL_STATE;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box,
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen MAILBOX_TRANSACTION_FLAG_HIDE |
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen MAILBOX_TRANSACTION_FLAG_REFRESH);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->select_counter = ctx->client->select_counter;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->mail = mail_alloc(ctx->trans, ctx->fetch_data,
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->all_headers_ctx);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen /* Delayed uidset -> seqset conversion. VANISHED needs the uidset. */
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen mail_search_args_init(ctx->search_args, ctx->box, TRUE,
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen &ctx->cmd->client->search_saved_uidset);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->search_ctx =
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen mailbox_search_init(ctx->trans, ctx->search_args, NULL);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen return 0;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen}
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen{
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen const unsigned char *data;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen size_t len;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen data = str_data(ctx->cur_str);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen len = str_len(ctx->cur_str);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (len == 0)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen return 0;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen /* there's an extra space at the end if we added any fetch items
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen to buffer */
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (data[len-1] == ' ') {
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen len--;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen ctx->first = FALSE;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen return -1;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen str_truncate(ctx->cur_str, 0);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen return 0;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen}
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen{
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen const struct imap_fetch_context_handler *handler;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (!ctx->first)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen str_append_c(ctx->cur_str, ' ');
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen handler = array_idx(&ctx->handlers, ctx->cur_handler);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen str_printfa(ctx->cur_str, "%s %s ",
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen handler->name, handler->nil_reply);
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (!handler->buffered) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen return -1;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen }
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen return 0;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen}
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainenstatic int imap_fetch_more_int(struct imap_fetch_context *ctx)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen{
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen struct client *client = ctx->client;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen const struct imap_fetch_context_handler *handlers;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen unsigned int count;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen int ret;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (ctx->cont_handler != NULL) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen ret = ctx->cont_handler(ctx);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (ret == 0)
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen return 0;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen
c4bb0320ab43ea35fa6df88fc745fdad906cee44Timo Sirainen if (ret < 0) {
c4bb0320ab43ea35fa6df88fc745fdad906cee44Timo Sirainen if (client->output->closed)
c4bb0320ab43ea35fa6df88fc745fdad906cee44Timo Sirainen return -1;
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen
c4bb0320ab43ea35fa6df88fc745fdad906cee44Timo Sirainen if (ctx->cur_mail->expunged) {
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen /* not an error, just lost it. */
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen ctx->partial_fetch = TRUE;
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return -1;
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen }
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen ctx->cont_handler = NULL;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen ctx->cur_offset = 0;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen ctx->cur_handler++;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (ctx->cur_input != NULL)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_stream_unref(&ctx->cur_input);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen handlers = array_get(&ctx->handlers, &count);
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen for (;;) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen CLIENT_OUTPUT_OPTIMAL_SIZE) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen ret = o_stream_flush(client->output);
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (ret <= 0)
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen return ret;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen }
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (ctx->cur_mail == NULL) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (ctx->cmd->cancel)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (!mailbox_search_next(ctx->search_ctx, ctx->mail))
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen break;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ctx->cur_mail = ctx->mail;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen str_printfa(ctx->cur_str, "* %u FETCH (",
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen ctx->cur_mail->seq);
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen ctx->first = TRUE;
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen ctx->line_finished = FALSE;
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen }
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen for (; ctx->cur_handler < count; ctx->cur_handler++) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (str_len(ctx->cur_str) > 0 &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen !handlers[ctx->cur_handler].buffered) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* first non-buffered handler.
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen flush the buffer. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->line_partial = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen return -1;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen }
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen i_assert(ctx->cur_input == NULL);
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen T_BEGIN {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen const struct imap_fetch_context_handler *h =
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen &handlers[ctx->cur_handler];
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen ret = h->handler(ctx, ctx->cur_mail,
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen h->context);
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen } T_END;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ret == 0)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen return 0;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (ret < 0) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (ctx->cur_mail->expunged) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* not an error, just lost it. */
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ctx->partial_fetch = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(ret < 0 ||
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ctx->cont_handler != NULL);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen return -1;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ctx->cont_handler = NULL;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ctx->cur_offset = 0;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (ctx->cur_input != NULL)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen i_stream_unref(&ctx->cur_input);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen }
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (str_len(ctx->cur_str) > 0) {
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen /* no non-buffered handlers */
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen return -1;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen }
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen ctx->line_finished = TRUE;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen ctx->line_partial = FALSE;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (o_stream_send(client->output, ")\r\n", 3) < 0)
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen return -1;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen client->last_output = ioloop_time;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen ctx->cur_mail = NULL;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen ctx->cur_handler = 0;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen }
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen return 1;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen}
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainenint imap_fetch_more(struct imap_fetch_context *ctx)
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen{
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen int ret;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen i_assert(ctx->client->output_lock == NULL ||
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen ctx->client->output_lock == ctx->cmd);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen ret = imap_fetch_more_int(ctx);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if (ret < 0)
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen ctx->failed = TRUE;
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen if (ctx->line_partial) {
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen /* nothing can be sent until FETCH is finished */
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen ctx->client->output_lock = ctx->cmd;
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen }
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen return ret;
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen}
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainenint imap_fetch_deinit(struct imap_fetch_context *ctx)
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen{
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen const struct imap_fetch_context_handler *handler;
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen array_foreach(&ctx->handlers, handler) {
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if (handler->want_deinit)
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen handler->handler(ctx, NULL, handler->context);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen }
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if (!ctx->line_finished) {
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen ctx->failed = TRUE;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen ctx->failed = TRUE;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen }
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen str_free(&ctx->cur_str);
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen if (ctx->cur_input != NULL)
9847ec56efa15fa063eea9988eee2d4ed9ec7d58Timo Sirainen i_stream_unref(&ctx->cur_input);
9847ec56efa15fa063eea9988eee2d4ed9ec7d58Timo Sirainen
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if (ctx->mail != NULL)
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen mail_free(&ctx->mail);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen
d859478e8b106de6cea54f26861bd4232c92f62cTimo Sirainen mail_search_args_unref(&ctx->search_args);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (ctx->search_ctx != NULL) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen ctx->failed = TRUE;
d859478e8b106de6cea54f26861bd4232c92f62cTimo Sirainen }
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen if (ctx->all_headers_ctx != NULL)
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen mailbox_header_lookup_unref(&ctx->all_headers_ctx);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (ctx->trans != NULL) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen /* even if something failed, we want to commit changes to
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen cache, as well as possible \Seen flag changes for FETCH
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen replies we returned so far. */
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen if (mailbox_transaction_commit(&ctx->trans) < 0)
d859478e8b106de6cea54f26861bd4232c92f62cTimo Sirainen ctx->failed = TRUE;
d859478e8b106de6cea54f26861bd4232c92f62cTimo Sirainen }
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen return ctx->failed ? -1 : 0;
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen}
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen void *context ATTR_UNUSED)
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen{
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen const char *body;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODY, &body) < 0)
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen return -1;
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen if (ctx->first)
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen ctx->first = FALSE;
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen else {
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen return -1;
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen }
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen o_stream_send_str(ctx->client->output, body) < 0 ||
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
d979c1179d55ad86e40f869e48ef3e4db9c817b5Timo Sirainen return -1;
d979c1179d55ad86e40f869e48ef3e4db9c817b5Timo Sirainen return 1;
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen}
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainenstatic bool fetch_body_init(struct imap_fetch_context *ctx, const char *name,
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen const struct imap_arg **args)
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen{
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen if (name[4] == '\0') {
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "("BODY_NIL_REPLY")", fetch_body, NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return fetch_body_section_init(ctx, name, args);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail *mail, void *context ATTR_UNUSED)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *bodystructure;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen &bodystructure) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ctx->first)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ctx->first = FALSE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen else {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic bool
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenfetch_bodystructure_init(struct imap_fetch_context *ctx, const char *name,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const struct imap_arg **args ATTR_UNUSED)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "("BODY_NIL_REPLY" NIL NIL NIL NIL)",
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fetch_bodystructure, NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen void *context ATTR_UNUSED)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen{
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen const char *envelope;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE, &envelope) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ctx->first)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ctx->first = FALSE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen else {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen o_stream_send_str(ctx->client->output, envelope) < 0 ||
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic bool
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenfetch_envelope_init(struct imap_fetch_context *ctx, const char *name,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen const struct imap_arg **args ATTR_UNUSED)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, ENVELOPE_NIL_REPLY,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen fetch_envelope, NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen void *context ATTR_UNUSED)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen enum mail_flags flags;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen const char *const *keywords;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen flags = mail_get_flags(mail);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* Add \Seen flag */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ctx->seen_flags_changed = TRUE;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen flags |= MAIL_SEEN;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen } else if (ctx->flags_show_only_seen_changes) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return 1;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen mail_get_keyword_indexes(mail));
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen str_append(ctx->cur_str, "FLAGS (");
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen imap_write_flags(ctx->cur_str, flags, keywords);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen str_append(ctx->cur_str, ") ");
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return 1;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen}
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenstatic bool
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenfetch_flags_init(struct imap_fetch_context *ctx, const char *name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_arg **args ATTR_UNUSED)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen ctx->flags_have_handler = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->fetch_data |= MAIL_FETCH_FLAGS;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, name, "()", fetch_flags, NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return TRUE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainenstatic int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail,
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen void *context ATTR_UNUSED)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen time_t date;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
34f4c7610b846a945779b6be78d1ef575c7d0ca8Timo Sirainen if (mail_get_received_date(mail, &date) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(ctx->cur_str, "INTERNALDATE \"%s\" ",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_to_datetime(date));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return 1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainenstatic bool
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenfetch_internaldate_init(struct imap_fetch_context *ctx, const char *name,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen const struct imap_arg **args ATTR_UNUSED)
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen{
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, name,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen "\"01-Jan-1970 00:00:00 +0000\"",
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen fetch_internaldate, NULL);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen return TRUE;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen}
6469cf211a57433335641725dc236ebb2b9fdd3bTimo Sirainen
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainenstatic int fetch_modseq(struct imap_fetch_context *ctx, struct mail *mail,
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen void *context ATTR_UNUSED)
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen{
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen uint64_t modseq;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen modseq = mail_get_modseq(mail);
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen if (ctx->client->highest_fetch_modseq < modseq)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->client->highest_fetch_modseq = modseq;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(ctx->cur_str, "MODSEQ (%llu) ",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (unsigned long long)modseq);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainenstatic bool
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainenfetch_modseq_init(struct imap_fetch_context *ctx, const char *name,
8a13b020f90e080570658b18c042e7e352c8b14fTimo Sirainen const struct imap_arg **args ATTR_UNUSED)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL,
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen fetch_modseq, NULL);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return TRUE;
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen}
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainenstatic int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen void *context ATTR_UNUSED)
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(ctx->cur_str, "UID %u ", mail->uid);
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen return 1;
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen}
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenstatic bool
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenfetch_uid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_arg **args ATTR_UNUSED)
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainen{
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, fetch_uid, NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainenstatic 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->cur_str, "X-GUID ");
imap_quote_append_string(ctx->cur_str, value, FALSE);
str_append_c(ctx->cur_str, ' ');
return 1;
}
static bool
fetch_guid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name,
const struct imap_arg **args ATTR_UNUSED)
{
imap_fetch_add_handler(ctx, TRUE, FALSE, name, "", fetch_guid, NULL);
return TRUE;
}
static int fetch_x_mailbox(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
const char *str;
if (mail_get_special(mail, MAIL_FETCH_MAILBOX_NAME, &str) < 0)
i_panic("mailbox name not returned");
str_append(ctx->cur_str, "X-MAILBOX ");
imap_quote_append_string(ctx->cur_str, str, FALSE);
str_append_c(ctx->cur_str, ' ');
return 1;
}
static bool
fetch_x_mailbox_init(struct imap_fetch_context *ctx ATTR_UNUSED,
const char *name,
const struct imap_arg **args ATTR_UNUSED)
{
imap_fetch_add_handler(ctx, TRUE, FALSE, name, 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->cur_str, "X-REAL-UID %u ",
mail_get_real_mail(mail)->uid);
return 1;
}
static bool
fetch_x_real_uid_init(struct imap_fetch_context *ctx ATTR_UNUSED,
const char *name,
const struct imap_arg **args ATTR_UNUSED)
{
imap_fetch_add_handler(ctx, TRUE, FALSE, name, 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->cur_str, "X-SAVEDATE \"%s\" ",
imap_to_datetime(date));
return 1;
}
static bool
fetch_x_savedate_init(struct imap_fetch_context *ctx, const char *name,
const struct imap_arg **args ATTR_UNUSED)
{
ctx->fetch_data |= MAIL_FETCH_SAVE_DATE;
imap_fetch_add_handler(ctx, TRUE, FALSE, name,
"\"01-Jan-1970 00:00:00 +0000\"",
fetch_x_savedate, NULL);
return TRUE;
}
static const struct imap_fetch_handler
imap_fetch_default_handlers[] = {
{ "BODY", fetch_body_init },
{ "BODYSTRUCTURE", fetch_bodystructure_init },
{ "ENVELOPE", fetch_envelope_init },
{ "FLAGS", fetch_flags_init },
{ "INTERNALDATE", fetch_internaldate_init },
{ "MODSEQ", fetch_modseq_init },
{ "RFC822", fetch_rfc822_init },
{ "UID", 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);
}