imap-fetch.c revision efe78d3ba24fc866af1c79b9223dc0809ba26cad
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "imap-common.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "array.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "buffer.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "istream.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ostream.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "str.h"
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen#include "message-size.h"
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen#include "imap-date.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "imap-utf7.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "mail-search-build.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "imap-commands.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "imap-quote.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "imap-fetch.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "imap-util.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen#include <ctype.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define BODY_NIL_REPLY \
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define ENVELOPE_NIL_REPLY \
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic ARRAY(struct imap_fetch_handler) fetch_handlers;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen const struct imap_fetch_handler *h2)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen{
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen return strcmp(h1->name, h2->name);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen}
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen size_t count)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen array_append(&fetch_handlers, handlers, count);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen array_sort(&fetch_handlers, imap_fetch_handler_cmp);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen}
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenstatic int
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenimap_fetch_handler_bsearch(const char *name, const struct imap_fetch_handler *h)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return strcmp(name, h->name);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenbool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen const struct imap_fetch_handler *handler;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen const char *lookup_name, *p;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen for (p = init_ctx->name; i_isalnum(*p) || *p == '-'; p++) ;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lookup_name = t_strdup_until(init_ctx->name, p);
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen handler = array_bsearch(&fetch_handlers, lookup_name,
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen imap_fetch_handler_bsearch);
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen if (handler == NULL) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen init_ctx->error = t_strdup_printf("Unknown parameter: %s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen init_ctx->name);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen }
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (!handler->init(init_ctx)) {
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen i_assert(init_ctx->error != NULL);
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen return FALSE;
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen }
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen return TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainenvoid imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool (*init)(struct imap_fetch_init_context *))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct imap_fetch_init_context init_ctx;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen i_zero(&init_ctx);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen init_ctx.fetch_ctx = ctx;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen init_ctx.pool = ctx->ctx_pool;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen if (!init(&init_ctx))
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch i_unreached();
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen}
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainenint imap_fetch_att_list_parse(struct client *client, pool_t pool,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen const struct imap_arg *list,
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen struct imap_fetch_context **fetch_ctx_r,
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch const char **error_r)
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch{
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen struct imap_fetch_init_context init_ctx;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen const char *str;
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_zero(&init_ctx);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen init_ctx.fetch_ctx = imap_fetch_alloc(client, pool);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen init_ctx.pool = pool;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen init_ctx.args = list;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen while (imap_arg_get_atom(init_ctx.args, &str)) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen init_ctx.name = t_str_ucase(str);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen init_ctx.args++;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (!imap_fetch_init_handler(&init_ctx)) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen *error_r = t_strconcat("Invalid fetch-att list: ",
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen init_ctx.error, NULL);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen imap_fetch_free(&init_ctx.fetch_ctx);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return -1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!IMAP_ARG_IS_EOL(init_ctx.args)) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen *error_r = "fetch-att list contains non-atoms.";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen imap_fetch_free(&init_ctx.fetch_ctx);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen *fetch_ctx_r = init_ctx.fetch_ctx;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstruct imap_fetch_context *
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenimap_fetch_alloc(struct client *client, pool_t pool)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct imap_fetch_context *ctx;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx = p_new(pool, struct imap_fetch_context, 1);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen ctx->client = client;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->ctx_pool = pool;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen pool_ref(pool);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen p_array_init(&ctx->all_headers, pool, 64);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen p_array_init(&ctx->handlers, pool, 16);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen p_array_init(&ctx->tmp_keywords, pool,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->keywords.announce_count + 8);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return ctx;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen#undef imap_fetch_add_handler
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_init_context *ctx,
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen enum imap_fetch_handler_flags flags,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const char *nil_reply,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen imap_fetch_handler_t *handler, void *context)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* partially because of broken clients, but also partially because
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen it potentially can make client implementations faster, we have a
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen buffered parameter which basically means that the handler promises
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen to write the output in fetch_ctx->state.cur_str. The cur_str is then
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen sent to client before calling any non-buffered handlers.
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen We try to keep the handler registration order the same as the
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen client requested them. This is especially useful to get UID
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen returned first, which some clients rely on..
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen */
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen const struct imap_fetch_context_handler *ctx_handler;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct imap_fetch_context_handler h;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (context == NULL) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* don't allow duplicate handlers */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen array_foreach(&ctx->fetch_ctx->handlers, ctx_handler) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (ctx_handler->handler == handler &&
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ctx_handler->context == NULL)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_zero(&h);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen h.handler = handler;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen h.context = context;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen h.buffered = (flags & IMAP_FETCH_HANDLER_FLAG_BUFFERED) != 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen h.want_deinit = (flags & IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT) != 0;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen h.name = p_strdup(ctx->pool, ctx->name);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen h.nil_reply = p_strdup(ctx->pool, nil_reply);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (!h.buffered)
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen array_append(&ctx->fetch_ctx->handlers, &h, 1);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen else {
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen array_insert(&ctx->fetch_ctx->handlers,
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen ctx->fetch_ctx->buffered_handlers_count, &h, 1);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen ctx->fetch_ctx->buffered_handlers_count++;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen }
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen}
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainenstatic void
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainenexpunges_drop_known(struct mailbox *box,
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen const struct imap_fetch_qresync_args *qresync_args,
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen struct mailbox_transaction_context *trans,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ARRAY_TYPE(seq_range) *expunged_uids)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen struct mailbox_status status;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen struct mail *mail;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen const uint32_t *seqs, *uids;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen unsigned int i, count;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen seqs = array_get(qresync_args->qresync_sample_seqset, &count);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen uids = array_idx(qresync_args->qresync_sample_uidset, 0);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_assert(array_count(qresync_args->qresync_sample_uidset) == count);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_assert(count > 0);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen mailbox_get_open_status(box, STATUS_MESSAGES, &status);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen mail = mail_alloc(trans, 0, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* FIXME: we could do removals from the middle as well */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count && seqs[i] <= status.messages; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_set_seq(mail, seqs[i]);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (uids[i] != mail->uid)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (i > 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen seq_range_array_remove_range(expunged_uids, 1, uids[i-1]);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_free(&mail);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenget_expunges_fallback(struct mailbox *box,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct imap_fetch_qresync_args *qresync_args,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const ARRAY_TYPE(seq_range) *uid_filter_arr,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ARRAY_TYPE(seq_range) *expunged_uids)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mailbox_transaction_context *trans;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_search_args *search_args;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_search_context *search_ctx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail *mail;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const struct seq_range *uid_filter;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct mailbox_status status;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, count;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen uint32_t next_uid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int ret = 0;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen uid_filter = array_get(uid_filter_arr, &count);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen i_assert(count > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen next_uid = uid_filter[0].seq1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* search UIDs only in given range */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen search_args = mail_search_build_init();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen search_args->args->type = SEARCH_UIDSET;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_array_init(&search_args->args->value.seqset, count);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen array_append_array(&search_args->args->value.seqset, uid_filter_arr);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen trans = mailbox_transaction_begin(box, 0);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen mail_search_args_unref(&search_args);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail->uid == next_uid) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (next_uid < uid_filter[i].seq2)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen next_uid++;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen else if (++i < count)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen next_uid = uid_filter[i].seq1;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen else
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen break;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen } else {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* next_uid .. mail->uid-1 are expunged */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen i_assert(mail->uid > next_uid);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen while (mail->uid > uid_filter[i].seq2) {
e30b9e07f9657c35ca09ac36d57d60cbe2ebbc66Timo Sirainen seq_range_array_add_range(expunged_uids,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen next_uid,
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen uid_filter[i].seq2);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen i++;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(i < count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen next_uid = uid_filter[i].seq1;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (next_uid != mail->uid) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen seq_range_array_add_range(expunged_uids,
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen next_uid,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail->uid - 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch if (uid_filter[i].seq2 != mail->uid)
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch next_uid = mail->uid + 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else if (++i < count)
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen next_uid = uid_filter[i].seq1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen break;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (i < count) {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen i_assert(next_uid <= uid_filter[i].seq2);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen seq_range_array_add_range(expunged_uids, next_uid,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen uid_filter[i].seq2);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen i++;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen }
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen for (; i < count; i++) {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen seq_range_array_add_range(expunged_uids, uid_filter[i].seq1,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen uid_filter[i].seq2);
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch }
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mailbox_get_open_status(box, STATUS_UIDNEXT, &status);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen seq_range_array_remove_range(expunged_uids, status.uidnext,
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen (uint32_t)-1);
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen if (mailbox_search_deinit(&search_ctx) < 0)
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen ret = -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret == 0 && qresync_args->qresync_sample_seqset != NULL &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_is_created(qresync_args->qresync_sample_seqset))
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen expunges_drop_known(box, qresync_args, trans, expunged_uids);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)mailbox_transaction_commit(&trans);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenint imap_fetch_send_vanished(struct client *client, struct mailbox *box,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const struct mail_search_args *search_args,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const struct imap_fetch_qresync_args *qresync_args)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_search_arg *uidarg = search_args->args;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_search_arg *modseqarg = uidarg->next;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const ARRAY_TYPE(seq_range) *uid_filter;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen uint64_t modseq;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ARRAY_TYPE(seq_range) expunged_uids_range;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen string_t *str;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen int ret = 0;
b9dc21a94401638c00e40b695998875e1563ce77Timo Sirainen
b9dc21a94401638c00e40b695998875e1563ce77Timo Sirainen i_assert(uidarg->type == SEARCH_UIDSET);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_assert(modseqarg->type == SEARCH_MODSEQ);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
27ca6cb0548c6478005c77d04be641356ec7d83cTimo Sirainen uid_filter = &uidarg->value.seqset;
27ca6cb0548c6478005c77d04be641356ec7d83cTimo Sirainen modseq = modseqarg->value.modseq->modseq - 1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_array_init(&expunged_uids_range, array_count(uid_filter));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (!mailbox_get_expunged_uids(box, modseq, uid_filter, &expunged_uids_range)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* return all expunged UIDs */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (get_expunges_fallback(box, qresync_args, uid_filter,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen &expunged_uids_range) < 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen array_clear(&expunged_uids_range);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ret = -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (array_count(&expunged_uids_range) > 0) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen str = str_new(default_pool, 128);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen str_append(str, "* VANISHED (EARLIER) ");
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen imap_write_seq_range(str, &expunged_uids_range);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen str_append(str, "\r\n");
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen str_free(&str);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_free(&expunged_uids_range);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void imap_fetch_init(struct imap_fetch_context *ctx)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ctx->initialized)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen return;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen ctx->initialized = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (ctx->flags_update_seen && !ctx->flags_have_handler) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen ctx->flags_show_only_seen_changes = TRUE;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen imap_fetch_init_nofail_handler(ctx, imap_fetch_flags_init);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if ((ctx->fetch_data &
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen ctx->fetch_data |= MAIL_FETCH_NUL_STATE;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx, struct mailbox *box,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct mail_search_args *search_args)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers = NULL;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen const char *const *headers;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen i_assert(!ctx->state.fetching);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen imap_fetch_init(ctx);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_zero(&ctx->state);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (array_count(&ctx->all_headers) > 0 &&
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen MAIL_FETCH_STREAM_BODY)) == 0)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_append_zero(&ctx->all_headers);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen headers = array_idx(&ctx->all_headers, 0);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen wanted_headers = mailbox_header_lookup_init(box, headers);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen array_delete(&ctx->all_headers,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen array_count(&ctx->all_headers)-1, 1);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->state.trans = mailbox_transaction_begin(box,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAILBOX_TRANSACTION_FLAG_HIDE |
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen MAILBOX_TRANSACTION_FLAG_REFRESH);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_search_args_init(search_args, box, TRUE,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen &ctx->client->search_saved_uidset);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ctx->state.search_ctx =
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mailbox_search_init(ctx->state.trans, search_args, NULL,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ctx->fetch_data, wanted_headers);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ctx->state.cur_str = str_new(default_pool, 8192);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ctx->state.fetching = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ctx->state.line_finished = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (wanted_headers != NULL)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mailbox_header_lookup_unref(&wanted_headers);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen const unsigned char *data;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen size_t len;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen data = str_data(ctx->state.cur_str);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen len = str_len(ctx->state.cur_str);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (len == 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* there's an extra space at the end if we added any fetch items
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen to buffer */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (data[len-1] == ' ') {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen len--;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ctx->state.cur_first = FALSE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ctx->state.cur_flushed = TRUE;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen str_truncate(ctx->state.cur_str, 0);
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen return 0;
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen}
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen{
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen const struct imap_fetch_context_handler *handler;
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen if (!ctx->state.cur_first)
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen str_append_c(ctx->state.cur_str, ' ');
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen handler = array_idx(&ctx->handlers, ctx->state.cur_handler);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen str_printfa(ctx->state.cur_str, "%s %s ",
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen handler->name, handler->nil_reply);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (!handler->buffered) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic int imap_fetch_more_int(struct imap_fetch_context *ctx, bool cancel)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen struct imap_fetch_state *state = &ctx->state;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen struct client *client = ctx->client;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen const struct imap_fetch_context_handler *handlers;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen unsigned int count;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen int ret;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (state->cont_handler != NULL) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ret = state->cont_handler(ctx);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (ret == 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret < 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (client->output->closed)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (state->cur_mail->expunged) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* not an error, just lost it. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen state->skipped_expunged_msgs = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen } else {
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen return -1;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen state->cont_handler = NULL;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen state->cur_handler++;
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen if (state->cur_input != NULL)
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen i_stream_unref(&state->cur_input);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen handlers = array_get(&ctx->handlers, &count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (;;) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen CLIENT_OUTPUT_OPTIMAL_SIZE) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ret = o_stream_flush(client->output);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret <= 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return ret;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (state->cur_mail == NULL) {
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (cancel)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (!mailbox_search_next(state->search_ctx,
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen &state->cur_mail))
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen break;
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen str_printfa(state->cur_str, "* %u FETCH (",
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen state->cur_mail->seq);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen state->cur_first = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen state->cur_flushed = FALSE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen state->line_finished = FALSE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen for (; state->cur_handler < count; state->cur_handler++) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (str_len(state->cur_str) > 0 &&
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen !handlers[state->cur_handler].buffered) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* first non-buffered handler.
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen flush the buffer. */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen state->line_partial = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen i_assert(state->cur_input == NULL);
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen T_BEGIN {
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen const struct imap_fetch_context_handler *h =
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen &handlers[state->cur_handler];
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen ret = h->handler(ctx, state->cur_mail,
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen h->context);
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen } T_END;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (ret == 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (ret < 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (state->cur_mail->expunged) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* not an error, just lost it. */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen state->skipped_expunged_msgs = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen } else {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(ret < 0 ||
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen state->cont_handler != NULL);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen state->cont_handler = NULL;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (state->cur_input != NULL)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_stream_unref(&state->cur_input);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (str_len(state->cur_str) > 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* no non-buffered handlers */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen return -1;
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen }
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen state->line_finished = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen state->line_partial = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen o_stream_nsend(client->output, ")\r\n", 3);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen client->last_output = ioloop_time;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen state->cur_mail = NULL;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen state->cur_handler = 0;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen }
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen}
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainenint imap_fetch_more(struct imap_fetch_context *ctx,
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen struct client_command_context *cmd)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(ctx->client->output_cmd_lock == NULL ||
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen ctx->client->output_cmd_lock == cmd);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen ret = imap_fetch_more_int(ctx, cmd->cancel);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (ret < 0)
b00c511e4675c4a1270d92924fc445cfb8631cf3Timo Sirainen ctx->state.failed = TRUE;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (ctx->state.line_partial) {
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen /* nothing can be sent until FETCH is finished */
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen ctx->client->output_cmd_lock = cmd;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen }
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (cmd->cancel && ctx->client->output_cmd_lock != NULL) {
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen /* canceling didn't really work. we must not output
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen anything anymore. */
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (!ctx->client->destroyed)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen client_disconnect(ctx->client, "Failed to cancel FETCH");
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen ctx->client->output_cmd_lock = NULL;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen }
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen return ret;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen}
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainenint imap_fetch_more_no_lock_update(struct imap_fetch_context *ctx)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen int ret;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen ret = imap_fetch_more_int(ctx, FALSE);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (ret < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->state.failed = TRUE;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (!ctx->state.line_finished) {
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen client_disconnect(ctx->client,
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen "NOTIFY failed in the middle of FETCH reply");
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen }
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen }
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen return ret;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen}
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint imap_fetch_end(struct imap_fetch_context *ctx)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen struct imap_fetch_state *state = &ctx->state;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen if (ctx->state.fetching) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ctx->state.fetching = FALSE;
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen if (!state->line_finished &&
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen (!state->cur_first || state->cur_flushed)) {
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen if (state->cur_first) {
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen /* we've flushed an empty "FETCH (" reply so
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen far. we can't take it back, but RFC 3501
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen doesn't allow returning empty "FETCH ()"
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen either, so just add the current message's
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen UID there. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_printfa(ctx->state.cur_str, "UID %u ",
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen state->cur_mail->uid);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen state->failed = TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen state->failed = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->client->output_cmd_lock = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (state->cur_str != NULL)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen str_free(&state->cur_str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (state->cur_input != NULL)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_stream_unref(&state->cur_input);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (state->search_ctx != NULL) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (mailbox_search_deinit(&state->search_ctx) < 0)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen state->failed = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch if (state->trans != NULL) {
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch /* even if something failed, we want to commit changes to
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch cache, as well as possible \Seen flag changes for FETCH
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen replies we returned so far. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mailbox_transaction_commit(&state->trans) < 0)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen state->failed = TRUE;
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen }
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen return state->failed ? -1 : 0;
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen}
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainenvoid imap_fetch_free(struct imap_fetch_context **_ctx)
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen{
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen struct imap_fetch_context *ctx = *_ctx;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen const struct imap_fetch_context_handler *handler;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen *_ctx = NULL;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen (void)imap_fetch_end(ctx);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen array_foreach(&ctx->handlers, handler) {
02a6291366caff79793db35d479e2a062bec2af4Timo Sirainen if (handler->want_deinit)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen handler->handler(ctx, NULL, handler->context);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen }
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen pool_unref(&ctx->ctx_pool);
573085b4b25b0bbae8d27969df2c91702eefa23eTimo Sirainen}
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen void *context ATTR_UNUSED)
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *body;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (mail_get_special(mail, MAIL_FETCH_IMAP_BODY, &body) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ctx->state.cur_first)
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen ctx->state.cur_first = FALSE;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen else {
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen return -1;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen }
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen o_stream_send_str(ctx->client->output, body) < 0 ||
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool fetch_body_init(struct imap_fetch_init_context *ctx)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen{
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen if (ctx->name[4] == '\0') {
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY")",
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen fetch_body, NULL);
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen return TRUE;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen }
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen return imap_fetch_body_section_init(ctx);
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen}
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen struct mail *mail, void *context ATTR_UNUSED)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen{
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen const char *bodystructure;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen &bodystructure) < 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen if (ctx->state.cur_first)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ctx->state.cur_first = FALSE;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen else {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen return -1;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen
8abe071cb14a622b9d84b00a9269f96d01a576f6Timo Sirainen return 1;
8abe071cb14a622b9d84b00a9269f96d01a576f6Timo Sirainen}
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainenstatic bool fetch_bodystructure_init(struct imap_fetch_init_context *ctx)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen{
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY" NIL NIL NIL NIL)",
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen fetch_bodystructure, NULL);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return TRUE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen void *context ATTR_UNUSED)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen const char *envelope;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE, &envelope) < 0)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return -1;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (ctx->state.cur_first)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ctx->state.cur_first = FALSE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen else {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return -1;
0992011130e9d0a498ca860ddbe4028398a530c5Timo Sirainen }
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen o_stream_send_str(ctx->client->output, envelope) < 0 ||
0992011130e9d0a498ca860ddbe4028398a530c5Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return -1;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return 1;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic bool fetch_envelope_init(struct imap_fetch_init_context *ctx)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen imap_fetch_add_handler(ctx, 0, ENVELOPE_NIL_REPLY,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen fetch_envelope, NULL);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return TRUE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen void *context ATTR_UNUSED)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen enum mail_flags flags;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const *keywords;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen flags = mail_get_flags(mail);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0 &&
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen !mailbox_is_readonly(mail->box)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Add \Seen flag */
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen ctx->state.seen_flags_changed = TRUE;
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen flags |= MAIL_SEEN;
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen } else if (ctx->flags_show_only_seen_changes) {
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen return 1;
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen }
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen mail_get_keyword_indexes(mail));
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen str_append(ctx->state.cur_str, "FLAGS (");
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen imap_write_flags(ctx->state.cur_str, flags, keywords);
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen str_append(ctx->state.cur_str, ") ");
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen return 1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenbool imap_fetch_flags_init(struct imap_fetch_init_context *ctx)
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->fetch_ctx->flags_have_handler = TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_FLAGS;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen "()", fetch_flags, NULL);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return TRUE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen void *context ATTR_UNUSED)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen time_t date;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (mail_get_received_date(mail, &date) < 0)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
878a83a906e1be6354b563ead096955a22ad5fbeTimo Sirainen str_printfa(ctx->state.cur_str, "INTERNALDATE \"%s\" ",
878a83a906e1be6354b563ead096955a22ad5fbeTimo Sirainen imap_to_datetime(date));
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return 1;
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen}
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainenstatic bool fetch_internaldate_init(struct imap_fetch_init_context *ctx)
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "\"01-Jan-1970 00:00:00 +0000\"",
705f6fbad395e6f014838e797b7dbcaceafd2f1dTimo Sirainen fetch_internaldate, NULL);
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen return TRUE;
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen}
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainenstatic int fetch_modseq(struct imap_fetch_context *ctx, struct mail *mail,
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen void *context ATTR_UNUSED)
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uint64_t modseq;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen modseq = mail_get_modseq(mail);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ctx->client->highest_fetch_modseq < modseq)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->client->highest_fetch_modseq = modseq;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen str_printfa(ctx->state.cur_str, "MODSEQ (%llu) ",
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen (unsigned long long)modseq);
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen return 1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainenbool imap_fetch_modseq_init(struct imap_fetch_init_context *ctx)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen{
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen if (ctx->fetch_ctx->client->nonpermanent_modseqs) {
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx->error = "FETCH MODSEQ can't be used with non-permanent modseqs";
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen return FALSE;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen }
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen (void)client_enable(ctx->fetch_ctx->client, MAILBOX_FEATURE_CONDSTORE);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen NULL, fetch_modseq, NULL);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen return TRUE;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen}
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainenstatic int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen void *context ATTR_UNUSED)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen{
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen str_printfa(ctx->state.cur_str, "UID %u ", mail->uid);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return 1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenbool imap_fetch_uid_init(struct imap_fetch_init_context *ctx)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen NULL, fetch_uid, NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return TRUE;
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
dbe06905918a415a34c5621b9fdf45be0b9c8e64Timo Sirainenstatic int fetch_guid(struct imap_fetch_context *ctx, struct mail *mail,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen void *context ATTR_UNUSED)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const char *value;
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainen
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_GUID, &value) < 0)
8d5c97bf940e43e8ec6e9f1ec8655f3b20edafbeTimo Sirainen return -1;
8d5c97bf940e43e8ec6e9f1ec8655f3b20edafbeTimo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen str_append(ctx->state.cur_str, "X-GUID ");
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen imap_append_astring(ctx->state.cur_str, value);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen str_append_c(ctx->state.cur_str, ' ');
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen return 1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic bool fetch_guid_init(struct imap_fetch_init_context *ctx)
762e17079d29d9f1838114ff5fec9ceaba8eb6a8Timo Sirainen{
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_GUID;
50349cd047ca9e7c100cbeb70acfe26672649959Timo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen "", fetch_guid, NULL);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int fetch_x_mailbox(struct imap_fetch_context *ctx, struct mail *mail,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen void *context ATTR_UNUSED)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const char *name;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen string_t *mutf7_name;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen if (mail_get_special(mail, MAIL_FETCH_MAILBOX_NAME, &name) < 0)
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen i_panic("mailbox name not returned");
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen mutf7_name = t_str_new(strlen(name)*2);
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainen if (imap_utf8_to_utf7(name, mutf7_name) < 0)
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainen i_panic("FETCH: Mailbox name not UTF-8: %s", name);
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainen
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainen str_append(ctx->state.cur_str, "X-MAILBOX ");
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen imap_append_astring(ctx->state.cur_str, str_c(mutf7_name));
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen str_append_c(ctx->state.cur_str, ' ');
dbe06905918a415a34c5621b9fdf45be0b9c8e64Timo Sirainen return 1;
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen}
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic bool fetch_x_mailbox_init(struct imap_fetch_init_context *ctx)
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen{
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen NULL, fetch_x_mailbox, NULL);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return TRUE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen}
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic int fetch_x_real_uid(struct imap_fetch_context *ctx, struct mail *mail,
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen void *context ATTR_UNUSED)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct mail *real_mail;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (mail_get_backend_mail(mail, &real_mail) < 0)
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainen return -1;
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainen str_printfa(ctx->state.cur_str, "X-REAL-UID %u ", real_mail->uid);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return 1;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic bool fetch_x_real_uid_init(struct imap_fetch_init_context *ctx)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen NULL, fetch_x_real_uid, NULL);
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen return TRUE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen}
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic int fetch_x_savedate(struct imap_fetch_context *ctx, struct mail *mail,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen void *context ATTR_UNUSED)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen time_t date;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_get_save_date(mail, &date) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen str_printfa(ctx->state.cur_str, "X-SAVEDATE \"%s\" ",
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen imap_to_datetime(date));
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainenstatic bool fetch_x_savedate_init(struct imap_fetch_init_context *ctx)
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen{
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_SAVE_DATE;
72f2a851238e5661695c63bff0e9a9e800ba577aTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen "\"01-Jan-1970 00:00:00 +0000\"",
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen fetch_x_savedate, NULL);
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen return TRUE;
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen}
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const struct imap_fetch_handler
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenimap_fetch_default_handlers[] = {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen { "BINARY", imap_fetch_binary_init },
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen { "BODY", fetch_body_init },
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen { "BODYSTRUCTURE", fetch_bodystructure_init },
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen { "ENVELOPE", fetch_envelope_init },
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen { "FLAGS", imap_fetch_flags_init },
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen { "INTERNALDATE", fetch_internaldate_init },
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen { "MODSEQ", imap_fetch_modseq_init },
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen { "RFC822", imap_fetch_rfc822_init },
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen { "UID", imap_fetch_uid_init },
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen { "X-GUID", fetch_guid_init },
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen { "X-MAILBOX", fetch_x_mailbox_init },
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen { "X-REAL-UID", fetch_x_real_uid_init },
705f6fbad395e6f014838e797b7dbcaceafd2f1dTimo Sirainen { "X-SAVEDATE", fetch_x_savedate_init }
b7835adbfddd8c92b51d6653fb759f963302fa78Timo Sirainen};
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainenvoid imap_fetch_handlers_init(void)
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainen{
8552b0cad8ffe9ccb8270577ba28b8010c89af11Timo Sirainen i_array_init(&fetch_handlers, 32);
98c3aa2587ad3e81e1548a3a4f79b2a24566cec3Timo Sirainen imap_fetch_handlers_register(imap_fetch_default_handlers,
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen N_ELEMENTS(imap_fetch_default_handlers));
72f2a851238e5661695c63bff0e9a9e800ba577aTimo Sirainen}
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainenvoid imap_fetch_handlers_deinit(void)
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen{
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen array_free(&fetch_handlers);
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen}
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen