dovecot-2.2: lib-imap-storage: imap-msgpart rewrite and API change.

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/6fb61872b30a
changeset: 14622:6fb61872b30a
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jun 21 21:50:35 2012 +0300
description:
lib-imap-storage: imap-msgpart rewrite and API change.
The new API allows first parsing the validity of section strings and later
relying on them being valid without having to re-parse it. The
implementation also fixes a few things and adds "partial fetch cache".

diffstat:

 src/lib-imap-storage/Makefile.am        |    1 +
 src/lib-imap-storage/imap-msgpart-url.c |   53 +-
 src/lib-imap-storage/imap-msgpart.c     |  707 ++++++++++++++++++++-----------
 src/lib-imap-storage/imap-msgpart.h     |   46 +-
 src/lib-storage/mail-storage-private.h  |    7 +
 5 files changed, 531 insertions(+), 283 deletions(-)

diffs (truncated from 1003 to 300 lines):

diff -r bf8a885c2077 -r 6fb61872b30a src/lib-imap-storage/Makefile.am
--- a/src/lib-imap-storage/Makefile.am	Thu Jun 21 21:47:06 2012 +0300
+++ b/src/lib-imap-storage/Makefile.am	Thu Jun 21 21:50:35 2012 +0300
@@ -5,6 +5,7 @@
 	-I$(top_srcdir)/src/lib-test \
 	-I$(top_srcdir)/src/lib-charset \
 	-I$(top_srcdir)/src/lib-mail \
+	-I$(top_srcdir)/src/lib-index \
 	-I$(top_srcdir)/src/lib-storage \
 	-I$(top_srcdir)/src/lib-imap
 
diff -r bf8a885c2077 -r 6fb61872b30a src/lib-imap-storage/imap-msgpart-url.c
--- a/src/lib-imap-storage/imap-msgpart-url.c	Thu Jun 21 21:47:06 2012 +0300
+++ b/src/lib-imap-storage/imap-msgpart-url.c	Thu Jun 21 21:50:35 2012 +0300
@@ -1,3 +1,5 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
 #include "lib.h"
 #include "network.h"
 #include "istream.h"
@@ -162,13 +164,32 @@
 	return 1;
 }
 
+static int
+imap_msgpart_url_open_part(struct imap_msgpart_url *mpurl, struct mail **mail_r,
+			   struct imap_msgpart **msgpart_r, const char **error_r)
+{
+	int ret;
+
+	if ((ret = imap_msgpart_url_open_mail(mpurl, mail_r, error_r)) <= 0)
+		return ret;
+
+	if (imap_msgpart_parse((*mail_r)->box, mpurl->section, msgpart_r) < 0) {
+		*error_r = "Invalid section";
+		return 0;
+	}
+	imap_msgpart_set_partial(*msgpart_r, mpurl->partial_offset,
+				 mpurl->partial_size == 0 ? (uoff_t)-1 :
+				 mpurl->partial_size);
+	return 1;
+}
+
 int imap_msgpart_url_read_part(struct imap_msgpart_url *mpurl,
 			       struct istream **stream_r, uoff_t *size_r,
 			       const char **error_r)
 {
 	struct mail *mail;
-	struct istream *input;
-	uoff_t part_size;
+	struct imap_msgpart *msgpart;
+	struct imap_msgpart_open_result result;
 	int ret;
 
 	if (mpurl->input != NULL) {
@@ -179,20 +200,20 @@
 	}
 
 	/* open mail if it is not yet open */
-	if ((ret = imap_msgpart_url_open_mail(mpurl, &mail, error_r)) <= 0)
+	ret = imap_msgpart_url_open_part(mpurl, &mail, &msgpart, error_r);
+	if (ret <= 0)
 		return ret;
 
 	/* open the referenced part as a stream */
-	if ((ret = imap_msgpart_open(mail, mpurl->section,
-				     mpurl->partial_offset, mpurl->partial_size,
-				     &input, &part_size, error_r)) <= 0)
+	ret = imap_msgpart_open(mail, msgpart, &result);
+	imap_msgpart_free(&msgpart);
+	if (ret < 0) {
+		*error_r = mailbox_get_last_error(mail->box, NULL);
 		return ret;
+	}
 
-	mpurl->input = input;
-	mpurl->part_size = part_size;
-
-	*stream_r = input;
-	*size_r = part_size;
+	*stream_r = mpurl->input = result.input;
+	*size_r = mpurl->part_size = result.size;
 	return 1;
 }
 
