changeset 14594:27c8a6c9088d

Error handling API changes to previous IMAP URL related changes.
author Timo Sirainen <tss@iki.fi>
date Sat, 02 Jun 2012 19:01:25 +0300
parents e445670e7332
children 848be27099c8
files src/imap/cmd-append.c src/lib-imap-storage/imap-msgpart-url.c src/lib-imap-storage/imap-msgpart-url.h src/lib-imap-storage/imap-msgpart.c src/lib-imap-storage/imap-msgpart.h src/lib-imap/imap-url.c src/lib-imap/imap-url.h src/lib-imap/test-imap-url.c src/lib/uri-util.c src/lib/uri-util.h
diffstat 10 files changed, 191 insertions(+), 170 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-append.c	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/imap/cmd-append.c	Sat Jun 02 19:01:25 2012 +0300
@@ -220,8 +220,13 @@
 			if (ctx->failed)
 				return -1;
 
-			mpurl = imap_msgpart_url_parse(client->user, client->mailbox, caturl, &error);
-			if (mpurl == NULL) {
+			ret = imap_msgpart_url_parse(client->user, client->mailbox,
+						     caturl, &mpurl, &error);
+			if (ret < 0) {
+				client_send_storage_error(cmd, ctx->storage);
+				return -1;
+			}
+			if (ret == 0) {
 				/* invalid url, abort */
 				client_send_tagline(cmd,
 					t_strdup_printf("NO [BADURL %s] %s.", caturl, error));
@@ -239,7 +244,12 @@
 				struct istream *input = NULL;
 				uoff_t size;
 
-				if (!imap_msgpart_url_read_part(mpurl, &input, &size, &error)) {
+				ret = imap_msgpart_url_read_part(mpurl, &input, &size, &error);
+				if (ret < 0) {
+					client_send_storage_error(cmd, ctx->storage);
+					return -1;
+				}
+				if (ret == 0) {
 					/* invalid url, abort */
 					client_send_tagline(cmd,
 						t_strdup_printf("NO [BADURL %s] %s.", caturl, error));
--- a/src/lib-imap-storage/imap-msgpart-url.c	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib-imap-storage/imap-msgpart-url.c	Sat Jun 02 19:01:25 2012 +0300
@@ -44,9 +44,9 @@
 	return mpurl;
 }
 
-struct imap_msgpart_url *
-imap_msgpart_url_parse(struct mail_user *user, struct mailbox *selected_box,
-		       const char *urlstr, const char **error_r)
+int imap_msgpart_url_parse(struct mail_user *user, struct mailbox *selected_box,
+			   const char *urlstr, struct imap_msgpart_url **url_r,
+			   const char **error_r)
 {
 	struct mailbox_status box_status;
 	struct imap_url base_url, *url;
@@ -62,21 +62,21 @@
 	}
 
 	/* parse url */
-	url = imap_url_parse(urlstr, NULL, &base_url,
-			     IMAP_URL_PARSE_REQUIRE_RELATIVE, &error);
-	if (url == NULL) {
+	if (imap_url_parse(urlstr, &base_url,
+			   IMAP_URL_PARSE_REQUIRE_RELATIVE, &url, &error) < 0) {
 		*error_r = t_strconcat("Invalid IMAP URL: ", error, NULL);
-		return NULL;
+		return -1;
 	}
 	if (url->mailbox == NULL) {
 		*error_r = "Mailbox-relative IMAP URL, but no mailbox selected";
-		return NULL;
+		return -1;
 	}
 	if (url->uid == 0 || url->search_program != NULL) {
 		*error_r = "Invalid messagepart IMAP URL";
-		return NULL;
+		return -1;
 	}
-	return imap_msgpart_url_create(user, url);
+	*url_r = imap_msgpart_url_create(user, url);
+	return 0;
 }
 
 struct mailbox *imap_msgpart_url_get_mailbox(struct imap_msgpart_url *mpurl)
@@ -84,9 +84,8 @@
 	return mpurl->box;
 }
 
-struct mailbox *
-imap_msgpart_url_open_mailbox(struct imap_msgpart_url *mpurl,
-			      const char **error_r)
+int imap_msgpart_url_open_mailbox(struct imap_msgpart_url *mpurl,
+				  struct mailbox **box_r, const char **error_r)
 {
 	struct mailbox_status box_status;
 	enum mail_error error_code;
@@ -94,14 +93,16 @@
 	struct mail_namespace *ns;
 	struct mailbox *box;
 
-	if (mpurl->box != NULL)
-		return mpurl->box;
+	if (mpurl->box != NULL) {
+		*box_r = mpurl->box;
+		return 1;
+	}
 
 	/* find mailbox namespace */
 	ns = mail_namespace_find(mpurl->user->namespaces, mpurl->mailbox);
 	if (ns == NULL) {
 		*error_r = "Nonexistent mailbox namespace";
-		return NULL;
+		return 0;
 	}
 
 	/* open mailbox */
@@ -110,7 +111,7 @@
 		*error_r = mail_storage_get_last_error(mailbox_get_storage(box),
 						       &error_code);
 		mailbox_free(&box);
-		return NULL;
+		return error_code == MAIL_ERROR_TEMP ? -1 : 0;
 	}
 
 	/* verify UIDVALIDITY */
@@ -119,29 +120,32 @@
 	    box_status.uidvalidity != mpurl->uidvalidity) {
 		*error_r = "Invalid UIDVALIDITY";
 		mailbox_free(&box);
-		return NULL;
+		return 0;
 	}
 	mpurl->box = box;
-	return box;
+	*box_r = box;
+	return 1;
 }
 
