imap-fetch.c revision dbcc1233028625274a8224b3efeca01d73dbbb4c
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen#include "common.h"
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen#include "array.h"
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen#include "buffer.h"
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen#include "istream.h"
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen#include "ostream.h"
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen#include "str.h"
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen#include "message-send.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#include "message-size.h"
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen#include "message-parser.h"
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen#include "imap-date.h"
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen#include "commands.h"
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen#include "imap-fetch.h"
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen#include "imap-util.h"
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen#include <stdlib.h>
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenconst struct imap_fetch_handler default_handlers[8];
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainenstatic buffer_t *fetch_handlers = NULL;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainenstatic int imap_fetch_handler_cmp(const void *p1, const void *p2)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const struct imap_fetch_handler *h1 = p1, *h2 = p2;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return strcmp(h1->name, h2->name);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen}
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen size_t count)
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen{
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen void *data;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen size_t size;
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen if (fetch_handlers == NULL)
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen fetch_handlers = buffer_create_dynamic(default_pool, 128);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen buffer_append(fetch_handlers, handlers, sizeof(*handlers) * count);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen data = buffer_get_modifiable_data(fetch_handlers, &size);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen qsort(data, size / sizeof(*handlers), sizeof(*handlers),
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen imap_fetch_handler_cmp);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen}
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainenstatic int imap_fetch_handler_bsearch(const void *name_p, const void *handler_p)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const char *name = name_p;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const struct imap_fetch_handler *h = handler_p;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int i;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; h->name[i] != '\0'; i++) {
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (h->name[i] != name[i]) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (name[i] < 'A' || name[i] >= 'Z')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return name[i] - h->name[i];
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen }
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen }
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return name[i] < 'A' || name[i] >= 'Z' ? 0 : -1;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen}
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainenbool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct imap_arg **args)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen const struct imap_fetch_handler *handler;
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen handler = bsearch(name, fetch_handlers->data,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen fetch_handlers->used /
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen sizeof(struct imap_fetch_handler),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen sizeof(struct imap_fetch_handler),
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen imap_fetch_handler_bsearch);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (handler == NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen client_send_command_error(ctx->cmd,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen t_strconcat("Unknown command ", name, NULL));
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return handler->init(ctx, name, args);
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainen}
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct imap_fetch_context *imap_fetch_init(struct client_command_context *cmd)
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct client *client = cmd->client;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen struct imap_fetch_context *ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fetch_handlers == NULL) {
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen imap_fetch_handlers_register(default_handlers,
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen sizeof(default_handlers) /
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen sizeof(default_handlers[0]));
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen }
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->client = client;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->cmd = cmd;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->box = client->mailbox;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cur_str = str_new(default_pool, 8192);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ctx->all_headers_buf = buffer_create_dynamic(cmd->pool, 128);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ARRAY_CREATE(&ctx->handlers, cmd->pool,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct imap_fetch_context_handler, 16);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ctx->line_finished = TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return ctx;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_context *ctx,
6237f743bbaf74de5a2d2051672baed87023657bTimo Sirainen bool buffered, bool want_deinit,
6237f743bbaf74de5a2d2051672baed87023657bTimo Sirainen imap_fetch_handler_t *handler, void *context)
6237f743bbaf74de5a2d2051672baed87023657bTimo Sirainen{
6237f743bbaf74de5a2d2051672baed87023657bTimo Sirainen /* partially because of broken clients, but also partially because
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen it potentially can make client implementations faster, we have a
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen buffered parameter which basically means that the handler promises
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen to write the output in ctx->cur_str. The cur_str is then sent to
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen client before calling any non-buffered handlers.
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen We try to keep the handler registration order the same as the
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen client requested them. This is especially useful to get UID
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen returned first, which some clients rely on..
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen */
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen const struct imap_fetch_context_handler *handlers;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen struct imap_fetch_context_handler h;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen unsigned int i, size;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (context == NULL) {
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen /* don't allow duplicate handlers */
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen handlers = array_get(&ctx->handlers, &size);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen for (i = 0; i < size; i++) {
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (handlers[i].handler == handler &&
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen handlers[i].context == NULL)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen }
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen }
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen memset(&h, 0, sizeof(h));
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen h.handler = handler;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen h.context = context;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen h.buffered = buffered;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen h.want_deinit = want_deinit;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (!buffered)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen array_append(&ctx->handlers, &h, 1);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen else {
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen array_insert(&ctx->handlers, ctx->buffered_handlers_count,
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen &h, 1);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen ctx->buffered_handlers_count++;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen }
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen}
c740209eb3db031022c6fd436fa2ef1aa0ec46b8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen struct mail_search_arg *search_arg)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const void *null = NULL;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen const void *data;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen if (ctx->flags_update_seen) {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen if (mailbox_is_readonly(ctx->box))
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->flags_update_seen = FALSE;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen else if (!ctx->flags_have_handler) {
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen ctx->flags_show_only_seen_changes = TRUE;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen }
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen }
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen if (buffer_get_used_size(ctx->all_headers_buf) != 0 &&
325d4ad220bd13f6d176391d962a0e33c856a7f6Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen MAIL_FETCH_STREAM_BODY)) == 0)) {
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen buffer_append(ctx->all_headers_buf, &null, sizeof(null));
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen data = buffer_get_data(ctx->all_headers_buf, NULL);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen ctx->all_headers_ctx =
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen mailbox_header_lookup_init(ctx->box, data);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen }
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen MAILBOX_TRANSACTION_FLAG_HIDE);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ctx->select_counter = ctx->client->select_counter;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ctx->mail = mail_alloc(ctx->trans, ctx->fetch_data,
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen ctx->all_headers_ctx);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen ctx->search_ctx =
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen mailbox_search_init(ctx->trans, NULL, search_arg, NULL);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen}
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen{
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen const unsigned char *data;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen size_t len;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen i_assert(ctx->first);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen data = str_data(ctx->cur_str);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen len = str_len(ctx->cur_str);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* there's an extra space at the end if we added any fetch items
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen to buffer */
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen if (data[len-1] == ' ') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen len--;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen ctx->first = FALSE;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen }
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return -1;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen str_truncate(ctx->cur_str, 0);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return 0;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen}
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainenint imap_fetch(struct imap_fetch_context *ctx)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen{
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen const struct imap_fetch_context_handler *handlers;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen unsigned int size;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen int ret;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (ctx->cont_handler != NULL) {
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen ret = ctx->cont_handler(ctx);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (ret == 0)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return 0;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ret < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ctx->cur_mail->expunged) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen /* not an error, just lost it. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx->partial_fetch = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx->partial_fetch = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return -1;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->cont_handler = NULL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->cur_offset = 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->cur_handler++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
aff7542e1d2f48b030560a4f01096a2cc3f671ceTimo Sirainen
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen handlers = array_get(&ctx->handlers, &size);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen for (;;) {
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (o_stream_get_buffer_used_size(ctx->client->output) >=
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen CLIENT_OUTPUT_OPTIMAL_SIZE) {
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen ret = o_stream_flush(ctx->client->output);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (ret <= 0)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen return ret;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen }
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen
aff7542e1d2f48b030560a4f01096a2cc3f671ceTimo Sirainen if (ctx->cur_mail == NULL) {
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (ctx->cur_input != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_unref(&ctx->cur_input);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (mailbox_search_next(ctx->search_ctx,
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen ctx->mail) <= 0)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen break;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen ctx->cur_mail = ctx->mail;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen str_printfa(ctx->cur_str, "* %u FETCH (",
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen ctx->cur_mail->seq);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->first = TRUE;
7416b94f38e82381abd9cee660efdcf3e7b773afTimo Sirainen ctx->line_finished = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen for (; ctx->cur_handler < size; ctx->cur_handler++) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (str_len(ctx->cur_str) > 0 &&
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen !handlers[ctx->cur_handler].buffered) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* first non-buffered handler.
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen flush the buffer. */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return -1;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen t_push();
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ret = handlers[ctx->cur_handler].
aff7542e1d2f48b030560a4f01096a2cc3f671ceTimo Sirainen handler(ctx, ctx->cur_mail,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen handlers[ctx->cur_handler].context);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen t_pop();
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (ret == 0)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen return 0;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen if (ret < 0) {
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen if (ctx->cur_mail->expunged) {
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen /* not an error, just lost it. */
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen ctx->partial_fetch = TRUE;
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen } else {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen i_assert(ret < 0 ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cont_handler != NULL);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen return -1;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen ctx->cont_handler = NULL;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen ctx->cur_offset = 0;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen }
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (str_len(ctx->cur_str) > 0) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen /* no non-buffered handlers */
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen return -1;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen }
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen ctx->line_finished = TRUE;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen return -1;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen ctx->cur_mail = NULL;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen ctx->cur_handler = 0;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen }
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen return 1;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen}
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainenint imap_fetch_deinit(struct imap_fetch_context *ctx)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen{
c18e2301f4c81f2819711661890db7796d4450c3Timo Sirainen const struct imap_fetch_context_handler *handlers;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen unsigned int i, count;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen handlers = array_get(&ctx->handlers, &count);
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen for (i = 0; i < count; i++) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (handlers[i].want_deinit)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen handlers[i].handler(ctx, NULL, handlers[i].context);
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen }
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen str_free(&ctx->cur_str);
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (!ctx->line_finished) {
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen ctx->failed = TRUE;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen if (ctx->cur_input != NULL)
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen i_stream_unref(&ctx->cur_input);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen
c740209eb3db031022c6fd436fa2ef1aa0ec46b8Timo Sirainen if (ctx->mail != NULL)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen mail_free(&ctx->mail);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (ctx->search_ctx != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen ctx->failed = TRUE;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen if (ctx->all_headers_ctx != NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mailbox_header_lookup_deinit(&ctx->all_headers_ctx);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ctx->trans != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ctx->failed)
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen mailbox_transaction_rollback(&ctx->trans);
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen else {
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen if (mailbox_transaction_commit(&ctx->trans, 0) < 0)
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen ctx->failed = TRUE;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ctx->failed ? -1 : 0;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen void *context __attr_unused__)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen{
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen const char *body;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen body = mail_get_special(mail, MAIL_FETCH_IMAP_BODY);
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (body == NULL)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen return -1;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen if (ctx->first)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen ctx->first = FALSE;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen else {
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return -1;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen }
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen o_stream_send_str(ctx->client->output, body) < 0 ||
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen return -1;
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen return 1;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen}
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainenstatic bool fetch_body_init(struct imap_fetch_context *ctx, const char *name,
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen struct imap_arg **args)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen{
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen if (name[4] == '\0') {
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_body, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen return fetch_body_section_init(ctx, name, args);
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen}
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen struct mail *mail, void *context __attr_unused__)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen{
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen const char *bodystructure;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen bodystructure = mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (bodystructure == NULL)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen return -1;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (ctx->first)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen ctx->first = FALSE;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen else {
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen return -1;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen }
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return -1;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return 1;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen}
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic bool fetch_bodystructure_init(struct imap_fetch_context *ctx,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen const char *name __attr_unused__,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen struct imap_arg **args __attr_unused__)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_bodystructure, NULL);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen return TRUE;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen}
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen void *context __attr_unused__)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen{
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen const char *envelope;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen envelope = mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (envelope == NULL)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen return -1;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen if (ctx->first)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen ctx->first = FALSE;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen else {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen return -1;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen }
365435901c22df7e5838f574c950b0e32e77f78aTimo Sirainen
365435901c22df7e5838f574c950b0e32e77f78aTimo Sirainen if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen o_stream_send_str(ctx->client->output, envelope) < 0 ||
365435901c22df7e5838f574c950b0e32e77f78aTimo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
365435901c22df7e5838f574c950b0e32e77f78aTimo Sirainen return -1;
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen return 1;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen}
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic bool fetch_envelope_init(struct imap_fetch_context *ctx,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen const char *name __attr_unused__,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen struct imap_arg **args __attr_unused__)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen{
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_envelope, NULL);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return TRUE;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen}
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen void *context __attr_unused__)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen{
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen enum mail_flags flags;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen const char *const *keywords;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen flags = mail_get_flags(mail);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen keywords = mail_get_keywords(mail);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen /* 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 bool 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, FALSE, 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 bool 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, FALSE, 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 bool 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, FALSE, fetch_uid, NULL);
return TRUE;
}
static uoff_t textsize_count(const struct message_part *part)
{
uoff_t size = 0;
for (; part != NULL; part = part->next) {
if (part->flags & (MESSAGE_PART_FLAG_TEXT |
MESSAGE_PART_FLAG_MESSAGE_RFC822)) {
size += part->header_size.physical_size +
part->body_size.physical_size;
}
if (part->children != NULL)
size += textsize_count(part->children);
}
return size;
}
static int fetch_textsize(struct imap_fetch_context *ctx, struct mail *mail,
void *context __attr_unused__)
{
const struct message_part *part;
part = mail_get_parts(mail);
if (part == NULL)
return -1;
str_printfa(ctx->cur_str, "TEXTSIZE %"PRIuUOFF_T" ",
textsize_count(part));
return 1;
}
static bool fetch_textsize_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, FALSE, fetch_textsize, NULL);
return TRUE;
}
const struct imap_fetch_handler default_handlers[8] = {
{ "BODY", fetch_body_init },
{ "BODYSTRUCTURE", fetch_bodystructure_init },
{ "ENVELOPE", fetch_envelope_init },
{ "FLAGS", fetch_flags_init },
{ "INTERNALDATE", fetch_internaldate_init },
{ "RFC822", fetch_rfc822_init },
{ "TEXTSIZE", fetch_textsize_init },
{ "UID", fetch_uid_init }
};