@@ -200,17 +221,17 @@
 			    const char **error_r)
 {
 	struct mail *mail;
+	struct imap_msgpart *msgpart;
 	int ret;
 
 	if (mpurl->input != NULL)
 		return 1;
 
 	/* open mail if it is not yet open */
-	if ((ret = imap_msgpart_url_open_mail(mpurl, &mail, error_r)) <= 0)
-		return ret;
-
-	/* open the referenced part as a stream */
-	return imap_msgpart_verify(mail, mpurl->section, error_r);
+	ret = imap_msgpart_url_open_part(mpurl, &mail, &msgpart, error_r);
+	if (ret > 0)
+		imap_msgpart_free(&msgpart);
+	return ret;
 }
 
 void imap_msgpart_url_free(struct imap_msgpart_url **_mpurl)
diff -r bf8a885c2077 -r 6fb61872b30a src/lib-imap-storage/imap-msgpart.c
--- a/src/lib-imap-storage/imap-msgpart.c	Thu Jun 21 21:47:06 2012 +0300
+++ b/src/lib-imap-storage/imap-msgpart.c	Thu Jun 21 21:50:35 2012 +0300
@@ -1,25 +1,89 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
 #include "lib.h"
 #include "array.h"
 #include "istream.h"
 #include "istream-crlf.h"
+#include "istream-nonuls.h"
 #include "istream-header-filter.h"
 #include "message-parser.h"
-#include "mail-storage.h"
+#include "mail-storage-private.h"
 #include "mail-namespace.h"
 #include "imap-parser.h"
 #include "imap-msgpart.h"
 
-int imap_msgpart_find(struct mail *mail, const char *section,
-		      const struct message_part **part_r,
-		      const char **subsection_r)
+enum fetch_type {
+	FETCH_FULL,
+	FETCH_MIME,
+	FETCH_HEADER,
+	FETCH_HEADER_FIELDS,
+	FETCH_HEADER_FIELDS_NOT,
+	FETCH_BODY
+};
+
+struct imap_msgpart {
+	pool_t pool;
+
+	/* "" for root, otherwise e.g. "1.2.3". the .MIME, .HEADER, etc.
+	   suffix not included */
+	const char *section_number;
+	enum fetch_type fetch_type;
+	enum mail_fetch_field wanted_fields;
+
+	/* HEADER.FIELDS[.NOT] (list of headers) */
+        struct mailbox_header_lookup_ctx *header_ctx;
+	const char *const *headers;
+
+	/* which part of the message part to fetch (default: 0..(uoff_t)-1) */
+	uoff_t partial_offset, partial_size;
+};
+
+struct imap_msgpart_open_ctx {
+	/* from matching message_part, set after opening: */
+	uoff_t physical_pos;
+	struct message_size mime_hdr_size;
+	struct message_size mime_body_size;
+};
+
+static struct imap_msgpart *imap_msgpart_type(enum fetch_type fetch_type)
 {
-	struct message_part *part;
+	struct imap_msgpart *msgpart;
+	pool_t pool;
+
+	pool = pool_alloconly_create("imap msgpart", sizeof(*msgpart)+32);
+	msgpart = p_new(pool, struct imap_msgpart, 1);
+	msgpart->pool = pool;
+	msgpart->partial_size = (uoff_t)-1;
+	msgpart->fetch_type = fetch_type;
+	if (fetch_type == FETCH_HEADER || fetch_type == FETCH_FULL)
+		msgpart->wanted_fields |= MAIL_FETCH_STREAM_HEADER;
+	if (fetch_type == FETCH_BODY || fetch_type == FETCH_FULL)
+		msgpart->wanted_fields |= MAIL_FETCH_STREAM_BODY;
+	return msgpart;
+}
+
+struct imap_msgpart *imap_msgpart_full(void)
+{
+	return imap_msgpart_type(FETCH_FULL);
+}
+
+struct imap_msgpart *imap_msgpart_header(void)
+{
+	return imap_msgpart_type(FETCH_HEADER);
+}
+
+struct imap_msgpart *imap_msgpart_body(void)
+{
+	return imap_msgpart_type(FETCH_BODY);
+}
+
+static struct message_part *
+imap_msgpart_find(struct message_part *parts, const char *section)
+{
+	struct message_part *part = parts;
 	const char *path;
 	unsigned int num;
 
-	if (mail_get_parts(mail, &part) < 0)
-		return -1;
-
 	path = section;
 	while (*path >= '0' && *path <= '9' && part != NULL) {
 		/* get part number, we have already verified its validity */
@@ -53,21 +117,18 @@
 			part = part->children;
 		}
 	}
