imap-fetch.c revision 4c9745326e5e53447eb308ad613e08766703292b
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen "\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0"
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenstatic ARRAY_DEFINE(fetch_handlers, struct imap_fetch_handler);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenstatic int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen array_append(&fetch_handlers, handlers, count);
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen array_sort(&fetch_handlers, imap_fetch_handler_cmp);
4c892b0d94c5b1d6853dbe8e0b38059ea5b08ecaTimo Sirainenimap_fetch_handler_bsearch(const char *name, const struct imap_fetch_handler *h)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainenbool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen const char *lookup_name, *p;
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen for (p = name; i_isalnum(*p) || *p == '-'; p++) ;
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen handler = array_bsearch(&fetch_handlers, lookup_name,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen t_strconcat("Unknown parameter ", name, NULL));
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenimap_fetch_init(struct client_command_context *cmd, struct mailbox *box)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen p_array_init(&ctx->all_headers, cmd->pool, 64);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenbool imap_fetch_add_changed_since(struct imap_fetch_context *ctx,
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen search_arg = p_new(ctx->search_args->pool, struct mail_search_arg, 1);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen p_new(ctx->cmd->pool, struct mail_search_modseq, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen search_arg->value.modseq->modseq = modseq + 1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen search_arg->next = ctx->search_args->args->next;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return imap_fetch_init_handler(ctx, "MODSEQ", NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_context *ctx,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* partially because of broken clients, but also partially because
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen it potentially can make client implementations faster, we have a
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen buffered parameter which basically means that the handler promises
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen to write the output in ctx->cur_str. The cur_str is then sent to
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client before calling any non-buffered handlers.
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen We try to keep the handler registration order the same as the
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client requested them. This is especially useful to get UID
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen returned first, which some clients rely on..
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen const struct imap_fetch_context_handler *ctx_handler;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* don't allow duplicate handlers */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen memset(&h, 0, sizeof(h));
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen h.nil_reply = p_strdup(ctx->cmd->pool, nil_reply);
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen array_insert(&ctx->handlers, ctx->buffered_handlers_count,
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainenexpunges_drop_known(struct imap_fetch_context *ctx,
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen unsigned int i, count;
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen seqs = array_get(ctx->qresync_sample_seqset, &count);
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen uids = array_idx(ctx->qresync_sample_uidset, 0);
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen i_assert(array_count(ctx->qresync_sample_uidset) == count);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mailbox_get_open_status(ctx->box, STATUS_MESSAGES, &status);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* FIXME: we could do removals from the middle as well */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen for (i = 0; i < count && seqs[i] <= status.messages; i++) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen seq_range_array_remove_range(expunged_uids, 1, uids[i-1]);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic int get_expunges_fallback(struct imap_fetch_context *ctx,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen unsigned int i, count;
a2150da2dc906c26a26219cbefbe28a119aafee2Timo Sirainen uid_filter = array_get(uid_filter_arr, &count);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* search UIDs only in given range */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_array_init(&search_args->args->value.seqset, count);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen array_append_array(&search_args->args->value.seqset, uid_filter_arr);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen trans = mailbox_transaction_begin(ctx->box, 0);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen else if (++i < count)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* next_uid .. mail->uid-1 are expunged */
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen else if (++i < count)
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen seq_range_array_add_range(expunged_uids, next_uid,
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen for (; i < count; i++) {
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen seq_range_array_add_range(expunged_uids, uid_filter[i].seq1,
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen mailbox_get_open_status(ctx->box, STATUS_UIDNEXT, &status);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen seq_range_array_remove_range(expunged_uids, status.uidnext,
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen if (ret == 0 && ctx->qresync_sample_seqset != NULL &&
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen expunges_drop_known(ctx, trans, expunged_uids);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenimap_fetch_send_vanished(struct imap_fetch_context *ctx)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen const struct mail_search_arg *uidarg = ctx->search_args->args;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen const struct mail_search_arg *modseqarg = uidarg->next;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen const ARRAY_TYPE(seq_range) *uid_filter = &uidarg->value.seqset;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen uint64_t modseq = modseqarg->value.modseq->modseq - 1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_array_init(&expunged_uids_range, array_count(uid_filter));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!mailbox_get_expunged_uids(ctx->box, modseq, uid_filter, &expunged_uids_range)) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* return all expunged UIDs */
5e751dbaecf7c337abc149f328c4a13ee5c15134Timo Sirainen imap_write_seq_range(str, &expunged_uids_range);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen o_stream_send(ctx->client->output, str_data(str), str_len(str));
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainenint imap_fetch_begin(struct imap_fetch_context *ctx)
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen ctx->select_counter = ctx->client->select_counter;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* Delayed uidset -> seqset conversion. VANISHED needs the uidset. */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen mail_search_args_init(ctx->search_args, ctx->box, TRUE,
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen mailbox_search_init(ctx->trans, ctx->search_args, NULL,
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen const unsigned char *data;
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen /* there's an extra space at the end if we added any fetch items
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen const struct imap_fetch_context_handler *handler;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen handler = array_idx(&ctx->handlers, ctx->cur_handler);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainenstatic int imap_fetch_more_int(struct imap_fetch_context *ctx)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen const struct imap_fetch_context_handler *handlers;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen unsigned int count;
if (ret <= 0)
return ret;
T_BEGIN {
const struct imap_fetch_context_handler *h =
h->context);
} T_END;
if (ret == 0)
if (ret < 0) {
int ret;
if (ret < 0)
return ret;
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;
const char *name,
return TRUE;
const char *name,
return TRUE;
return TRUE;
static const struct imap_fetch_handler
void imap_fetch_handlers_init(void)
void imap_fetch_handlers_deinit(void)