-struct mail *
-imap_msgpart_url_open_mail(struct imap_msgpart_url *mpurl, const char **error_r)
+int imap_msgpart_url_open_mail(struct imap_msgpart_url *mpurl,
+			       struct mail **mail_r, const char **error_r)
 {
 	struct mailbox_transaction_context *t;
+	struct mailbox *box;
 	struct mail *mail;
+	int ret;
 
-	if (mpurl->mail != NULL)
-		return mpurl->mail;
+	if (mpurl->mail != NULL) {
+		*mail_r = mpurl->mail;
+		return 1;
+	}
 
 	/* open mailbox if it is not yet open */
-	if (mpurl->box == NULL) {
-		if (imap_msgpart_url_open_mailbox(mpurl, error_r) == NULL)
-			return NULL;
-	}
+	if ((ret = imap_msgpart_url_open_mailbox(mpurl, &box, error_r)) <= 0)
+		return ret;
 
 	/* start transaction */
-	t = mailbox_transaction_begin(mpurl->box, 0);
+	t = mailbox_transaction_begin(box, 0);
 	mail = mail_alloc(t, 0, NULL);
 
 	/* find the message */
@@ -149,64 +153,64 @@
 		*error_r = "Message not found";
 		mail_free(&mail);
 		mailbox_transaction_rollback(&t);	
-		return NULL;
+		return 0;
 	}
 
 	mpurl->trans = t;
 	mpurl->mail = mail;
-	return mail;
+	*mail_r = mail;
+	return 1;
 }
 
-bool imap_msgpart_url_read_part(struct imap_msgpart_url *mpurl,
-				struct istream **stream_r, uoff_t *size_r,
-				const char **error_r)
+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;
+	int ret;
 
 	if (mpurl->input != NULL) {
 		i_stream_seek(mpurl->input, 0);
 		*stream_r = mpurl->input;
 		*size_r = mpurl->part_size;
-		return TRUE;
+		return 1;
 	}
 
-	/* open mailbox if it is not yet open */
-	if (mpurl->mail == NULL) {
-		if (imap_msgpart_url_open_mail(mpurl, error_r) == NULL)
-			return FALSE;
-	}
+	/* 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 */
-	if (!imap_msgpart_open(mpurl->mail, mpurl->section,
-			       mpurl->partial_offset, mpurl->partial_size,
-			       &input, &part_size, error_r))
-		return FALSE;
+	if ((ret = imap_msgpart_open(mail, mpurl->section,
+				     mpurl->partial_offset, mpurl->partial_size,
+				     &input, &part_size, error_r)) <= 0)
+		return ret;
 
 	mpurl->input = input;
 	mpurl->part_size = part_size;
 
 	*stream_r = input;
 	*size_r = part_size;
-	return TRUE;
+	return 1;
 }
 