-
-	*part_r = part;
-	*subsection_r = path;
-	return 0;
+	i_assert(part == NULL || *path == '\0');
+	return part;
 }
 
 static int
-imap_msgpart_get_header_fields(const char *header_list,
-			       const char *const **fields_r, size_t *count_r)
+imap_msgpart_get_header_fields(pool_t pool, const char *header_list,
+			       ARRAY_TYPE(const_string) *fields)
 {
 	struct istream *input;
 	struct imap_parser *parser;
 	const struct imap_arg *args, *hdr_list;
 	unsigned int list_count;
-	ARRAY_TYPE(const_string) fields = ARRAY_INIT;
 	unsigned int i;
 	int result = 0;
 
@@ -76,304 +137,452 @@
 
 	if (imap_parser_finish_line(parser, 0, 0, &args) > 0 &&
 	    imap_arg_get_list_full(args, &hdr_list, &list_count) &&
+	    args[1].type == IMAP_ARG_EOL &&
 	    list_count > 0) {
 		const char *value;
 		
-		if (fields_r != NULL)
-			t_array_init(&fields, list_count);
-
+		p_array_init(fields, pool, list_count);
 		for (i = 0; i < list_count; i++) {
 			if (!imap_arg_get_astring(&hdr_list[i], &value)) {
 				result = -1;
 				break;
 			}
 
-			if (fields_r != NULL) {
-				value = t_str_ucase(value);
-				array_append(&fields, &value, 1);
-			}
-		}
-
-		if (fields_r != NULL) {
-			*fields_r = array_get(&fields, &list_count);
-			*count_r = list_count;
+			value = p_strdup(pool, t_str_ucase(value));
+			array_append(fields, &value, 1);
 		}
 	} else {
 		result = -1;
 	}
 
+	/* istream-header-filter requires headers to be sorted */
+	array_sort(fields, i_strcasecmp_p);
+
 	imap_parser_unref(&parser);
 	i_stream_unref(&input);
 	return result;
 }
 
 static int
-imap_msgpart_verify_header_fields(const char *header_list, const char **error_r)
+imap_msgpart_parse_header_fields(struct mailbox *box,
+				 struct imap_msgpart *msgpart,
+				 const char *header_list)
 {
+	ARRAY_TYPE(const_string) fields;
+
 	/* HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
-	if (imap_msgpart_get_header_fields(header_list, NULL, NULL) < 0) {
-		*error_r = "Invalid header fields";
+	if (imap_msgpart_get_header_fields(msgpart->pool, header_list,
+					   &fields) < 0)
+		return -1;
+
+	(void)array_append_space(&fields);
+	msgpart->headers = array_idx(&fields, 0);
+	msgpart->header_ctx = mailbox_header_lookup_init(box, msgpart->headers);
+	return 0;
+}
+
+int imap_msgpart_parse(struct mailbox *box, const char *section,
+		       struct imap_msgpart **msgpart_r)


More information about the dovecot-cvs mailing list