dovecot-2.2: IMAP BINARY extension supports now FETCH BINARY com...

dovecot at dovecot.org dovecot at dovecot.org
Sat Aug 11 05:31:53 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/f3ef88e19cd5
changeset: 14859:f3ef88e19cd5
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Aug 11 05:31:46 2012 +0300
description:
IMAP BINARY extension supports now FETCH BINARY command.

diffstat:

 src/doveadm/doveadm-mail.c                     |    1 +
 src/imap/cmd-fetch.c                           |   18 +-
 src/imap/imap-commands-util.c                  |    2 +
 src/imap/imap-fetch-body.c                     |  108 ++++++++-
 src/imap/imap-fetch.c                          |    1 +
 src/imap/imap-fetch.h                          |    1 +
 src/lib-imap-storage/imap-msgpart.c            |  197 ++++++++++++---
 src/lib-imap-storage/imap-msgpart.h            |   14 +
 src/lib-storage/fail-mail.c                    |   12 +
 src/lib-storage/index/Makefile.am              |    1 +
 src/lib-storage/index/cydir/cydir-mail.c       |    1 +
 src/lib-storage/index/dbox-multi/mdbox-mail.c  |    1 +
 src/lib-storage/index/dbox-single/sdbox-mail.c |    1 +
 src/lib-storage/index/imapc/imapc-mail.c       |    1 +
 src/lib-storage/index/index-mail-binary.c      |  313 +++++++++++++++++++++++++
 src/lib-storage/index/index-mail.h             |    4 +
 src/lib-storage/index/maildir/maildir-mail.c   |    1 +
 src/lib-storage/index/mbox/mbox-mail.c         |    1 +
 src/lib-storage/index/pop3c/pop3c-mail.c       |    1 +
 src/lib-storage/index/raw/raw-mail.c           |    1 +
 src/lib-storage/mail-error.h                   |    5 +-
 src/lib-storage/mail-storage-private.h         |   18 +
 src/lib-storage/mail-storage.c                 |   12 +
 src/lib-storage/mail-storage.h                 |   12 +
 src/lib-storage/mail-user.c                    |    1 +
 src/lib-storage/mail.c                         |   24 +
 src/plugins/virtual/virtual-mail.c             |    1 +
 27 files changed, 701 insertions(+), 52 deletions(-)

diffs (truncated from 1199 to 300 lines):

diff -r ae5ad2935674 -r f3ef88e19cd5 src/doveadm/doveadm-mail.c
--- a/src/doveadm/doveadm-mail.c	Sat Aug 11 05:29:05 2012 +0300
+++ b/src/doveadm/doveadm-mail.c	Sat Aug 11 05:31:46 2012 +0300
@@ -46,6 +46,7 @@
 		break;
 	case MAIL_ERROR_NOTPOSSIBLE:
 	case MAIL_ERROR_EXISTS:
+	case MAIL_ERROR_CONVERSION:
 		exit_code = DOVEADM_EX_NOTPOSSIBLE;
 		break;
 	case MAIL_ERROR_PARAMS:
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/cmd-fetch.c
--- a/src/imap/cmd-fetch.c	Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/cmd-fetch.c	Sat Aug 11 05:31:46 2012 +0300
@@ -143,6 +143,7 @@
 {
 	static const char *ok_message = "OK Fetch completed.";
 	const char *tagged_reply = ok_message;
+	enum mail_error error;
 
 	if (ctx->skipped_expunged_msgs) {
 		tagged_reply = "OK ["IMAP_RESP_CODE_EXPUNGEISSUED"] "
@@ -160,12 +161,17 @@
 			return TRUE;
 		}
 
-		errstr = mailbox_get_last_error(cmd->client->mailbox, NULL);
-
-		/* We never want to reply NO to FETCH requests,
-		   BYE is preferrable (see imap-ml for reasons). */
-		client_disconnect_with_error(cmd->client, errstr);
-		return TRUE;
+		errstr = mailbox_get_last_error(cmd->client->mailbox, &error);
+		if (error == MAIL_ERROR_CONVERSION) {
+			/* BINARY found unsupported Content-Transfer-Encoding */
+			tagged_reply = "NO ["IMAP_RESP_CODE_UNKNOWN_CTE"] "
+				"Unknown Content-Transfer-Encoding.";
+		} else {
+			/* We never want to reply NO to FETCH requests,
+			   BYE is preferrable (see imap-ml for reasons). */
+			client_disconnect_with_error(cmd->client, errstr);
+			return TRUE;
+		}
 	}
 
 	return cmd_sync(cmd,
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/imap-commands-util.c
--- a/src/imap/imap-commands-util.c	Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/imap-commands-util.c	Sat Aug 11 05:31:46 2012 +0300
@@ -134,6 +134,8 @@
 	case MAIL_ERROR_INUSE:
 		resp_code = IMAP_RESP_CODE_INUSE;
 		break;
+	case MAIL_ERROR_CONVERSION:
+		break;
 	}
 	if (resp_code == NULL || *error_string == '[')
 		return t_strconcat("NO ", error_string, NULL);
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/imap-fetch-body.c
--- a/src/imap/imap-fetch-body.c	Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/imap-fetch-body.c	Sat Aug 11 05:31:46 2012 +0300
@@ -24,6 +24,8 @@
 	struct imap_msgpart *msgpart;
 
 	unsigned int partial:1;