-bool imap_msgpart_url_verify(struct imap_msgpart_url *mpurl,
-			     const char **error_r)
+int imap_msgpart_url_verify(struct imap_msgpart_url *mpurl,
+			    const char **error_r)
 {
-	if (mpurl->input != NULL)
-		return TRUE;
+	struct mail *mail;
+	int ret;
 
-	/* open mailbox if it is not yet open */
-	if (mpurl->mail == NULL) {
-		if (imap_msgpart_url_open_mail(mpurl, error_r) == NULL)
-			return FALSE;
-	}
+	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 */
-	if (!imap_msgpart_verify(mpurl->mail, mpurl->section, error_r))
-		return FALSE;
-	return TRUE;
+	return imap_msgpart_verify(mail, mpurl->section, error_r);
 }
 
 void imap_msgpart_url_free(struct imap_msgpart_url **_mpurl)
--- a/src/lib-imap-storage/imap-msgpart-url.h	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib-imap-storage/imap-msgpart-url.h	Sat Jun 02 19:01:25 2012 +0300
@@ -4,26 +4,28 @@
 struct imap_url;
 struct imap_msgpart_url;
 
+/* Functions returning int return 1 on success, 0 if URL doesn't point to
+   valid mail, -1 on storage error. */
+
 struct imap_msgpart_url *
 imap_msgpart_url_create(struct mail_user *user, const struct imap_url *url);
-struct imap_msgpart_url *
-imap_msgpart_url_parse(struct mail_user *user, struct mailbox *selected_box,
-		       const char *urlstr, const char **error_r);
+int imap_msgpart_url_parse(struct mail_user *user, struct mailbox *selected_box,
+			   const char *urlstr, struct imap_msgpart_url **url_r,
+			   const char **error_r);
 
-struct mailbox *
-imap_msgpart_url_open_mailbox(struct imap_msgpart_url *mpurl,
-			      const char **error_r);
+int imap_msgpart_url_open_mailbox(struct imap_msgpart_url *mpurl,
+				  struct mailbox **box_r, const char **error_r);
 struct mailbox *imap_msgpart_url_get_mailbox(struct imap_msgpart_url *mpurl);
-struct mail *
-imap_msgpart_url_open_mail(struct imap_msgpart_url *mpurl, const char **error_r);
+int imap_msgpart_url_open_mail(struct imap_msgpart_url *mpurl,
+			       struct mail **mail_r, const char **error_r);
 
-/* Returns NULL stream when part has zero length, e.g. when partial offset is
-   larger than the size of the referenced part */
-bool imap_msgpart_url_read_part(struct imap_msgpart_url *mpurl,
-				struct istream **stream_r, uoff_t *size_r,
-				const char **error_r);
-bool imap_msgpart_url_verify(struct imap_msgpart_url *mpurl,
-			     const char **error_r);
+/* stream_r is set to NULL when part has zero length, e.g. when partial offset
+   is larger than the size of the referenced part */
+int imap_msgpart_url_read_part(struct imap_msgpart_url *mpurl,
+			       struct istream **stream_r, uoff_t *size_r,
+			       const char **error_r);
+int imap_msgpart_url_verify(struct imap_msgpart_url *mpurl,
+			    const char **error_r);
 void imap_msgpart_url_free(struct imap_msgpart_url **mpurl);
 
 #endif
--- a/src/lib-imap-storage/imap-msgpart.c	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib-imap-storage/imap-msgpart.c	Sat Jun 02 19:01:25 2012 +0300
@@ -59,7 +59,7 @@
 	return 0;
 }
 
-static bool
+static int
 imap_msgpart_get_header_fields(const char *header_list,
 			       const char *const **fields_r, size_t *count_r)
 {
@@ -69,7 +69,7 @@
 	unsigned int list_count;
 	ARRAY_TYPE(const_string) fields = ARRAY_INIT;
 	unsigned int i;
-	bool result = TRUE;
+	int result = 0;
 
 	input = i_stream_create_from_data(header_list, strlen(header_list));
 	parser = imap_parser_create(input, NULL, (size_t)-1);
@@ -84,7 +84,7 @@
 
 		for (i = 0; i < list_count; i++) {
 			if (!imap_arg_get_astring(&hdr_list[i], &value)) {
-				result = FALSE;
+				result = -1;
 				break;
 			}
 
@@ -99,24 +99,23 @@
 			*count_r = list_count;
 		}
 	} else {
-		result = FALSE;
+		result = -1;
 	}
 
 	imap_parser_unref(&parser);
 	i_stream_unref(&input);
