imap-fetch.c revision 43d32cbe60fdaef2699d99f1ca259053e9350411
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "common.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen#include "buffer.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "istream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "ostream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "str.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "message-send.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "message-size.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "imap-date.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "commands.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "imap-fetch.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-util.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen#include <stdlib.h>
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen#define BODY_NIL_REPLY \
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen "\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0 NIL NIL NIL"
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
4bbb027a827d27d1816b8d60c5392cfd9c79e4bdTimo Sirainenconst struct imap_fetch_handler default_handlers[7];
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic buffer_t *fetch_handlers = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int imap_fetch_handler_cmp(const void *p1, const void *p2)
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const struct imap_fetch_handler *h1 = p1, *h2 = p2;
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return strcmp(h1->name, h2->name);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen size_t count)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen void *data;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen size_t size;
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen if (fetch_handlers == NULL)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen fetch_handlers = buffer_create_dynamic(default_pool, 128);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen buffer_append(fetch_handlers, handlers, sizeof(*handlers) * count);
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen data = buffer_get_modifiable_data(fetch_handlers, &size);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen qsort(data, size / sizeof(*handlers), sizeof(*handlers),
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen imap_fetch_handler_cmp);
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen}
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int imap_fetch_handler_bsearch(const void *name_p, const void *handler_p)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *name = name_p;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const struct imap_fetch_handler *h = handler_p;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen int i;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (i = 0; h->name[i] != '\0'; i++) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (h->name[i] != name[i]) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (name[i] < 'A' || name[i] >= 'Z')
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return name[i] - h->name[i];
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return name[i] < 'A' || name[i] >= 'Z' ? 0 : -1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainen const struct imap_arg **args)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const struct imap_fetch_handler *handler;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen handler = bsearch(name, fetch_handlers->data,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen fetch_handlers->used /
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sizeof(struct imap_fetch_handler),
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sizeof(struct imap_fetch_handler),
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen imap_fetch_handler_bsearch);
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen if (handler == NULL) {
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen client_send_command_error(ctx->cmd,
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen t_strconcat("Unknown command ", name, NULL));
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen return FALSE;
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen return handler->init(ctx, name, args);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainenstruct imap_fetch_context *imap_fetch_init(struct client_command_context *cmd)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen struct client *client = cmd->client;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct imap_fetch_context *ctx;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (fetch_handlers == NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen imap_fetch_handlers_register(default_handlers,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sizeof(default_handlers) /
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sizeof(default_handlers[0]));
6389aeec8c26b585e583c364b48ad12adf741898Timo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->client = client;
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen ctx->cmd = cmd;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->box = client->mailbox;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->cur_str = str_new(default_pool, 8192);
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen ctx->all_headers_buf = buffer_create_dynamic(cmd->pool, 128);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen p_array_init(&ctx->handlers, cmd->pool, 16);
9c4e6f29ad07fbd27cb9ac510fa69f8c60709f1fTimo Sirainen ctx->line_finished = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return ctx;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen#undef imap_fetch_add_handler
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_context *ctx,
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen bool buffered, bool want_deinit,
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen const char *name, const char *nil_reply,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen imap_fetch_handler_t *handler, void *context)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* partially because of broken clients, but also partially because
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen it potentially can make client implementations faster, we have a
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen buffered parameter which basically means that the handler promises
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen to write the output in ctx->cur_str. The cur_str is then sent to
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen client before calling any non-buffered handlers.
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen We try to keep the handler registration order the same as the
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen client requested them. This is especially useful to get UID
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen returned first, which some clients rely on..
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const struct imap_fetch_context_handler *handlers;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct imap_fetch_context_handler h;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen unsigned int i, size;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (context == NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* don't allow duplicate handlers */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen handlers = array_get(&ctx->handlers, &size);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (i = 0; i < size; i++) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (handlers[i].handler == handler &&
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen handlers[i].context == NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen memset(&h, 0, sizeof(h));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen h.handler = handler;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen h.context = context;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen h.buffered = buffered;
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen h.want_deinit = want_deinit;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen h.name = p_strdup(ctx->cmd->pool, name);
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen h.nil_reply = p_strdup(ctx->cmd->pool, nil_reply);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (!buffered)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen array_append(&ctx->handlers, &h, 1);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen else {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen array_insert(&ctx->handlers, ctx->buffered_handlers_count,
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen &h, 1);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen ctx->buffered_handlers_count++;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct mail_search_arg *search_arg)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const void *null = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const void *data;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->flags_update_seen) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (mailbox_is_readonly(ctx->box))
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->flags_update_seen = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else if (!ctx->flags_have_handler) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->flags_show_only_seen_changes = TRUE;
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (buffer_get_used_size(ctx->all_headers_buf) != 0 &&
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen MAIL_FETCH_STREAM_BODY)) == 0)) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen buffer_append(ctx->all_headers_buf, &null, sizeof(null));
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen data = buffer_get_data(ctx->all_headers_buf, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->all_headers_ctx =
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen mailbox_header_lookup_init(ctx->box, data);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
87132ebf759dc7fe1f4b8aeb68c7d44be26eba42Timo Sirainen if ((ctx->fetch_data &
87132ebf759dc7fe1f4b8aeb68c7d44be26eba42Timo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
87132ebf759dc7fe1f4b8aeb68c7d44be26eba42Timo Sirainen ctx->fetch_data |= MAIL_FETCH_NUL_STATE;
87132ebf759dc7fe1f4b8aeb68c7d44be26eba42Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen MAILBOX_TRANSACTION_FLAG_HIDE);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->select_counter = ctx->client->select_counter;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ctx->mail = mail_alloc(ctx->trans, ctx->fetch_data,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ctx->all_headers_ctx);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->search_ctx =
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mailbox_search_init(ctx->trans, NULL, search_arg, NULL);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen{
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen const unsigned char *data;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen size_t len;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen data = str_data(ctx->cur_str);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen len = str_len(ctx->cur_str);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* there's an extra space at the end if we added any fetch items
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen to buffer */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (data[len-1] == ' ') {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen len--;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen ctx->first = FALSE;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen }
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return -1;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen str_truncate(ctx->cur_str, 0);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return 0;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen}
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen{
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen const struct imap_fetch_context_handler *handler;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (!ctx->first)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen str_append_c(ctx->cur_str, ' ');
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen handler = array_idx(&ctx->handlers, ctx->cur_handler);
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen str_printfa(ctx->cur_str, "%s %s ",
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen handler->name, handler->nil_reply);
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (!handler->buffered) {
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return -1;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen }
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return 0;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen}
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenint imap_fetch(struct imap_fetch_context *ctx)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen struct client *client = ctx->client;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const struct imap_fetch_context_handler *handlers;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen unsigned int count;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen int ret;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->cont_handler != NULL) {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen ret = ctx->cont_handler(ctx);
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (ret == 0)
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen return 0;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (ret < 0) {
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (ctx->client->output->closed)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return -1;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (ctx->cur_mail->expunged) {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen /* not an error, just lost it. */
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen ctx->partial_fetch = TRUE;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return -1;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen } else {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen return -1;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen }
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->cont_handler = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->cur_offset = 0;
07fe84e1db9fe5a79e815f000bd94ae61f5831dbTimo Sirainen ctx->cur_handler++;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen /* assume initially that we're locking it */
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen i_assert(client->output_lock == NULL ||
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen client->output_lock == ctx->cmd);
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen client->output_lock = ctx->cmd;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen handlers = array_get(&ctx->handlers, &count);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (;;) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen CLIENT_OUTPUT_OPTIMAL_SIZE) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen ret = o_stream_flush(client->output);
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (ret <= 0) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (!ctx->line_partial) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen /* last line was fully sent */
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen client->output_lock = NULL;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return ret;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->cur_mail == NULL) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (ctx->cmd->cancel)
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen return 1;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (ctx->cur_input != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_stream_unref(&ctx->cur_input);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (mailbox_search_next(ctx->search_ctx,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ctx->mail) <= 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ctx->cur_mail = ctx->mail;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_printfa(ctx->cur_str, "* %u FETCH (",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->cur_mail->seq);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->first = TRUE;
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen ctx->line_finished = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen for (; ctx->cur_handler < count; ctx->cur_handler++) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (str_len(ctx->cur_str) > 0 &&
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen !handlers[ctx->cur_handler].buffered) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* first non-buffered handler.
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen flush the buffer. */
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen ctx->line_partial = TRUE;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return -1;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen }
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen t_push();
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ret = handlers[ctx->cur_handler].
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen handler(ctx, ctx->cur_mail,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen handlers[ctx->cur_handler].context);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen t_pop();
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (ret == 0) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (!ctx->line_partial) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen /* last line was fully sent */
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen client->output_lock = NULL;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen }
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen return 0;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen }
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (ret < 0) {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (ctx->cur_mail->expunged) {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen /* not an error, just lost it. */
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen ctx->partial_fetch = TRUE;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return -1;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen } else {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen i_assert(ret < 0 ||
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen ctx->cont_handler != NULL);
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen return -1;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->cont_handler = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->cur_offset = 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (str_len(ctx->cur_str) > 0) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* no non-buffered handlers */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen ctx->line_finished = TRUE;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen ctx->line_partial = FALSE;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (o_stream_send(client->output, ")\r\n", 3) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
6e916cab4984d6386d0b2d366e5d23c11749d3a3Timo Sirainen ctx->client->last_output = ioloop_time;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->cur_mail = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->cur_handler = 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenint imap_fetch_deinit(struct imap_fetch_context *ctx)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen const struct imap_fetch_context_handler *handlers;
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen unsigned int i, count;
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen handlers = array_get(&ctx->handlers, &count);
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen for (i = 0; i < count; i++) {
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen if (handlers[i].want_deinit)
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen handlers[i].handler(ctx, NULL, handlers[i].context);
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen }
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen if (!ctx->line_finished) {
ac4b4c7436b9f6d90aaf2d25f6abb61469f5a818Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
f44d5610838aa97d9080f295b01c21c99c856624Timo Sirainen ctx->failed = TRUE;
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
1e62ad3955db977d527fa57d9584e504a8c26fd5Timo Sirainen ctx->failed = TRUE;
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen }
ac4b4c7436b9f6d90aaf2d25f6abb61469f5a818Timo Sirainen str_free(&ctx->cur_str);
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (ctx->cur_input != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_stream_unref(&ctx->cur_input);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (ctx->mail != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mail_free(&ctx->mail);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->search_ctx != NULL) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->failed = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->all_headers_ctx != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mailbox_header_lookup_deinit(&ctx->all_headers_ctx);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->trans != NULL) {
5eca7b6535c3e74fb98aef5c34f096d9252a8f46Timo Sirainen /* even if something failed, we want to commit changes to
5eca7b6535c3e74fb98aef5c34f096d9252a8f46Timo Sirainen cache, as well as possible \Seen flag changes for FETCH
5eca7b6535c3e74fb98aef5c34f096d9252a8f46Timo Sirainen replies we returned so far. */
5eca7b6535c3e74fb98aef5c34f096d9252a8f46Timo Sirainen if (mailbox_transaction_commit(&ctx->trans, 0) < 0)
5eca7b6535c3e74fb98aef5c34f096d9252a8f46Timo Sirainen ctx->failed = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return ctx->failed ? -1 : 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen const char *body;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODY, &body) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->first)
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen ctx->first = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen }
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send_str(ctx->client->output, body) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool fetch_body_init(struct imap_fetch_context *ctx, const char *name,
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainen const struct imap_arg **args)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen if (name[4] == '\0') {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name,
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen "("BODY_NIL_REPLY")", fetch_body, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen return fetch_body_section_init(ctx, name, args);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen struct mail *mail, void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen const char *bodystructure;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen &bodystructure) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->first)
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen ctx->first = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen }
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenstatic bool
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenfetch_bodystructure_init(struct imap_fetch_context *ctx, const char *name,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen const struct imap_arg **args ATTR_UNUSED)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name,
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen "("BODY_NIL_REPLY" NIL NIL NIL NIL)",
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen fetch_bodystructure, NULL);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen const char *envelope;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE, &envelope) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (ctx->first)
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen ctx->first = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen }
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send_str(ctx->client->output, envelope) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenstatic bool
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenfetch_envelope_init(struct imap_fetch_context *ctx, const char *name,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen const struct imap_arg **args ATTR_UNUSED)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name,
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)",
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen fetch_envelope, NULL);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen enum mail_flags flags;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const char *const *keywords;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen flags = mail_get_flags(mail);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen keywords = mail_get_keywords(mail);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* Add \Seen flag */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen flags |= MAIL_SEEN;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen } else if (ctx->flags_show_only_seen_changes) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_append(ctx->cur_str, "FLAGS (");
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen imap_write_flags(ctx->cur_str, flags, keywords);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_append(ctx->cur_str, ") ");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenstatic bool
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenfetch_flags_init(struct imap_fetch_context *ctx, const char *name,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen const struct imap_arg **args ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->flags_have_handler = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->fetch_data |= MAIL_FETCH_FLAGS;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, name, "()", fetch_flags, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen time_t date;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_received_date(mail, &date) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
73d29cffe84aa9742353c40516a09e18385ab341Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_printfa(ctx->cur_str, "INTERNALDATE \"%s\" ",
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen imap_to_datetime(date));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenstatic bool
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenfetch_internaldate_init(struct imap_fetch_context *ctx, const char *name,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen const struct imap_arg **args ATTR_UNUSED)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, name,
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen "\"01-01-1970 00:00:00 +0000\"",
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen fetch_internaldate, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_printfa(ctx->cur_str, "UID %u ", mail->uid);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenstatic bool
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenfetch_uid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen const struct imap_arg **args ATTR_UNUSED)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, fetch_uid, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
4bbb027a827d27d1816b8d60c5392cfd9c79e4bdTimo Sirainenconst struct imap_fetch_handler default_handlers[7] = {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "BODY", fetch_body_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "BODYSTRUCTURE", fetch_bodystructure_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "ENVELOPE", fetch_envelope_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "FLAGS", fetch_flags_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "INTERNALDATE", fetch_internaldate_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "RFC822", fetch_rfc822_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "UID", fetch_uid_init }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen};