Mercurial > dovecot > original-hg > dovecot-1.2
diff src/imap/imap-fetch.c @ 988:8028c4dcf38f HEAD
mail-storage.h interface changes, affects pretty much everything.
FETCH, SEARCH, SORT and THREAD handling were pretty much moved from
lib-storage/ to imap/ so adding non-index storages would be much easier now.
Also POP3 server can now be easily implemented with lib-storage.
Not too well tested, and at least one major problem: partial fetching is
_slow_.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 20 Jan 2003 16:52:51 +0200 |
parents | |
children | 21788a1e9e39 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/imap/imap-fetch.c Mon Jan 20 16:52:51 2003 +0200 @@ -0,0 +1,279 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "common.h" +#include "istream.h" +#include "ostream.h" +#include "str.h" +#include "message-send.h" +#include "message-size.h" +#include "imap-date.h" +#include "commands.h" +#include "imap-fetch.h" + +#include <unistd.h> + +static void fetch_uid(struct imap_fetch_context *ctx, struct mail *mail) +{ + str_printfa(ctx->str, "UID %u ", mail->uid); +} + +static int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail) +{ + const struct mail_full_flags *flags; + + flags = mail->get_flags(mail); + if (flags == NULL) + return FALSE; + + str_printfa(ctx->str, "FLAGS (%s) ", + imap_write_flags(flags->flags, flags->custom_flags, + flags->custom_flags_count)); + return TRUE; +} + +static int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail) +{ + time_t time; + + time = mail->get_received_date(mail); + if (time == (time_t)-1) + return FALSE; + + str_printfa(ctx->str, "INTERNALDATE \"%s\" ", imap_to_datetime(time)); + return TRUE; +} + +static int fetch_rfc822_size(struct imap_fetch_context *ctx, struct mail *mail) +{ + uoff_t size; + + size = mail->get_size(mail); + if (size == (uoff_t)-1) + return FALSE; + + str_printfa(ctx->str, "RFC822.SIZE %"PRIuUOFF_T" ", size); + return TRUE; +} + +static int fetch_body(struct imap_fetch_context *ctx, struct mail *mail) +{ + const char *body; + + body = mail->get_special(mail, MAIL_FETCH_IMAP_BODY); + if (body == NULL) + return FALSE; + + str_printfa(ctx->str, "BODY (%s) ", body); + return TRUE; +} + +static int fetch_bodystructure(struct imap_fetch_context *ctx, + struct mail *mail) +{ + const char *bodystructure; + + bodystructure = mail->get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE); + if (bodystructure == NULL) + return FALSE; + + str_printfa(ctx->str, "BODYSTRUCTURE (%s) ", bodystructure); + return TRUE; +} + +static int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail) +{ + const char *envelope; + + envelope = mail->get_special(mail, MAIL_FETCH_IMAP_ENVELOPE); + if (envelope == NULL) + return FALSE; + + str_printfa(ctx->str, "ENVELOPE (%s) ", envelope); + return TRUE; +} + +static int fetch_send_rfc822(struct imap_fetch_context *ctx, struct mail *mail) +{ + struct message_size hdr_size, body_size; + struct istream *stream; + const char *str; + + stream = mail->get_stream(mail, &hdr_size, &body_size); + if (stream == NULL) + return FALSE; + + message_size_add(&body_size, &hdr_size); + + str = t_strdup_printf(" RFC822 {%"PRIuUOFF_T"}\r\n", + body_size.virtual_size); + if (ctx->first) { + str++; ctx->first = FALSE; + } + if (o_stream_send_str(ctx->output, str) < 0) + return FALSE; + + return message_send(ctx->output, stream, &body_size, 0, (uoff_t)-1); +} + +static int fetch_send_rfc822_header(struct imap_fetch_context *ctx, + struct mail *mail) +{ + struct message_size hdr_size; + struct istream *stream; + const char *str; + + stream = mail->get_stream(mail, &hdr_size, NULL); + if (stream == NULL) + return FALSE; + + str = t_strdup_printf(" RFC822.HEADER {%"PRIuUOFF_T"}\r\n", + hdr_size.virtual_size); + if (ctx->first) { + str++; ctx->first = FALSE; + } + if (o_stream_send_str(ctx->output, str) < 0) + return FALSE; + + return message_send(ctx->output, stream, &hdr_size, 0, (uoff_t)-1); +} + +static int fetch_send_rfc822_text(struct imap_fetch_context *ctx, + struct mail *mail) +{ + struct message_size hdr_size, body_size; + struct istream *stream; + const char *str; + + stream = mail->get_stream(mail, &hdr_size, &body_size); + if (stream == NULL) + return FALSE; + + str = t_strdup_printf(" RFC822.TEXT {%"PRIuUOFF_T"}\r\n", + body_size.virtual_size); + if (ctx->first) { + str++; ctx->first = FALSE; + } + if (o_stream_send_str(ctx->output, str) < 0) + return FALSE; + + i_stream_seek(stream, hdr_size.physical_size); + return message_send(ctx->output, stream, &body_size, 0, (uoff_t)-1); +} + +static int fetch_mail(struct imap_fetch_context *ctx, struct mail *mail) +{ + struct imap_fetch_body_data *body; + size_t len, orig_len; + int failed, data_written; + + 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) || mail->seen_updated) + fetch_flags(ctx, mail); + if (ctx->fetch_data & MAIL_FETCH_RECEIVED_DATE) + fetch_internaldate(ctx, mail); + if (ctx->fetch_data & MAIL_FETCH_SIZE) + fetch_rfc822_size(ctx, mail); + if (ctx->fetch_data & MAIL_FETCH_IMAP_BODY) + fetch_body(ctx, mail); + if (ctx->fetch_data & MAIL_FETCH_IMAP_BODYSTRUCTURE) + fetch_bodystructure(ctx, mail); + if (ctx->fetch_data & MAIL_FETCH_IMAP_ENVELOPE) + fetch_envelope(ctx, mail); + + /* 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; + + /* 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; + } + + 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 imap_fetch_context ctx; + struct mail *mail; + int all_found, update_seen = FALSE; + + if (!client->mailbox->readonly) { + /* If we have any BODY[..] sections, \Seen flag is added for + all messages */ + struct imap_fetch_body_data *body; + + for (body = bodies; body != NULL; body = body->next) { + if (!body->peek) { + update_seen = TRUE; + break; + } + } + + if (imap_data & (IMAP_FETCH_RFC822|IMAP_FETCH_RFC822_TEXT)) + update_seen = TRUE; + } + + memset(&ctx, 0, sizeof(ctx)); + ctx.fetch_data = fetch_data; + ctx.imap_data = imap_data; + ctx.bodies = bodies; + ctx.output = client->output; + ctx.str = t_str_new(8192); + + ctx.fetch_ctx = client->mailbox-> + fetch_init(client->mailbox, fetch_data, &update_seen, + messageset, uidset); + if (ctx.fetch_ctx == NULL) + return -1; + + while ((mail = client->mailbox->fetch_next(ctx.fetch_ctx)) != NULL) { + if (!fetch_mail(&ctx, mail)) { + ctx.failed = TRUE; + break; + } + } + + if (!client->mailbox->fetch_deinit(ctx.fetch_ctx, &all_found)) + return -1; + return ctx.failed ? -1 : all_found; +}