-
 	return result;
 }
 
-static bool
+static int
 imap_msgpart_verify_header_fields(const char *header_list, const char **error_r)
 {
 	/* HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
-	if (!imap_msgpart_get_header_fields(header_list, NULL, NULL)) {
+	if (imap_msgpart_get_header_fields(header_list, NULL, NULL) < 0) {
 		*error_r = "Invalid header fields";
-		return FALSE;
+		return 0;
 	}
-	return TRUE;
+	return 1;
 }
 
 static struct istream *
@@ -131,7 +130,8 @@
 	uoff_t old_offset;
 
 	/* HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
-	if (!imap_msgpart_get_header_fields(header_list, &hdr_fields, &hdr_count)) {
+	if (imap_msgpart_get_header_fields(header_list,
+					   &hdr_fields, &hdr_count) < 0) {
 		*error_r = "Invalid header fields";
 		return NULL;
 	}
@@ -158,8 +158,8 @@
 	return input;
 }
 
-static bool
-imap_msgpart_get_partial(struct istream *input, struct message_size part_size,
+static void
+imap_msgpart_get_partial(struct istream **input, struct message_size part_size,
 			 uoff_t partial_offset, uoff_t partial_size,
 			 struct istream **stream_r, uoff_t *size_r)
 {
@@ -167,35 +167,34 @@
 	uoff_t size = part_size.virtual_size;
 
 	if (partial_offset >= size) {
-		i_stream_unref(&input);
+		i_stream_unref(input);
 		*size_r = 0;
 		*stream_r = NULL;
-		return TRUE;
+		return;
 	}
 
 	if (size != part_size.physical_size) {
-		result = i_stream_create_crlf(input);
-		i_stream_unref(&input);
-		input = result;
+		result = i_stream_create_crlf(*input);
+		i_stream_unref(input);
+		*input = result;
 	}
 
 	if (partial_offset > 0)
-		i_stream_seek(input, input->v_offset + partial_offset);
+		i_stream_seek(*input, (*input)->v_offset + partial_offset);
 
 	size = partial_size > 0 && (size - partial_offset) > partial_size ?
 		partial_size : (size - partial_offset);
-	result = i_stream_create_limit(input, size);
-	i_stream_unref(&input);
+	result = i_stream_create_limit(*input, size);
+	i_stream_unref(input);
 	
 	*size_r = size;
 	*stream_r = result;
-	return TRUE;
 }
 
-bool imap_msgpart_open(struct mail *mail, const char *section,
-		       uoff_t partial_offset, uoff_t partial_size,
-		       struct istream **stream_r,
-		       uoff_t *size_r, const char **error_r)
+int imap_msgpart_open(struct mail *mail, const char *section,
+		      uoff_t partial_offset, uoff_t partial_size,
+		      struct istream **stream_r,
+		      uoff_t *size_r, const char **error_r)
 {
 	struct message_size hdr_size, body_size, part_size;
 	struct istream *input = NULL;
@@ -204,14 +203,14 @@
 	if (stream_r != NULL) {
 		if (mail_get_stream(mail, &hdr_size, &body_size, &input) < 0) {
 			*error_r = "Failed to read message";
-			return FALSE;
+			return -1;
 		}
 	}
 
 	if (section == NULL || *section == '\0') {
 		/* full message */
 		if (stream_r == NULL)
-			return TRUE;
+			return 1;
 
 		part_size.physical_size =
 			hdr_size.physical_size + body_size.physical_size;
@@ -220,9 +219,10 @@
 
 		i_stream_seek(input, 0);
 		i_stream_ref(input);
-		return imap_msgpart_get_partial(input, part_size,
-						partial_offset, partial_size,
-						stream_r, size_r);
+		imap_msgpart_get_partial(&input, part_size,
+					 partial_offset, partial_size,
+					 stream_r, size_r);
+		return 1;
 	}
 
 	section = t_str_ucase(section);
