dovecot-2.0: Added support for saving base64-encoded attachments...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Oct 2 14:34:02 EEST 2010
details: http://hg.dovecot.org/dovecot-2.0/rev/3ef0ac874fd7
changeset: 12254:3ef0ac874fd7
user: Timo Sirainen <tss at iki.fi>
date: Mon Aug 23 19:04:10 2010 +0100
description:
Added support for saving base64-encoded attachments de-base64d
diffstat:
src/lib-storage/index/Makefile.am | 2 +
src/lib-storage/index/dbox-common/dbox-attachment.c | 96 +++++-
src/lib-storage/index/index-attachment.c | 427 +++++++++++++++++++++---
src/lib-storage/index/index-attachment.h | 8 +
src/lib-storage/index/istream-attachment.c | 9 -
src/lib-storage/index/istream-base64-encoder.c | 148 ++++++++
src/lib-storage/index/istream-base64-encoder.h | 8 +
7 files changed, 615 insertions(+), 83 deletions(-)
diffs (truncated from 995 to 300 lines):
diff -r 0078f598d1fc -r 3ef0ac874fd7 src/lib-storage/index/Makefile.am
--- a/src/lib-storage/index/Makefile.am Mon Aug 23 19:03:16 2010 +0100
+++ b/src/lib-storage/index/Makefile.am Mon Aug 23 19:04:10 2010 +0100
@@ -13,6 +13,7 @@
libstorage_index_la_SOURCES = \
istream-attachment.c \
+ istream-base64-encoder.c \
istream-mail-stats.c \
index-attachment.c \
index-fetch.c \
@@ -38,6 +39,7 @@
headers = \
istream-attachment.h \
+ istream-base64-encoder.h \
istream-mail-stats.h \
index-attachment.h \
index-mail.h \
diff -r 0078f598d1fc -r 3ef0ac874fd7 src/lib-storage/index/dbox-common/dbox-attachment.c
--- a/src/lib-storage/index/dbox-common/dbox-attachment.c Mon Aug 23 19:03:16 2010 +0100
+++ b/src/lib-storage/index/dbox-common/dbox-attachment.c Mon Aug 23 19:04:10 2010 +0100
@@ -5,16 +5,24 @@
#include "istream-concat.h"
#include "str.h"
#include "istream-attachment.h"
+#include "istream-base64-encoder.h"
#include "dbox-file.h"
#include "dbox-save.h"
#include "dbox-attachment.h"
+enum dbox_attachment_decode_option {
+ DBOX_ATTACHMENT_DECODE_OPTION_NONE = '-',
+ DBOX_ATTACHMENT_DECODE_OPTION_BASE64 = 'B',
+ DBOX_ATTACHMENT_DECODE_OPTION_CRLF = 'C'
+};
+
void dbox_attachment_save_write_metadata(struct mail_save_context *ctx,
string_t *str)
{
const ARRAY_TYPE(mail_attachment_extref) *extrefs;
const struct mail_attachment_extref *extref;
bool add_space = FALSE;
+ unsigned int startpos;
extrefs = index_attachment_save_get_extrefs(ctx);
if (extrefs == NULL || array_count(extrefs) == 0)
@@ -26,13 +34,61 @@
add_space = TRUE;
else
str_append_c(str, ' ');
- str_printfa(str, "%"PRIuUOFF_T" %"PRIuUOFF_T" %s",
- extref->start_offset, extref->size, extref->path);
+ str_printfa(str, "%"PRIuUOFF_T" %"PRIuUOFF_T" ",
+ extref->start_offset, extref->size);
+
+ startpos = str_len(str);
+ if (extref->base64_have_crlf)
+ str_append_c(str, DBOX_ATTACHMENT_DECODE_OPTION_CRLF);
+ if (extref->base64_blocks_per_line > 0) {
+ str_printfa(str, "%c%u",
+ DBOX_ATTACHMENT_DECODE_OPTION_BASE64,
+ extref->base64_blocks_per_line * 4);
+ }
+ if (startpos == str_len(str)) {
+ /* make it clear there are no options */
+ str_append_c(str, DBOX_ATTACHMENT_DECODE_OPTION_NONE);
+ }
+ str_append_c(str, ' ');
+ str_append(str, extref->path);
}
str_append_c(str, '\n');
}
static bool
+parse_extref_decode_options(const char *str,
+ struct mail_attachment_extref *extref)
+{
+ unsigned int num;
+
+ if (*str == DBOX_ATTACHMENT_DECODE_OPTION_NONE)
+ return str[1] == '\0';
+
+ while (*str != '\0') {
+ switch (*str) {
+ case DBOX_ATTACHMENT_DECODE_OPTION_BASE64:
+ str++; num = 0;
+ while (*str >= '0' && *str <= '9') {
+ num = num*10 + (*str-'0');
+ str++;
+ }
+ if (num == 0 || num % 4 != 0)
+ return FALSE;
+
+ extref->base64_blocks_per_line = num/4;
+ break;
+ case DBOX_ATTACHMENT_DECODE_OPTION_CRLF:
+ extref->base64_have_crlf = TRUE;
+ str++;
+ break;
+ default:
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static bool
dbox_attachment_parse_extref_real(const char *line, pool_t pool,
ARRAY_TYPE(mail_attachment_extref) *extrefs)
{
@@ -43,20 +99,27 @@
args = t_strsplit(line, " ");
len = str_array_length(args);
- if ((len % 3) != 0)
+ if ((len % 4) != 0)
return FALSE;
last_voffset = 0;
- memset(&extref, 0, sizeof(extref));
- for (i = 0; args[i] != NULL; i += 3) {
- if (str_to_uoff(args[i+0], &extref.start_offset) < 0 ||
- str_to_uoff(args[i+1], &extref.size) < 0 ||
- extref.start_offset < last_voffset)
+ for (i = 0; args[i] != NULL; i += 4) {
+ const char *start_offset_str = args[i+0];
+ const char *size_str = args[i+1];
+ const char *decode_options = args[i+2];
+ const char *path = args[i+3];
+
+ memset(&extref, 0, sizeof(extref));
+ if (str_to_uoff(start_offset_str, &extref.start_offset) < 0 ||
+ str_to_uoff(size_str, &extref.size) < 0 ||
+ extref.start_offset < last_voffset ||
+ !parse_extref_decode_options(decode_options, &extref))
return FALSE;
+
last_voffset += extref.size +
(extref.start_offset - last_voffset);
- extref.path = p_strdup(pool, args[i+2]);
+ extref.path = p_strdup(pool, path);
array_append(extrefs, &extref, 1);
}
return TRUE;
@@ -109,6 +172,15 @@
last_voffset += extref->size;
input2 = i_stream_create_file(path, IO_BLOCK_SIZE);
+
+ if (extref->base64_blocks_per_line > 0) {
+ input = i_stream_create_base64_encoder(input2,
+ extref->base64_blocks_per_line*4,
+ extref->base64_have_crlf);
+ i_stream_unref(&input2);
+ input2 = input;
+ }
+
input = i_stream_create_attachment(input2, extref->size);
i_stream_unref(&input2);
array_append(&streams, &input, 1);
@@ -154,7 +226,9 @@
ret = dbox_attachment_file_get_stream_from(file, ext_refs,
stream_r);
} T_END;
- if (ret == 0)
- dbox_file_set_corrupted(file, "Ext refs metadata corrupted");
+ if (ret == 0) {
+ dbox_file_set_corrupted(file, "Ext refs metadata corrupted: %s",
+ ext_refs);
+ }
return ret;
}
diff -r 0078f598d1fc -r 3ef0ac874fd7 src/lib-storage/index/index-attachment.c
--- a/src/lib-storage/index/index-attachment.c Mon Aug 23 19:03:16 2010 +0100
+++ b/src/lib-storage/index/index-attachment.c Mon Aug 23 19:04:10 2010 +0100
@@ -5,6 +5,7 @@
#include "fs-api.h"
#include "istream.h"
#include "ostream.h"
+#include "base64.h"
#include "sha1.h"
#include "str.h"
#include "hex-binary.h"
@@ -14,28 +15,53 @@
#include "index-mail.h"
#include "index-attachment.h"
+#define BASE64_ATTACHMENT_MAX_EXTRA_BYTES 1024
+
enum mail_attachment_state {
MAIL_ATTACHMENT_STATE_NO,
MAIL_ATTACHMENT_STATE_MAYBE,
MAIL_ATTACHMENT_STATE_YES
};
+enum base64_state {
+ BASE64_STATE_0 = 0,
+ BASE64_STATE_1,
+ BASE64_STATE_2,
+ BASE64_STATE_3,
+ BASE64_STATE_CR,
+ BASE64_STATE_EOB,
+ BASE64_STATE_EOM
+};
+
+struct mail_save_attachment_part {
+ char *content_type, *content_disposition;
+ enum mail_attachment_state state;
+ /* start offset of the message part in the original input stream */
+ uoff_t start_offset;
+
+ /* for saving attachments base64-decoded: */
+ enum base64_state base64_state, base64_prev_state;
+ unsigned int base64_line_blocks, cur_base64_blocks;
+ unsigned int base64_last_newline_size;
+ uoff_t base64_bytes;
+ bool base64_have_crlf; /* CRLF linefeeds */
+ bool base64_failed;
+
+ int temp_fd;
+ struct ostream *output;
+ struct sha1_ctxt part_hash;
+ buffer_t *part_buf;
+};
+
struct mail_save_attachment {
pool_t pool;
struct message_parser_ctx *parser;
struct fs *fs;
struct istream *input;
+ /* per-MIME part data */
+ struct mail_save_attachment_part part;
struct message_part *prev_part;
- char *content_type, *content_disposition;
- enum mail_attachment_state state;
- /* start offset of the message part in the original input stream */
- uoff_t start_offset;
-
- int temp_fd;
- struct ostream *output;
- struct sha1_ctxt part_hash;
- buffer_t *part_buf;
ARRAY_TYPE(mail_attachment_extref) extrefs;
};
@@ -79,8 +105,8 @@
T_BEGIN {
content_type = t_str_new(64);
if (rfc822_parse_content_type(&parser, content_type) >= 0) {
- i_free(ctx->attach->content_type);
- ctx->attach->content_type =
+ i_free(ctx->attach->part.content_type);
+ ctx->attach->part.content_type =
i_strdup(str_c(content_type));
}
} T_END;
@@ -91,8 +117,8 @@
const struct message_header_line *hdr)
{
/* just pass it as-is to backend. */
- i_free(ctx->attach->content_disposition);
- ctx->attach->content_disposition =
+ i_free(ctx->attach->part.content_disposition);
+ ctx->attach->part.content_disposition =
i_strndup(hdr->full_value, hdr->full_value_len);
}
@@ -136,9 +162,8 @@
return box->v.save_is_attachment(ctx, part);
}
-static int index_attachment_save_temp_open(struct mail_save_context *ctx)
+static int index_attachment_save_temp_open_fd(struct mail_storage *storage)
{
- struct mail_storage *storage = ctx->transaction->box->storage;
string_t *temp_path;
int fd;
@@ -156,15 +181,150 @@
(void)close(fd);
return -1;
}
+ return fd;
+}
- ctx->attach->temp_fd = fd;
- ctx->attach->output = o_stream_create_fd(fd, 0, FALSE);
- sha1_init(&ctx->attach->part_hash);
+static int index_attachment_save_temp_open(struct mail_save_context *ctx)
+{
+ int fd;
+
+ fd = index_attachment_save_temp_open_fd(ctx->transaction->box->storage);
+ if (fd == -1)
+ return -1;
+
+ ctx->attach->part.temp_fd = fd;
More information about the dovecot-cvs
mailing list