imap-fetch.c revision a77bddd704784189944b731f5ce774bfb4440e0b
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "common.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "buffer.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "istream.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "ostream.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "str.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "message-send.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "message-size.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "imap-date.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "commands.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "imap-fetch.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include <unistd.h>
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainenconst char *const *imap_fetch_get_body_fields(const char *fields)
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char **field_list, **field, **dest;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen while (*fields == ' ')
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen fields++;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (*fields == '(')
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen fields++;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen field_list = t_strsplit(fields, " )");
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* array ends at ")" element */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen for (field = dest = field_list; *field != NULL; field++) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (strcmp(*field, ")") == 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen break;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (**field != '\0') {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen *dest = *field;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen dest++;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen *dest = NULL;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return field_list;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic void fetch_uid(struct imap_fetch_context *ctx, struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_printfa(ctx->str, "UID %u ", mail->uid);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const struct mail_full_flags *flags)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (flags == NULL) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen flags = mail->get_flags(mail);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (flags == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen }
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen str_printfa(ctx->str, "FLAGS (%s) ", imap_write_flags(flags));
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen return TRUE;
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen time_t time;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen time = mail->get_received_date(mail);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (time == (time_t)-1)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_printfa(ctx->str, "INTERNALDATE \"%s\" ", imap_to_datetime(time));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return TRUE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int fetch_rfc822_size(struct imap_fetch_context *ctx, struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen uoff_t size;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen size = mail->get_size(mail);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (size == (uoff_t)-1)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_printfa(ctx->str, "RFC822.SIZE %"PRIuUOFF_T" ", size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return TRUE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *body;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen body = mail->get_special(mail, MAIL_FETCH_IMAP_BODY);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (body == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ctx->first) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, "BODY (") < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ctx->first = FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, " BODY (") < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, body) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send(ctx->output, ")", 1) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return TRUE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *bodystructure;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen bodystructure = mail->get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (bodystructure == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ctx->first) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, "BODYSTRUCTURE (") < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ctx->first = FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, " BODYSTRUCTURE (") < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, bodystructure) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send(ctx->output, ")", 1) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return TRUE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *envelope;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen envelope = mail->get_special(mail, MAIL_FETCH_IMAP_ENVELOPE);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (envelope == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ctx->first) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, "ENVELOPE (") < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ctx->first = FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, " ENVELOPE (") < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen if (o_stream_send_str(ctx->output, envelope) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send(ctx->output, ")", 1) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return TRUE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int fetch_send_rfc822(struct imap_fetch_context *ctx, struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct message_size hdr_size, body_size;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct istream *stream;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *str;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen stream = mail->get_stream(mail, &hdr_size, &body_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (stream == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen message_size_add(&body_size, &hdr_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str = t_strdup_printf(" RFC822 {%"PRIuUOFF_T"}\r\n",
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen body_size.virtual_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ctx->first) {
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen str++; ctx->first = FALSE;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen }
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen if (o_stream_send_str(ctx->output, str) < 0)
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen return FALSE;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen return message_send(ctx->output, stream, &body_size,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen 0, body_size.virtual_size, NULL,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen !mail->has_no_nuls) >= 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int fetch_send_rfc822_header(struct imap_fetch_context *ctx,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen struct message_size hdr_size;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct istream *stream;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *str;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen stream = mail->get_stream(mail, &hdr_size, NULL);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (stream == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str = t_strdup_printf(" RFC822.HEADER {%"PRIuUOFF_T"}\r\n",
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen hdr_size.virtual_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ctx->first) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str++; ctx->first = FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_send_str(ctx->output, str) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen return message_send(ctx->output, stream, &hdr_size,
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen 0, hdr_size.virtual_size, NULL,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen !mail->has_no_nuls) >= 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainenstatic int fetch_send_rfc822_text(struct imap_fetch_context *ctx,
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct message_size hdr_size, body_size;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct istream *stream;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *str;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen stream = mail->get_stream(mail, &hdr_size, &body_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (stream == NULL)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str = t_strdup_printf(" RFC822.TEXT {%"PRIuUOFF_T"}\r\n",
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen body_size.virtual_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ctx->first) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str++; ctx->first = FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen if (o_stream_send_str(ctx->output, str) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_stream_seek(stream, hdr_size.physical_size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return message_send(ctx->output, stream, &body_size,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen 0, body_size.virtual_size, NULL,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen !mail->has_no_nuls) >= 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int fetch_mail(struct imap_fetch_context *ctx, struct mail *mail)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const struct mail_full_flags *flags;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen struct imap_fetch_body_data *body;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen size_t len, orig_len;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen int failed, data_written, seen_updated = FALSE;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen if (!ctx->update_seen)
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen flags = NULL;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen else {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen flags = mail->get_flags(mail);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (flags == NULL)
return FALSE;
if ((flags->flags & MAIL_SEEN) == 0) {
if (!mail->update_flags(mail, &ctx->seen_flag,
MODIFY_ADD))
return FALSE;
flags = NULL; /* \Seen won't update automatically */
seen_updated = TRUE;
}
}
t_push();
str_truncate(ctx->str, 0);
str_printfa(ctx->str, "* %u FETCH (", mail->seq);
orig_len = str_len(ctx->str);
failed = TRUE;
data_written = FALSE;
do {
/* write the data into temp string */
if (ctx->imap_data & IMAP_FETCH_UID)
fetch_uid(ctx, mail);
if ((ctx->fetch_data & MAIL_FETCH_FLAGS) || seen_updated)
if (!fetch_flags(ctx, mail, flags))
break;
if (ctx->fetch_data & MAIL_FETCH_RECEIVED_DATE)
if (!fetch_internaldate(ctx, mail))
break;
if (ctx->fetch_data & MAIL_FETCH_SIZE)
if (!fetch_rfc822_size(ctx, mail))
break;
/* send the data written into temp string */
len = str_len(ctx->str);
ctx->first = len == orig_len;
if (!ctx->first)
str_truncate(ctx->str, --len);
if (o_stream_send(ctx->output, str_data(ctx->str), len) < 0)
break;
data_written = TRUE;
/* medium size data .. seems to be faster without
putting through string */
if (ctx->fetch_data & MAIL_FETCH_IMAP_BODY)
if (!fetch_body(ctx, mail))
break;
if (ctx->fetch_data & MAIL_FETCH_IMAP_BODYSTRUCTURE)
if (!fetch_bodystructure(ctx, mail))
break;
if (ctx->fetch_data & MAIL_FETCH_IMAP_ENVELOPE)
if(!fetch_envelope(ctx, mail))
break;
/* large data */
if (ctx->imap_data & IMAP_FETCH_RFC822)
if (!fetch_send_rfc822(ctx, mail))
break;
if (ctx->imap_data & IMAP_FETCH_RFC822_HEADER)
if (!fetch_send_rfc822_header(ctx, mail))
break;
if (ctx->imap_data & IMAP_FETCH_RFC822_TEXT)
if (!fetch_send_rfc822_text(ctx, mail))
break;
for (body = ctx->bodies; body != NULL; body = body->next) {
if (!imap_fetch_body_section(ctx, body, mail))
break;
}
failed = FALSE;
} while (0);
if (data_written) {
if (o_stream_send(ctx->output, ")\r\n", 3) < 0)
failed = TRUE;
}
t_pop();
return !failed;
}
int imap_fetch(struct client *client,
enum mail_fetch_field fetch_data,
enum imap_fetch_field imap_data,
struct imap_fetch_body_data *bodies,
const char *messageset, int uidset)
{
struct mailbox *box = client->mailbox;
struct imap_fetch_context ctx;
struct mail *mail;
struct imap_fetch_body_data *body;
const char *null = NULL;
const char *const *wanted_headers, *const *arr;
buffer_t *buffer;
int all_found;
memset(&ctx, 0, sizeof(ctx));
ctx.fetch_data = fetch_data;
ctx.imap_data = imap_data;
ctx.bodies = bodies;
ctx.output = client->output;
ctx.select_counter = client->select_counter;
ctx.seen_flag.flags = MAIL_SEEN;
if (!box->is_readonly(box)) {
/* If we have any BODY[..] sections, \Seen flag is added for
all messages. */
for (body = bodies; body != NULL; body = body->next) {
if (!body->peek) {
ctx.update_seen = TRUE;
break;
}
}
if (imap_data & (IMAP_FETCH_RFC822|IMAP_FETCH_RFC822_TEXT))
ctx.update_seen = TRUE;
}
/* If we have only BODY[HEADER.FIELDS (...)] fetches, get them
separately rather than parsing the full header so mail storage
can try to cache them. */
ctx.body_fetch_from_cache = TRUE;
buffer = buffer_create_dynamic(pool_datastack_create(), 64, (size_t)-1);
for (body = bodies; body != NULL; body = body->next) {
if (strncmp(body->section, "HEADER.FIELDS ", 14) != 0) {
ctx.body_fetch_from_cache = FALSE;
break;
}
arr = imap_fetch_get_body_fields(body->section + 14);
while (*arr != NULL) {
buffer_append(buffer, arr, sizeof(*arr));
arr++;
}
}
buffer_append(buffer, &null, sizeof(null));
wanted_headers = !ctx.body_fetch_from_cache ? NULL :
buffer_get_data(buffer, NULL);
if (ctx.update_seen) {
if (!box->lock(box, MAILBOX_LOCK_FLAGS | MAILBOX_LOCK_READ))
return -1;
}
ctx.fetch_ctx = box->fetch_init(box, fetch_data, wanted_headers,
messageset, uidset);
if (ctx.fetch_ctx == NULL)
ctx.failed = TRUE;
else {
ctx.str = str_new(default_pool, 8192);
while ((mail = box->fetch_next(ctx.fetch_ctx)) != NULL) {
if (!fetch_mail(&ctx, mail)) {
ctx.failed = TRUE;
break;
}
}
str_free(ctx.str);
if (!box->fetch_deinit(ctx.fetch_ctx, &all_found))
ctx.failed = TRUE;
}
(void)box->lock(box, MAILBOX_LOCK_UNLOCK);
return ctx.failed ? -1 : all_found;
}