@@ -230,20 +230,21 @@
 	if (strcmp(section, "TEXT") == 0) {
 		/* message body */
 		if (stream_r == NULL)
-			return TRUE;
-		
+			return 1;
+
 		i_stream_seek(input, hdr_size.physical_size);
 		i_stream_ref(input);
-		return imap_msgpart_get_partial(input, body_size,
-						partial_offset, partial_size,
-						stream_r, size_r);
+		imap_msgpart_get_partial(&input, body_size,
+					 partial_offset, partial_size,
+					 stream_r, size_r);
+		return 1;
 	}
 
 	if (strncmp(section, "HEADER", 6) == 0) {
 		/* header */
 		if (stream_r == NULL) {
 			if (section[6] == '\0') {
-				return TRUE;
+				return 1;
 			} else if (strncmp(section, "HEADER.FIELDS ", 14) == 0) {
 				return imap_msgpart_verify_header_fields(section+14, error_r);
 			} else if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0) {
@@ -265,53 +266,57 @@
 			}
 
 			if (input != NULL) {
-				return imap_msgpart_get_partial(input,
-					hdr_size, partial_offset, partial_size,
+				imap_msgpart_get_partial(&input, hdr_size,
+					partial_offset, partial_size,
 					stream_r, size_r);
+				return 1;
 			}
 		}
-
 	} else if (*section >= '0' && *section <= '9') {
 		const struct message_part *part;
 		const char *subsection;
 
 		if (imap_msgpart_find(mail, section, &part, &subsection) < 0) {
 			*error_r = "Cannot read message part";
-			return FALSE;
+			return -1;
 		}
 
 		if (part == NULL) {
 			*error_r = "Unknown message part";
-			return FALSE;
+			return 0;
 		}
 
 		if (*subsection == '\0') {
 			if (stream_r == NULL)
-				return TRUE;
+				return 1;
 		
 			/* fetch the whole section */
 			i_stream_seek(input, part->physical_pos +
 				      part->header_size.physical_size);
 			i_stream_ref(input);
-			return imap_msgpart_get_partial(input, part->body_size, partial_offset,
-					partial_size, stream_r, size_r);
+			imap_msgpart_get_partial(&input, part->body_size,
+						 partial_offset, partial_size,
+						 stream_r, size_r);
+			return 1;
 		}
 
 		if (strcmp(subsection, "MIME") == 0) {
 			if (stream_r == NULL)
-				return TRUE;
+				return 1;
 
 			/* fetch section's MIME header */
 			i_stream_seek(input, part->physical_pos);
 			i_stream_ref(input);
-			return imap_msgpart_get_partial(input, part->header_size,
-				partial_offset, partial_size, stream_r, size_r);
+			imap_msgpart_get_partial(&input, part->header_size,
+						 partial_offset, partial_size,
+						 stream_r, size_r);
+			return 1;
 		}
 
 		/* TEXT and HEADER are only for message/rfc822 parts */
 		if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) == 0) {
 			*error_r = "Invalid section";
-			return FALSE;
+			return 0;
 		}
 
 		i_assert(part->children != NULL && part->children->next == NULL);
@@ -319,20 +324,22 @@
 
 		if (strcmp(subsection, "TEXT") == 0) {
 			if (stream_r == NULL)
-				return TRUE;
+				return 1;
 
 			/* sub-message body */
 			i_stream_seek(input, part->physical_pos +
 				      part->header_size.physical_size);
 			i_stream_ref(input);
-			return imap_msgpart_get_partial(input, part->body_size,
-				partial_offset, partial_size, stream_r, size_r);
+			imap_msgpart_get_partial(&input, part->body_size,
+						 partial_offset, partial_size,
+						 stream_r, size_r);
+			return 1;
 		}	
 
 		if (strncmp(subsection, "HEADER", 6) == 0) {
 			if (stream_r == NULL) {
 				if (section[6] == '\0') {
-					return TRUE;
+					return 1;
 				} else if (strncmp(subsection, "HEADER.FIELDS ", 14) == 0) {
 					return imap_msgpart_verify_header_fields(subsection+14, error_r);
 				} else if (strncmp(subsection, "HEADER.FIELDS.NOT ", 18) == 0) {
@@ -358,14 +365,15 @@
 				}
 
 				if (input != NULL) {
-					return imap_msgpart_get_partial(input,
-						hdr_size, partial_offset,
-						partial_size, stream_r, size_r);
+					imap_msgpart_get_partial(&input, hdr_size,
+						partial_offset, partial_size,
+						stream_r, size_r);
+					return 1;
 				}
 			}
 		}
 	}
 
 	*error_r = "Invalid section";