+	unsigned int binary:1;
+	unsigned int binary_size:1;
 };
 
 static void fetch_read_error(struct imap_fetch_context *ctx)
@@ -40,7 +42,13 @@
 	string_t *str;
 
 	str = t_str_new(128);
-	str_printfa(str, "BODY[%s]", body->section);
+	if (body->binary_size)
+		str_append(str, "BINARY.SIZE");
+	else if (body->binary)
+		str_append(str, "BINARY");
+	else
+		str_append(str, "BODY");
+	str_printfa(str, "[%s]", body->section);
 	if (body->partial) {
 		str_printfa(str, "<%"PRIuUOFF_T">",
 			    imap_msgpart_get_partial_offset(body->msgpart));
@@ -130,6 +138,27 @@
 	return ctx->cont_handler(ctx);
 }
 
+static int fetch_binary_size(struct imap_fetch_context *ctx, struct mail *mail,
+			     const struct imap_fetch_body_data *body)
+{
+	string_t *str;
+	size_t size;
+
+	if (imap_msgpart_size(mail, body->msgpart, &size) < 0)
+		return -1;
+
+	str = t_str_new(128);
+	if (ctx->first)
+		ctx->first = FALSE;
+	else
+		str_append_c(str, ' ');
+	str_printfa(str, "%s %"PRIuUOFF_T, get_body_name(body), size);
+
+	if (o_stream_send(ctx->client->output, str_data(str), str_len(str)) < 0)
+		return -1;
+	return 1;
+}
+
 /* Parse next digits in string into integer. Returns -1 if the integer
    becomes too big and wraps. */
 static int read_uoff_t(const char **p, uoff_t *value)
@@ -294,6 +323,83 @@
 	return TRUE;
 }
 
