imap-fetch.c revision 88ea893b45d3ed8d68000921db9156c03cbe1b00
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "common.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "buffer.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "istream.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "ostream.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "str.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "message-send.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "message-size.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-date.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "commands.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-fetch.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-util.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen#include <stdlib.h>
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenconst struct imap_fetch_handler default_handlers[7];
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic buffer_t *fetch_handlers = NULL;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic int imap_fetch_handler_cmp(const void *p1, const void *p2)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const struct imap_fetch_handler *h1 = p1, *h2 = p2;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return strcmp(h1->name, h2->name);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen size_t count)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen void *data;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen size_t size;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (fetch_handlers == NULL)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen fetch_handlers = buffer_create_dynamic(default_pool, 128);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen buffer_append(fetch_handlers, handlers, sizeof(*handlers) * count);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
5a0ac2e5ef482016e00575a7dce83f52c1704732Timo Sirainen data = buffer_get_modifyable_data(fetch_handlers, &size);
5a0ac2e5ef482016e00575a7dce83f52c1704732Timo Sirainen qsort(data, size / sizeof(*handlers), sizeof(*handlers),
7823ef73e51bb81a17dcb306aff89016d4ce258fTimo Sirainen imap_fetch_handler_cmp);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic int imap_fetch_handler_bsearch(const void *name_p, const void *handler_p)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char *name = name_p;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const struct imap_fetch_handler *h = handler_p;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen int i;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (i = 0; h->name[i] != '\0'; i++) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (h->name[i] != name[i]) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (name[i] < 'A' || name[i] >= 'Z')
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return name[i] - h->name[i];
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return name[i] < 'A' || name[i] >= 'Z' ? 0 : -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenint imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct imap_arg **args)
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const struct imap_fetch_handler *handler;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen handler = bsearch(name, fetch_handlers->data,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen fetch_handlers->used /
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen sizeof(struct imap_fetch_handler),
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen sizeof(struct imap_fetch_handler),
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen imap_fetch_handler_bsearch);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (handler == NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_send_command_error(ctx->cmd,
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen t_strconcat("Unknown command ", name, NULL));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen return handler->init(ctx, name, args);
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen}
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainenstruct imap_fetch_context *imap_fetch_init(struct client_command_context *cmd)
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen{
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen struct client *client = cmd->client;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct imap_fetch_context *ctx;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (fetch_handlers == NULL) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen imap_fetch_handlers_register(default_handlers,
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen sizeof(default_handlers) /
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen sizeof(default_handlers[0]));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->client = client;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cmd = cmd;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ctx->box = client->mailbox;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cur_str = str_new(default_pool, 8192);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->all_headers_buf = buffer_create_dynamic(cmd->pool, 128);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ARRAY_CREATE(&ctx->handlers, cmd->pool,
7026c16186f543e11af12b8b87f396006db93297Timo Sirainen struct imap_fetch_context_handler, 16);
6cc5a850bb6c1769f4113009c2067e5a719175a0Timo Sirainen ctx->line_finished = TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return ctx;
7026c16186f543e11af12b8b87f396006db93297Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_context *ctx, int buffered,
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen imap_fetch_handler_t *handler, void *context)
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen{
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen /* partially because of broken clients, but also partially because
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen it potentially can make client implementations faster, we have a
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen buffered parameter which basically means that the handler promises
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen to write the output in ctx->cur_str. The cur_str is then sent to
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen client before calling any non-buffered handlers.
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen We try to keep the handler registration order the same as the
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen client requested them. This is especially useful to get UID
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen returned first, which some clients rely on..
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen */
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen const struct imap_fetch_context_handler *handlers;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen struct imap_fetch_context_handler h;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen unsigned int i, size;
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen if (context == NULL) {
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen /* don't allow duplicate handlers */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen handlers = array_get(&ctx->handlers, &size);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen for (i = 0; i < size; i++) {
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen if (handlers[i].handler == handler &&
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen handlers[i].context == NULL)
548d8f62722578f076b4944e30013675f2605206Timo Sirainen return;
98950c9167dc2fab6c13d6d4c968e1963ecd73d7Timo Sirainen }
98950c9167dc2fab6c13d6d4c968e1963ecd73d7Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen memset(&h, 0, sizeof(h));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen h.handler = handler;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen h.context = context;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen h.buffered = buffered;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
64c48ffb71f1cf99acf375768fde4cff9b512648Timo Sirainen if (!buffered)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_append(&ctx->handlers, &h, 1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen else {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_insert(&ctx->handlers, ctx->buffered_handlers_count,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen &h, 1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->buffered_handlers_count++;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct mail_search_arg *search_arg)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const void *null = NULL;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen const void *data;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ctx->flags_update_seen) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (mailbox_is_readonly(ctx->box))
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->flags_update_seen = FALSE;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen else if (!ctx->flags_have_handler) {
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ctx->flags_show_only_seen_changes = TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen }
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (buffer_get_used_size(ctx->all_headers_buf) != 0 &&
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen MAIL_FETCH_STREAM_BODY)) == 0)) {
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen buffer_append(ctx->all_headers_buf, &null, sizeof(null));
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen data = buffer_get_data(ctx->all_headers_buf, NULL);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ctx->all_headers_ctx =
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen mailbox_header_lookup_init(ctx->box, data);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box,
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen MAILBOX_TRANSACTION_FLAG_HIDE);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ctx->select_counter = ctx->client->select_counter;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ctx->mail = mail_alloc(ctx->trans, ctx->fetch_data,
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ctx->all_headers_ctx);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ctx->search_ctx =
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen mailbox_search_init(ctx->trans, NULL, search_arg, NULL);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen}
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen{
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen const unsigned char *data;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen size_t len;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen i_assert(ctx->first);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen data = str_data(ctx->cur_str);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen len = str_len(ctx->cur_str);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen /* there's an extra space at the end if we added any fetch items
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen to buffer */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (data[len-1] == ' ') {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen len--;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->first = FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_truncate(ctx->cur_str, 0);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenint imap_fetch(struct imap_fetch_context *ctx)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const struct imap_fetch_context_handler *handlers;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen unsigned int size;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen int ret;
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen if (ctx->cont_handler != NULL) {
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen ret = ctx->cont_handler(ctx);
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen if (ret == 0)
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen return 0;
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen if (ret < 0) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ctx->cur_mail->expunged) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* not an error, just lost it. */
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen ctx->partial_fetch = TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->partial_fetch = TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen } else {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cont_handler = NULL;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cur_offset = 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cur_handler++;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen handlers = array_get(&ctx->handlers, &size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (;;) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (o_stream_get_buffer_used_size(ctx->client->output) >=
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen CLIENT_OUTPUT_OPTIMAL_SIZE) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ret = o_stream_flush(ctx->client->output);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ret <= 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return ret;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ctx->cur_mail == NULL) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (ctx->cur_input != NULL) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen i_stream_unref(ctx->cur_input);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cur_input = NULL;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen
6cc5a850bb6c1769f4113009c2067e5a719175a0Timo Sirainen if (mailbox_search_next(ctx->search_ctx,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->mail) <= 0)
6cc5a850bb6c1769f4113009c2067e5a719175a0Timo Sirainen break;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cur_mail = ctx->mail;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_printfa(ctx->cur_str, "* %u FETCH (",
7026c16186f543e11af12b8b87f396006db93297Timo Sirainen ctx->cur_mail->seq);
7026c16186f543e11af12b8b87f396006db93297Timo Sirainen ctx->first = TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->line_finished = FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (; ctx->cur_handler < size; ctx->cur_handler++) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (str_len(ctx->cur_str) > 0 &&
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen !handlers[ctx->cur_handler].buffered) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* first non-buffered handler.
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen flush the buffer. */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen t_push();
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ret = handlers[ctx->cur_handler].
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen handler(ctx, ctx->cur_mail,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen handlers[ctx->cur_handler].context);
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen t_pop();
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ret == 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ret < 0) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ctx->cur_mail->expunged) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* not an error, just lost it. */
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen ctx->partial_fetch = TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen } else {
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen i_assert(ret < 0 ||
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen ctx->cont_handler != NULL);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cont_handler = NULL;
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen ctx->cur_offset = 0;
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen }
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen if (str_len(ctx->cur_str) > 0) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* no non-buffered handlers */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->line_finished = TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx->cur_mail = NULL;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen ctx->cur_handler = 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return 1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenint imap_fetch_deinit(struct imap_fetch_context *ctx)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_free(ctx->cur_str);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (!ctx->line_finished) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen ctx->failed = TRUE;
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen }
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen
9511a40d933181045343110c8101b75887062aaeTimo Sirainen if (ctx->cur_input != NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_unref(ctx->cur_input);
ctx->cur_input = NULL;
}
if (ctx->mail != NULL)
mail_free(ctx->mail);
if (ctx->search_ctx != NULL) {
if (mailbox_search_deinit(ctx->search_ctx) < 0)
ctx->failed = TRUE;
}
if (ctx->all_headers_ctx != NULL)
mailbox_header_lookup_deinit(ctx->all_headers_ctx);
if (ctx->trans != NULL) {
if (ctx->failed)
mailbox_transaction_rollback(ctx->trans);
else {
if (mailbox_transaction_commit(ctx->trans, 0) < 0)
ctx->failed = TRUE;
}
}
return ctx->failed ? -1 : 0;
}
static int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
void *context __attr_unused__)
{
const char *body;
body = mail_get_special(mail, MAIL_FETCH_IMAP_BODY);
if (body == NULL)
return -1;
if (ctx->first)
ctx->first = FALSE;
else {
if (o_stream_send(ctx->client->output, " ", 1) < 0)
return -1;
}
if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
o_stream_send_str(ctx->client->output, body) < 0 ||
o_stream_send(ctx->client->output, ")", 1) < 0)
return -1;
return 1;
}
static int fetch_body_init(struct imap_fetch_context *ctx, const char *name,
struct imap_arg **args)
{
if (name[4] == '\0') {
ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
imap_fetch_add_handler(ctx, FALSE, fetch_body, NULL);
return TRUE;
}
return fetch_body_section_init(ctx, name, args);
}
static int fetch_bodystructure(struct imap_fetch_context *ctx,
struct mail *mail, void *context __attr_unused__)
{
const char *bodystructure;
bodystructure = mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE);
if (bodystructure == NULL)
return -1;
if (ctx->first)
ctx->first = FALSE;
else {
if (o_stream_send(ctx->client->output, " ", 1) < 0)
return -1;
}
if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
o_stream_send(ctx->client->output, ")", 1) < 0)
return -1;
return 1;
}
static int fetch_bodystructure_init(struct imap_fetch_context *ctx,
const char *name __attr_unused__,
struct imap_arg **args __attr_unused__)
{
ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
imap_fetch_add_handler(ctx, FALSE, fetch_bodystructure, NULL);
return TRUE;
}
static int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
void *context __attr_unused__)
{
const char *envelope;
envelope = mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE);
if (envelope == NULL)
return -1;
if (ctx->first)
ctx->first = FALSE;
else {
if (o_stream_send(ctx->client->output, " ", 1) < 0)
return -1;
}
if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
o_stream_send_str(ctx->client->output, envelope) < 0 ||
o_stream_send(ctx->client->output, ")", 1) < 0)
return -1;
return 1;
}
static int fetch_envelope_init(struct imap_fetch_context *ctx,
const char *name __attr_unused__,
struct imap_arg **args __attr_unused__)
{
ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
imap_fetch_add_handler(ctx, FALSE, fetch_envelope, NULL);
return TRUE;
}
static int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
void *context __attr_unused__)
{
enum mail_flags flags;
const char *const *keywords;
flags = mail_get_flags(mail);
keywords = mail_get_keywords(mail);
if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
/* Add \Seen flag */
flags |= MAIL_SEEN;
if (mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN) < 0)
return -1;
} else if (ctx->flags_show_only_seen_changes) {
return 1;
}
str_append(ctx->cur_str, "FLAGS (");
imap_write_flags(ctx->cur_str, flags, keywords);
str_append(ctx->cur_str, ") ");
return 1;
}
static int fetch_flags_init(struct imap_fetch_context *ctx,
const char *name __attr_unused__,
struct imap_arg **args __attr_unused__)
{
ctx->flags_have_handler = TRUE;
ctx->fetch_data |= MAIL_FETCH_FLAGS;
imap_fetch_add_handler(ctx, TRUE, fetch_flags, NULL);
return TRUE;
}
static int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail,
void *context __attr_unused__)
{
time_t time;
time = mail_get_received_date(mail);
if (time == (time_t)-1)
return -1;
str_printfa(ctx->cur_str, "INTERNALDATE \"%s\" ",
imap_to_datetime(time));
return 1;
}
static int fetch_internaldate_init(struct imap_fetch_context *ctx,
const char *name __attr_unused__,
struct imap_arg **args __attr_unused__)
{
ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
imap_fetch_add_handler(ctx, TRUE, fetch_internaldate, NULL);
return TRUE;
}
static int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
void *context __attr_unused__)
{
str_printfa(ctx->cur_str, "UID %u ", mail->uid);
return 1;
}
static int fetch_uid_init(struct imap_fetch_context *ctx __attr_unused__,
const char *name __attr_unused__,
struct imap_arg **args __attr_unused__)
{
imap_fetch_add_handler(ctx, TRUE, fetch_uid, NULL);
return TRUE;
}
const struct imap_fetch_handler default_handlers[7] = {
{ "BODY", fetch_body_init },
{ "BODYSTRUCTURE", fetch_bodystructure_init },
{ "ENVELOPE", fetch_envelope_init },
{ "FLAGS", fetch_flags_init },
{ "INTERNALDATE", fetch_internaldate_init },
{ "RFC822", fetch_rfc822_init },
{ "UID", fetch_uid_init }
};