imap-fetch.c revision de7dae07a080f9f0fe70a5ace618f78823954005
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen "\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic ARRAY_DEFINE(fetch_handlers, struct imap_fetch_handler);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
713a54f695b8ad63826d22ebbe52f55c347e8c88Timo Sirainen array_append(&fetch_handlers, handlers, count);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen array_sort(&fetch_handlers, imap_fetch_handler_cmp);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenimap_fetch_handler_bsearch(const char *name, const struct imap_fetch_handler *h)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenbool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *lookup_name, *p;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (p = name; i_isalnum(*p) || *p == '-'; p++) ;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen handler = array_bsearch(&fetch_handlers, lookup_name,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen t_strconcat("Unknown parameter ", name, NULL));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenimap_fetch_init(struct client_command_context *cmd, struct mailbox *box)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen p_array_init(&ctx->all_headers, cmd->pool, 64);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenbool imap_fetch_add_changed_since(struct imap_fetch_context *ctx,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen search_arg = p_new(ctx->search_args->pool, struct mail_search_arg, 1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen p_new(ctx->cmd->pool, struct mail_search_modseq, 1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen search_arg->value.modseq->modseq = modseq + 1;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen search_arg->next = ctx->search_args->args->next;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return imap_fetch_init_handler(ctx, "MODSEQ", NULL);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_context *ctx,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* partially because of broken clients, but also partially because
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen it potentially can make client implementations faster, we have a
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen buffered parameter which basically means that the handler promises
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen to write the output in ctx->cur_str. The cur_str is then sent to
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client before calling any non-buffered handlers.
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen We try to keep the handler registration order the same as the
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client requested them. This is especially useful to get UID
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen returned first, which some clients rely on..
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const struct imap_fetch_context_handler *handlers;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int i, size;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* don't allow duplicate handlers */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (i = 0; i < size; i++) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen memset(&h, 0, sizeof(h));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen h.nil_reply = p_strdup(ctx->cmd->pool, nil_reply);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen array_insert(&ctx->handlers, ctx->buffered_handlers_count,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenexpunges_drop_known(struct imap_fetch_context *ctx, struct mail *mail,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int i, count;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen seqs = array_get(ctx->qresync_sample_seqset, &count);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen uids = array_idx(ctx->qresync_sample_uidset, 0);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen i_assert(array_count(ctx->qresync_sample_uidset) == count);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen /* FIXME: we could do removals from the middle as well */
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen for (i = 0; i < count; i++) {
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen seq_range_array_remove_range(expunges, 1, uids[i-1]);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainenstatic int get_expunges_fallback(struct imap_fetch_context *ctx,
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen unsigned int i, count;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen /* search UIDs in given range */
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen i_array_init(&search_args->args->value.seqset, array_count(uids));
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen array_append_array(&search_args->args->value.seqset, uids);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen trans = mailbox_transaction_begin(ctx->box, 0);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen while (mailbox_search_next(search_ctx, mail) > 0) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen else if (++i < count)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen /* next_uid .. mail->uid-1 are expunged */
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen for (; i < count; i++) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen seq_range_array_add_range(expunges, uid_range[i].seq1,
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen mailbox_get_status(ctx->box, STATUS_UIDNEXT, &status);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen seq_range_array_remove_range(expunges, status.uidnext, (uint32_t)-1);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (ret == 0 && ctx->qresync_sample_seqset != NULL)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenmailbox_expunge_to_range(const ARRAY_TYPE(mailbox_expunge_rec) *input,
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen unsigned int i, count;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen for (i = 0; i < count; i++)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen seq_range_array_add(output, 0, expunges[i].uid);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenimap_fetch_send_vanished(struct imap_fetch_context *ctx)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen const struct mail_search_arg *uidarg = ctx->search_args->args;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen const struct mail_search_arg *modseqarg = uidarg->next;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen const ARRAY_TYPE(seq_range) *uids = &uidarg->value.seqset;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen uint64_t modseq = modseqarg->value.modseq->modseq - 1;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen i_array_init(&expunges_range, array_count(uids));
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (mailbox_get_expunges(ctx->box, modseq, uids, &expunges))
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen mailbox_expunge_to_range(&expunges, &expunges_range);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen /* return all expunged UIDs */
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (get_expunges_fallback(ctx, uids, &expunges_range) < 0) {
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen o_stream_send(ctx->client->output, str_data(str), str_len(str));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenint imap_fetch_begin(struct imap_fetch_context *ctx)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ctx->select_counter = ctx->client->select_counter;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ctx->mail = mail_alloc(ctx->trans, ctx->fetch_data,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* Delayed uidset -> seqset conversion. VANISHED needs the uidset. */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mail_search_args_init(ctx->search_args, ctx->box, TRUE,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mailbox_search_init(ctx->trans, ctx->search_args, NULL);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const unsigned char *data;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* there's an extra space at the end if we added any fetch items
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const struct imap_fetch_context_handler *handler;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen handler = array_idx(&ctx->handlers, ctx->cur_handler);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic int imap_fetch_more_int(struct imap_fetch_context *ctx)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const struct imap_fetch_context_handler *handlers;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int count;
if (ret < 0) {
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;
unsigned int i, count;
for (i = 0; i < count; i++) {
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 *str;
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)