-	return FALSE;
+	return 0;
 }
--- a/src/lib-imap-storage/imap-msgpart.h	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib-imap-storage/imap-msgpart.h	Sat Jun 02 19:01:25 2012 +0300
@@ -1,20 +1,21 @@
 #ifndef IMAP_MSGPART_H
 #define IMAP_MSGPART_H
 
-/* Find message_part for section (eg. 1.3.4) */
+/* Find message_part for section (eg. 1.3.4). Returns -1 if storage error,
+   0 otherwise. part_r is set to NULL if section doesn't exist. */
 int imap_msgpart_find(struct mail *mail, const char *section,
 		      const struct message_part **part_r,
 		      const char **subsection_r);
 
-/* Open message part refenced by IMAP section as istream. Returns TRUE on
-   success and FALSE otherwise. Returned stream_r stream may be NULL when there
-   is no data to return. */
-bool imap_msgpart_open(struct mail *mail, const char *section,
-		       uoff_t partial_offset, uoff_t partial_size,
-		       struct istream **stream_r,
-		       uoff_t *size_r, const char **error_r);
+/* Open message part refenced by IMAP section as istream. Returns 1 if
+   successful, 0 if section is invalid, -1 if storage error. Returned stream_r
+   stream may be NULL when there is no data to return. */
+int imap_msgpart_open(struct mail *mail, const char *section,
+		      uoff_t partial_offset, uoff_t partial_size,
+		      struct istream **stream_r,
+		      uoff_t *size_r, const char **error_r);
 
