imap-fetch.c revision 6f84506cf692d4f4f1ac69498e936b27dabdb60c
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic ARRAY_DEFINE(fetch_handlers, struct imap_fetch_handler);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen array_append(&fetch_handlers, handlers, count);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen array_sort(&fetch_handlers, imap_fetch_handler_cmp);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenimap_fetch_handler_bsearch(const char *name, const struct imap_fetch_handler *h)
942302b0247403645394d848b3c620ead262a2a5Timo Sirainenbool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx)
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen const char *lookup_name, *p;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (p = init_ctx->name; i_isalnum(*p) || *p == '-'; p++) ;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen lookup_name = t_strdup_until(init_ctx->name, p);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen handler = array_bsearch(&fetch_handlers, lookup_name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen init_ctx->error = t_strdup_printf("Unknown parameter: %s",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen bool (*init)(struct imap_fetch_init_context *))
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenimap_fetch_alloc(struct client *client, pool_t pool)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx = p_new(pool, struct imap_fetch_context, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid imap_fetch_add_changed_since(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen search_arg = p_new(ctx->search_args->pool, struct mail_search_arg, 1);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen p_new(ctx->search_args->pool, struct mail_search_modseq, 1);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen search_arg->value.modseq->modseq = modseq + 1;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen search_arg->next = ctx->search_args->args->next;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen imap_fetch_init_nofail_handler(ctx, imap_fetch_modseq_init);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_init_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* partially because of broken clients, but also partially because
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen it potentially can make client implementations faster, we have a
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen buffered parameter which basically means that the handler promises
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen to write the output in fetch_ctx->state.cur_str. The cur_str is then
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen sent to client before calling any non-buffered handlers.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen We try to keep the handler registration order the same as the
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen client requested them. This is especially useful to get UID
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen returned first, which some clients rely on..
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen const struct imap_fetch_context_handler *ctx_handler;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen /* don't allow duplicate handlers */
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen array_foreach(&ctx->fetch_ctx->handlers, ctx_handler) {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen memset(&h, 0, sizeof(h));
09773218272c490c3ad1572a6579703d7c35344cTimo Sirainen h.buffered = (flags & IMAP_FETCH_HANDLER_FLAG_BUFFERED) != 0;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen h.want_deinit = (flags & IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT) != 0;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen array_append(&ctx->fetch_ctx->handlers, &h, 1);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen ctx->fetch_ctx->buffered_handlers_count, &h, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_qresync_args *qresync_args,
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen unsigned int i, count;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen seqs = array_get(qresync_args->qresync_sample_seqset, &count);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen uids = array_idx(qresync_args->qresync_sample_uidset, 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(array_count(qresync_args->qresync_sample_uidset) == count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_get_open_status(box, STATUS_MESSAGES, &status);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* FIXME: we could do removals from the middle as well */
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen for (i = 0; i < count && seqs[i] <= status.messages; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen seq_range_array_remove_range(expunged_uids, 1, uids[i-1]);
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen const struct imap_fetch_qresync_args *qresync_args,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen unsigned int i, count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uid_filter = array_get(uid_filter_arr, &count);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* search UIDs only in given range */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_array_init(&search_args->args->value.seqset, count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_append_array(&search_args->args->value.seqset, uid_filter_arr);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen else if (++i < count)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* next_uid .. mail->uid-1 are expunged */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen else if (++i < count)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen seq_range_array_add_range(expunged_uids, next_uid,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (; i < count; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen seq_range_array_add_range(expunged_uids, uid_filter[i].seq1,
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen mailbox_get_open_status(box, STATUS_UIDNEXT, &status);
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen seq_range_array_remove_range(expunged_uids, status.uidnext,
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen if (ret == 0 && qresync_args->qresync_sample_seqset != NULL &&
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen array_is_created(qresync_args->qresync_sample_seqset))
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainen expunges_drop_known(box, qresync_args, trans, expunged_uids);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint imap_fetch_send_vanished(struct client *client, struct mailbox *box,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen const struct imap_fetch_qresync_args *qresync_args)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen const struct mail_search_arg *uidarg = search_args->args;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mail_search_arg *modseqarg = uidarg->next;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen i_array_init(&expunged_uids_range, array_count(uid_filter));
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (!mailbox_get_expunged_uids(box, modseq, uid_filter, &expunged_uids_range)) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen /* return all expunged UIDs */
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (get_expunges_fallback(box, qresync_args, uid_filter,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_write_seq_range(str, &expunged_uids_range);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void imap_fetch_init(struct imap_fetch_context *ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ctx->flags_update_seen && !ctx->flags_have_handler) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_init_nofail_handler(ctx, imap_fetch_flags_init);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenimap_fetch_begin_full(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_header_lookup_ctx *wanted_headers = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *headers;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen wanted_headers = mailbox_header_lookup_init(box, headers);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.trans = mailbox_transaction_begin(box,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* fetch can be executed multiple times.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen clone the search args for this fetch */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen search_args = mail_search_args_dup(ctx->search_args);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_search_init(ctx->state.trans, search_args, NULL,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.cur_str = str_new(default_pool, 8192);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx, struct mailbox *box)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid imap_fetch_begin_once(struct imap_fetch_context *ctx, struct mailbox *box)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const unsigned char *data;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* there's an extra space at the end if we added any fetch items
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_context_handler *handler;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen handler = array_idx(&ctx->handlers, ctx->state.cur_handler);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int imap_fetch_more_int(struct imap_fetch_context *ctx, bool cancel)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_context_handler *handlers;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int count;
c48f32afa608cb0aeef8f34bc2c61271ff394364Timo Sirainen /* not an error, just lost it. */
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen for (; state->cur_handler < count; state->cur_handler++) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen /* first non-buffered handler.
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen flush the buffer. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* not an error, just lost it. */
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen /* no non-buffered handlers */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint imap_fetch_more(struct imap_fetch_context *ctx,
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen /* nothing can be sent until FETCH is finished */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint imap_fetch_end(struct imap_fetch_context *ctx)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen if (mailbox_search_deinit(&state->search_ctx) < 0)
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen /* even if something failed, we want to commit changes to
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen cache, as well as possible \Seen flag changes for FETCH
6c40fee25bda974c0502e32ca70ca8ebb1c88a76Timo Sirainen replies we returned so far. */
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen if (mailbox_transaction_commit(&state->trans) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid imap_fetch_free(struct imap_fetch_context **_ctx)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen const struct imap_fetch_context_handler *handler;
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen handler->handler(ctx, NULL, handler->context);
const char *body;
return TRUE;
const char *bodystructure;
&bodystructure) < 0)
return TRUE;
const char *envelope;
return TRUE;
const char *const *keywords;
return TRUE;
return TRUE;
(unsigned long long)modseq);
return TRUE;
return TRUE;
const char *value;
return TRUE;
const char *name;
return TRUE;
return TRUE;
return TRUE;
static const struct imap_fetch_handler
void imap_fetch_handlers_init(void)
void imap_fetch_handlers_deinit(void)