+bool imap_fetch_binary_init(struct imap_fetch_init_context *ctx)
+{
+	struct imap_fetch_body_data *body;
+	const struct imap_arg *list_args;
+	unsigned int list_count;
+	const char *str, *p, *error;
+
+	i_assert(strncmp(ctx->name, "BINARY", 6) == 0);
+	p = ctx->name + 6;
+
+	body = p_new(ctx->fetch_ctx->pool, struct imap_fetch_body_data, 1);
+	body->binary = TRUE;
+
+	if (strncmp(p, ".SIZE", 5) == 0) {
+		/* fetch decoded size of the section */
+		p += 5;
+		body->binary_size = TRUE;
+	} else if (strncmp(p, ".PEEK", 5) == 0) {
+		p += 5;
+	} else {
+		ctx->fetch_ctx->flags_update_seen = TRUE;
+	}
+	if (*p != '[') {
+		ctx->error = "Invalid BINARY[..] parameter: Missing '['";
+		return FALSE;
+	}
+
+	if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) {
+		/* BINARY[HEADER.FIELDS.. (headers list)] */
+		if (!imap_arg_get_atom(&ctx->args[1], &str) ||
+		    str[0] != ']') {
+			ctx->error = "Invalid BINARY[..] parameter: Missing ']'";
+			return FALSE;
+		}
+		if (body_header_fields_parse(ctx, body, p+1,
+					     list_args, list_count) < 0)
+			return FALSE;
+		p = str+1;
+		ctx->args += 2;
+	} else {
+		/* no headers list */
+		body->section = p+1;
+		p = strchr(body->section, ']');
+		if (p == NULL) {
+			ctx->error = "Invalid BINARY[..] parameter: Missing ']'";
+			return FALSE;
+		}
+		body->section = p_strdup_until(ctx->fetch_ctx->pool,
+					       body->section, p);
+		p++;
+	}
+	if (imap_msgpart_parse(ctx->fetch_ctx->box, body->section,
+			       &body->msgpart) < 0) {
+		ctx->error = "Invalid BINARY[..] section";
+		return -1;
+	}
+	imap_msgpart_set_decode_to_binary(body->msgpart);
+	ctx->fetch_ctx->fetch_data |=
+		imap_msgpart_get_fetch_data(body->msgpart);
+
+	if (!body->binary_size) {
+		if (body_parse_partial(body, p, &error) < 0) {
+			ctx->error = p_strdup_printf(ctx->fetch_ctx->pool,
+				"Invalid BINARY[..] parameter: %s", error);
+			return FALSE;
+		}
+	}
+
+	/* update the section name for the imap_fetch_add_handler() */
+	ctx->name = p_strdup(ctx->fetch_ctx->pool, get_body_name(body));
+	if (body->binary_size)
+		imap_fetch_add_handler(ctx, 0, "NIL", fetch_binary_size, body);
+	else
+		imap_fetch_add_handler(ctx, 0, "NIL", fetch_body_msgpart, body);
+	return TRUE;
+}
+
 static int ATTR_NULL(3)
 fetch_rfc822_size(struct imap_fetch_context *ctx, struct mail *mail,
 		  void *context ATTR_UNUSED)
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/imap-fetch.c
--- a/src/imap/imap-fetch.c	Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/imap-fetch.c	Sat Aug 11 05:31:46 2012 +0300
@@ -860,6 +860,7 @@
 
 static const struct imap_fetch_handler
 imap_fetch_default_handlers[] = {
+	{ "BINARY", imap_fetch_binary_init },
 	{ "BODY", fetch_body_init },
 	{ "BODYSTRUCTURE", fetch_bodystructure_init },
 	{ "ENVELOPE", fetch_envelope_init },
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/imap-fetch.h
--- a/src/imap/imap-fetch.h	Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/imap-fetch.h	Sat Aug 11 05:31:46 2012 +0300
@@ -125,6 +125,7 @@
 
 bool imap_fetch_body_section_init(struct imap_fetch_init_context *ctx);
 bool imap_fetch_rfc822_init(struct imap_fetch_init_context *ctx);
+bool imap_fetch_binary_init(struct imap_fetch_init_context *ctx);
 
 void imap_fetch_handlers_init(void);
 void imap_fetch_handlers_deinit(void);
diff -r ae5ad2935674 -r f3ef88e19cd5 src/lib-imap-storage/imap-msgpart.c
--- a/src/lib-imap-storage/imap-msgpart.c	Sat Aug 11 05:29:05 2012 +0300
+++ b/src/lib-imap-storage/imap-msgpart.c	Sat Aug 11 05:31:46 2012 +0300
@@ -5,8 +5,12 @@
 #include "istream.h"
 #include "istream-crlf.h"
 #include "istream-nonuls.h"
+#include "istream-base64.h"
 #include "istream-header-filter.h"
+#include "istream-qp.h"
+#include "ostream.h"
 #include "message-parser.h"
+#include "message-decoder.h"
 #include "mail-storage-private.h"
 #include "mail-namespace.h"
 #include "imap-parser.h"
@@ -37,6 +41,8 @@
 
 	/* which part of the message part to fetch (default: 0..(uoff_t)-1) */
 	uoff_t partial_offset, partial_size;
+
+	unsigned int decode_cte_to_binary:1;
 };
 
 struct imap_msgpart_open_ctx {
@@ -293,6 +299,11 @@
 	pool_unref(&msgpart->pool);
 }
 
+void imap_msgpart_set_decode_to_binary(struct imap_msgpart *msgpart)
+{
+	msgpart->decode_cte_to_binary = TRUE;
+}
+
 void imap_msgpart_set_partial(struct imap_msgpart *msgpart,
 			      uoff_t offset, uoff_t size)
 {
@@ -394,7 +405,7 @@
 		       const struct imap_msgpart *msgpart)
 {
 	struct mail_msgpart_partial_cache *cache = &mail->box->partial_cache;
-	struct istream *nul_input, *crlf_input;
+	struct istream *crlf_input;
 	const unsigned char *data;
 	size_t size;
 	uoff_t physical_start = input->v_offset;
@@ -415,11 +426,6 @@
 		   message parts. */
 		skip_using_parts(mail, input, &virtual_skip);
 	}
-	if (!mail->has_no_nuls) {
-		nul_input = i_stream_create_nonuls(input, 0x80);
-		i_stream_unref(&input);
-		input = nul_input;
-	}
 	crlf_input = i_stream_create_crlf(input);
 	i_stream_unref(&input);
 	input = crlf_input;
@@ -445,6 +451,7 @@
 
 static void
 imap_msgpart_get_partial(struct mail *mail, const struct imap_msgpart *msgpart,
+			 bool convert_nuls, bool use_partial_cache,
 			 const struct message_size *part_size,
 			 struct imap_msgpart_open_result *result)
 {
@@ -468,6 +475,7 @@
 	} else {
 		/* input has LF linefeeds. it can be slow to seek to wanted
 		   position, so try to do caching whenever possible */
+		i_assert(use_partial_cache);
 		result->input = imap_msgpart_crlf_seek(mail, result->input,
 						       msgpart);
 	}
@@ -480,49 +488,73 @@
 		/* send all bytes */
 		result->size = bytes_left;
 	}
+
+	if (!mail->has_no_nuls && convert_nuls) {
+		/* IMAP literals must not contain NULs. change them to


More information about the dovecot-cvs mailing list