-static inline bool
+static inline int
 imap_msgpart_verify(struct mail *mail, const char *section,
 		    const char **error_r)
 {
--- a/src/lib-imap/imap-url.c	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib-imap/imap-url.c	Sat Jun 02 19:01:25 2012 +0300
@@ -893,34 +893,31 @@
 
 /* Public API */
 
-struct imap_url *
-imap_url_parse(const char *url, pool_t pool, struct imap_url *base,
-	       enum imap_url_parse_flags flags, const char **error_r)
+int imap_url_parse(const char *url, struct imap_url *base,
+		   enum imap_url_parse_flags flags,
+		   struct imap_url **url_r, const char **error_r)
 {
 	struct imap_url_parser url_parser;
 
-	if (pool == NULL)
-		pool = pool_datastack_create();
-
 	/* base != NULL indicates whether relative URLs are allowed. However, certain
 	   flags may also dictate whether relative URLs are allowed/required. */
 	i_assert((flags & IMAP_URL_PARSE_REQUIRE_RELATIVE) == 0 || base != NULL);
 	i_assert((flags & IMAP_URL_PARSE_SCHEME_EXTERNAL) == 0 || base == NULL);
 
 	memset(&url_parser, '\0', sizeof(url_parser));
-	uri_parser_init(&url_parser.parser, pool, url);
+	uri_parser_init(&url_parser.parser, pool_datastack_create(), url);
 
-	url_parser.url = p_new(pool, struct imap_url, 1);
+	url_parser.url = t_new(struct imap_url, 1);
 	url_parser.url->uauth_expire = (time_t)-1;
 	url_parser.base = base;
 	url_parser.flags = flags;
 
 	if (!imap_url_do_parse(&url_parser)) {
-		if (error_r != NULL)
-			*error_r = url_parser.parser.error;
-		return NULL;
+		*error_r = url_parser.parser.error;
+		return -1;
 	}
-	return url_parser.url;
+	*url_r = url_parser.url;
+	return 0;
 }
 
 /*
--- a/src/lib-imap/imap-url.h	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib-imap/imap-url.h	Sat Jun 02 19:01:25 2012 +0300
@@ -55,10 +55,10 @@
 	IMAP_URL_PARSE_ALLOW_URLAUTH	= 0x04
 };
 
-/* Parses full IMAP URL */
-struct imap_url *
-imap_url_parse(const char *url, pool_t pool, struct imap_url *base,
-	       enum imap_url_parse_flags flags, const char **error_r);
+/* Parses full IMAP URL. The returned URL is allocated from data stack. */
+int imap_url_parse(const char *url, struct imap_url *base,
+		   enum imap_url_parse_flags flags,
+		   struct imap_url **url_r, const char **error_r);
 
 /*
  * IMAP URL construction
--- a/src/lib-imap/test-imap-url.c	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib-imap/test-imap-url.c	Sat Jun 02 19:01:25 2012 +0300
@@ -562,7 +562,8 @@
 		test_begin(t_strdup_printf("imap url valid [%d]", i));
 
 		if (urlb->host_name == NULL) urlb = NULL;
-		urlp=imap_url_parse(url, NULL, urlb, flags, &error);
+		if (imap_url_parse(url, urlb, flags, &urlp, &error) < 0)
+			urlp = NULL;
 
 		test_out_reason(t_strdup_printf("imap_url_parse(%s)",
 			valid_url_tests[i].url), urlp != NULL, error);
@@ -881,7 +882,8 @@
 
 		test_begin(t_strdup_printf("imap url invalid [%d]", i));
 
-		urlp = imap_url_parse(url, NULL, urlb, flags, &error);
+		if (imap_url_parse(url, urlb, flags, &urlp, &error) < 0)
+			urlp = NULL;
 		test_out_reason(t_strdup_printf("parse %s", url), urlp == NULL, error);
 
 		test_end();
--- a/src/lib/uri-util.c	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib/uri-util.c	Sat Jun 02 19:01:25 2012 +0300
@@ -202,10 +202,9 @@
 	return TRUE;
 }
 
-const char *uri_cut_scheme(const char **uri_p)
+int uri_cut_scheme(const char **uri_p, const char **scheme_r)
 {
 	const char *p = *uri_p;
-	const char *scheme;
 	size_t len = 1;
 	
 	/* RFC 3968:
@@ -213,7 +212,7 @@
 	 */
 	
 	if (!i_isalpha(*p))
-		return NULL;		
+		return -1;
 	p++;
 		
 	while (len < URI_MAX_SCHEME_NAME_LEN && *p != '\0') {			
@@ -224,12 +223,11 @@
 	}
 	
 	if (*p != ':')
-		return NULL;
+		return -1;
 	
-	scheme = t_strdup_until(*uri_p, p);
+	*scheme_r = t_strdup_until(*uri_p, p);
 	*uri_p = p + 1;
-
-	return scheme;
+	return 0;
 }
 
 int uri_parse_scheme(struct uri_parser *parser, const char **scheme_r)
@@ -240,8 +238,8 @@
 		return 0;
 
 	p = (const char *)parser->cur;
-	if ((*scheme_r = uri_cut_scheme(&p)) == NULL)
-		return 0;
+	if (uri_cut_scheme(&p, scheme_r) < 0)
+		return -1;
 
 	parser->cur = (const unsigned char *)p;
 	return 1;
@@ -266,7 +264,7 @@
 	while (parser->cur < parser->end && i_isdigit(*parser->cur)) {
 		uint8_t prev = octet;
 
-		octet = octet * 10 + (uint8_t)(parser->cur[0] - '0');
+		octet = octet * 10 + (parser->cur[0] - '0');
 		if (octet < prev)
 			return -1;
 
@@ -671,8 +669,7 @@
 	return 1;
 }
 
-int uri_parse_fragment
-(struct uri_parser *parser, const char **fragment_r)
+int uri_parse_fragment(struct uri_parser *parser, const char **fragment_r)
 {
 	const unsigned char *p = parser->cur;
 
--- a/src/lib/uri-util.h	Sat Jun 02 18:15:46 2012 +0300
+++ b/src/lib/uri-util.h	Sat Jun 02 19:01:25 2012 +0300
@@ -31,7 +31,7 @@
 bool uri_data_decode(struct uri_parser *parser, const char *data,
 		     const char *until, const char **decoded_r);
 
-const char *uri_cut_scheme(const char **uri_p);
+int uri_cut_scheme(const char **uri_p, const char **scheme_r);
 int uri_parse_scheme(struct uri_parser *parser, const char **scheme_r);
 int uri_parse_authority(struct uri_parser *parser, struct uri_authority *auth);