dovecot-2.2: imap: Rewrote FETCH command to use imap-msgpart API.
dovecot at dovecot.org
dovecot at dovecot.org
Thu Jun 21 21:54:03 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/df8ba29d9eb3
changeset: 14623:df8ba29d9eb3
user: Timo Sirainen <tss at iki.fi>
date: Thu Jun 21 21:52:56 2012 +0300
description:
imap: Rewrote FETCH command to use imap-msgpart API.
diffstat:
src/imap/cmd-select.c | 1 -
src/imap/imap-client.h | 12 -
src/imap/imap-fetch-body.c | 811 ++++++++------------------------------------
src/imap/imap-fetch.c | 5 +-
src/imap/imap-fetch.h | 5 +-
5 files changed, 156 insertions(+), 678 deletions(-)
diffs (truncated from 1095 to 300 lines):
diff -r 6fb61872b30a -r df8ba29d9eb3 src/imap/cmd-select.c
--- a/src/imap/cmd-select.c Thu Jun 21 21:50:35 2012 +0300
+++ b/src/imap/cmd-select.c Thu Jun 21 21:52:56 2012 +0300
@@ -301,7 +301,6 @@
STATUS_HIGHESTMODSEQ, &status);
client->mailbox = ctx->box;
- client->select_counter++;
client->mailbox_examined = readonly;
client->messages_count = status.messages;
client->recent_count = status.recent;
diff -r 6fb61872b30a -r df8ba29d9eb3 src/imap/imap-client.h
--- a/src/imap/imap-client.h Thu Jun 21 21:50:35 2012 +0300
+++ b/src/imap/imap-client.h Thu Jun 21 21:52:56 2012 +0300
@@ -78,15 +78,6 @@
unsigned int temp_executed:1; /* temporary execution state tracking */
};
-struct partial_fetch_cache {
- unsigned int select_counter;
- unsigned int uid;
-
- uoff_t physical_start;
- bool cr_skipped;
- struct message_size pos;
-};
-
struct imap_client_vfuncs {
void (*destroy)(struct client *client, const char *reason);
};
@@ -111,7 +102,6 @@
struct mail_user *user;
struct mailbox *mailbox;
struct mailbox_keywords keywords;
- unsigned int select_counter; /* increased when mailbox is changed */
unsigned int sync_counter;
uint32_t messages_count, recent_count, uidvalidity;
enum mailbox_feature enabled_features;
@@ -130,8 +120,6 @@
uint64_t sync_last_full_modseq;
uint64_t highest_fetch_modseq;
- struct partial_fetch_cache last_partial;
-
/* SEARCHRES extension: Last saved SEARCH result */
ARRAY_TYPE(seq_range) search_saved_uidset;
/* SEARCH=CONTEXT extension: Searches that get updated */
diff -r 6fb61872b30a -r df8ba29d9eb3 src/imap/imap-fetch-body.c
--- a/src/imap/imap-fetch-body.c Thu Jun 21 21:50:35 2012 +0300
+++ b/src/imap/imap-fetch-body.c Thu Jun 21 21:52:56 2012 +0300
@@ -10,6 +10,7 @@
#include "message-parser.h"
#include "message-send.h"
#include "mail-storage-private.h"
+#include "imap-quote.h"
#include "imap-parser.h"
#include "imap-msgpart.h"
#include "imap-fetch.h"
@@ -19,17 +20,10 @@
#include <unistd.h>
struct imap_fetch_body_data {
- struct imap_fetch_body_data *next;
+ const char *section; /* NOTE: always uppercased */
+ struct imap_msgpart *msgpart;
- struct mailbox_header_lookup_ctx *header_ctx;
- const char *section; /* NOTE: always uppercased */
- uoff_t skip, max_size; /* if you don't want max_size,
- set it to (uoff_t)-1 */
-
- const char *const *fields;
- size_t fields_count;
-
- unsigned int skip_set:1;
+ unsigned int partial:1;
unsigned int peek:1;
};
@@ -42,54 +36,16 @@
mailbox_get_vname(ctx->cur_mail->box), ctx->cur_mail->uid);
}
-static int seek_partial(unsigned int select_counter, unsigned int uid,
- struct partial_fetch_cache *partial,
- struct istream *stream,
- uoff_t virtual_skip, bool *cr_skipped_r)
-{
- if (select_counter == partial->select_counter && uid == partial->uid &&
- stream->v_offset == partial->physical_start &&
- virtual_skip >= partial->pos.virtual_size) {
- /* we can use the cache */
- virtual_skip -= partial->pos.virtual_size;
- } else {
- partial->select_counter = select_counter;
- partial->uid = uid;
- partial->physical_start = stream->v_offset;
- partial->cr_skipped = FALSE;
- memset(&partial->pos, 0, sizeof(partial->pos));
- }
-
- i_stream_seek(stream, partial->physical_start +
- partial->pos.physical_size);
- if (message_skip_virtual(stream, virtual_skip, &partial->pos,
- partial->cr_skipped, cr_skipped_r) < 0)
- return -1;
-
- partial->cr_skipped = FALSE;
- return 0;
-}
-
-static uoff_t get_send_size(const struct imap_fetch_body_data *body,
- uoff_t max_size)
-{
- uoff_t size;
-
- if (body->skip >= max_size)
- return 0;
-
- size = max_size - body->skip;
- return size <= body->max_size ? size : body->max_size;
-}
-
static const char *get_body_name(const struct imap_fetch_body_data *body)
{
string_t *str;
str = t_str_new(128);
str_printfa(str, "BODY[%s]", body->section);
- if (body->skip_set)
- str_printfa(str, "<%"PRIuUOFF_T">", body->skip);
+ if (body->partial) {
+ str_printfa(str, "<%"PRIuUOFF_T">",
+ imap_msgpart_get_partial_offset(body->msgpart));
+ }
return str_c(str);
}
@@ -114,131 +70,7 @@
return str;
}
-static off_t imap_fetch_send(struct imap_fetch_context *ctx,
- struct ostream *output, struct istream *input,
- bool cr_skipped, uoff_t virtual_size,
- bool add_missing_eoh, bool *last_cr)
-{
- const unsigned char *msg;
- size_t i, size;
- uoff_t vsize_left, sent;
- off_t ret;
- unsigned char add;
- bool blocks = FALSE;
-
- /* go through the message data and insert CRs where needed. */
- sent = 0; vsize_left = virtual_size;
- while (vsize_left > 0 && !blocks &&
- i_stream_read_data(input, &msg, &size, 0) > 0) {
- add = '\0';
- for (i = 0; i < size && vsize_left > 0; i++) {
- vsize_left--;
-
- if (msg[i] == '\n') {
- if ((i > 0 && msg[i-1] != '\r') ||
- (i == 0 && !cr_skipped)) {
- /* missing CR */
- add = '\r';
- break;
- }
- } else if (msg[i] == '\0') {
- add = 128;
- break;
- }
- }
-
- if ((ret = o_stream_send(output, msg, i)) < 0)
- return -1;
- if ((uoff_t)ret < i) {
- add = '\0';
- blocks = TRUE;
- }
-
- if (ret > 0)
- cr_skipped = msg[ret-1] == '\r';
-
- i_stream_skip(input, ret);
- sent += ret;
-
- if (add != '\0') {
- if ((ret = o_stream_send(output, &add, 1)) < 0)
- return -1;
- if (ret == 0)
- blocks = TRUE;
- else {
- sent++;
- cr_skipped = add == '\r';
- if (add == 128)
- i_stream_skip(input, 1);
- }
- }
- }
- if (input->stream_errno != 0) {
- fetch_read_error(ctx);
- return -1;
- }
-
- if (add_missing_eoh && sent + 2 == virtual_size) {
- /* Netscape missing EOH workaround. */
- o_stream_set_max_buffer_size(output, (size_t)-1);
- if (o_stream_send(output, "\r\n", 2) < 0)
- return -1;
- sent += 2;
- }
-
- if ((uoff_t)sent != virtual_size && !blocks) {
- /* Input stream gave less data than we expected. Two choices
- here: either we fill the missing data with spaces or we
- disconnect the client.
-
- We shouldn't really ever get here. One reason is if mail
- was deleted from NFS server while we were reading it.
- Another is some temporary disk error.
-
- If we filled the missing data the client could cache it,
- and if it was just a temporary error the message would be
- permanently left corrupted in client's local cache. So, we
- disconnect the client and hope that next try works. */
- i_error("FETCH %s for mailbox %s UID %u got too little data: "
- "%"PRIuUOFF_T" vs %"PRIuUOFF_T, ctx->cur_name,
- mailbox_get_vname(ctx->cur_mail->box),
- ctx->cur_mail->uid, (uoff_t)sent, virtual_size);
- mail_set_cache_corrupted(ctx->cur_mail, ctx->cur_size_field);
- client_disconnect(ctx->client, "FETCH failed");
- return -1;
- }
-
- *last_cr = cr_skipped;
- return sent;
-}
-
-static int fetch_stream_send(struct imap_fetch_context *ctx)
-{
- off_t ret;
-
- o_stream_set_max_buffer_size(ctx->client->output, 4096);
- ret = imap_fetch_send(ctx, ctx->client->output, ctx->cur_input,
- ctx->skip_cr, ctx->cur_size - ctx->cur_offset,
- ctx->cur_append_eoh, &ctx->skip_cr);
- o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
-
- if (ret < 0)
- return -1;
-
- ctx->cur_offset += ret;
- if (ctx->update_partial) {
- struct partial_fetch_cache *p = &ctx->client->last_partial;
-
- p->cr_skipped = ctx->skip_cr != 0;
- p->pos.physical_size =
- ctx->cur_input->v_offset - p->physical_start;
- p->pos.virtual_size += ret;
- }
-
- return ctx->cur_offset == ctx->cur_size;
-}
-
-static int fetch_stream_send_direct(struct imap_fetch_context *ctx)
+static int fetch_stream_continue(struct imap_fetch_context *ctx)
{
off_t ret;
@@ -246,25 +78,20 @@
ret = o_stream_send_istream(ctx->client->output, ctx->cur_input);
o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
- if (ret < 0)
- return -1;
-
- ctx->cur_offset += ret;
-
- if (ctx->cur_append_eoh && ctx->cur_offset + 2 == ctx->cur_size) {
- /* Netscape missing EOH workaround. */
- if (o_stream_send(ctx->client->output, "\r\n", 2) < 0)
- return -1;
- ctx->cur_offset += 2;
- ctx->cur_append_eoh = FALSE;
- }
+ if (ret > 0)
+ ctx->cur_offset += ret;
if (ctx->cur_offset != ctx->cur_size) {
/* unfinished */
+ if (ctx->cur_input->stream_errno != 0) {
+ fetch_read_error(ctx);
+ client_disconnect(ctx->client, "FETCH failed");
+ return -1;
+ }
if (!i_stream_have_bytes_left(ctx->cur_input)) {
/* Input stream gave less data than expected */
i_error("FETCH %s for mailbox %s UID %u "
More information about the dovecot-cvs
mailing list