dovecot-2.2: Added support for creating IMAP URLs.

dovecot at dovecot.org dovecot at dovecot.org
Fri Sep 14 21:03:20 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/345e96ca65a2
changeset: 15045:345e96ca65a2
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Fri Sep 14 21:02:23 2012 +0300
description:
Added support for creating IMAP URLs.

diffstat:

 src/lib-imap/imap-url.c      |   93 +++++++++++++++++++++++++++
 src/lib-imap/imap-url.h      |    8 +-
 src/lib-imap/test-imap-url.c |   67 +++++++++++++++++++
 src/lib/uri-util.c           |  146 ++++++++++++++++++++++++++++++++++++++++--
 src/lib/uri-util.h           |   24 ++++++-
 5 files changed, 325 insertions(+), 13 deletions(-)

diffs (truncated from 503 to 300 lines):

diff -r 460db6251639 -r 345e96ca65a2 src/lib-imap/imap-url.c
--- a/src/lib-imap/imap-url.c	Thu Sep 13 17:12:59 2012 +0300
+++ b/src/lib-imap/imap-url.c	Fri Sep 14 21:02:23 2012 +0300
@@ -689,6 +689,8 @@
 		/* [ipartial] */
 		if (*segment != NULL &&
 		    strncasecmp(*segment, ";PARTIAL=", 9) == 0) {
+			have_partial = TRUE;
+
 			/* ";PARTIAL=" partial-range */
 			value = (*segment) + 9;
 			if ((p = strchr(value,';')) != NULL) {
@@ -754,6 +756,7 @@
 		url->uid = uid;
 		if (section != NULL)
 			url->section = p_strdup(parser->pool, str_c(section));
+		url->have_partial = have_partial;
 		url->partial_offset = partial_offset;
 		url->partial_size = partial_size;
 	}
@@ -925,6 +928,96 @@
  * IMAP URL construction
  */
 
+static void
+imap_url_append_mailbox(const struct imap_url *url, string_t *urlstr)
+{
+	uri_append_path_data(urlstr, ";", url->mailbox);
+	if (url->uidvalidity != 0)
+		str_printfa(urlstr, ";UIDVALIDITY=%u", url->uidvalidity);
+	if (url->uid == 0) {
+		/* message list */
+		if (url->search_program != NULL) {
+			str_append_c(urlstr, '?');
+			uri_append_query_data(urlstr, ";", url->search_program);
+		}
+	} else {
+		/* message part */
+		str_printfa(urlstr, "/;UID=%u", url->uid);
+		if (url->section != NULL) {
+			str_append(urlstr, "/;SECTION=");
+			uri_append_path_data(urlstr, ";", url->section);
+		}
+		if (url->have_partial) {
+			str_append(urlstr, "/;PARTIAL=");
+			if (url->partial_size == 0) {
+				str_printfa(urlstr, "%"PRIuUOFF_T,
+					    url->partial_offset);
+			} else {
+				str_printfa(urlstr, "%"PRIuUOFF_T".%"PRIuUOFF_T,
+					    url->partial_offset,
+					    url->partial_size);
+			}
+		}
+
+		/* urlauth */
+		if (url->uauth_access_application != NULL) {
+			if (url->uauth_expire != (time_t)-1) {
+				str_append(urlstr, ";EXPIRE=");
+				str_append(urlstr, iso8601_date_create(url->uauth_expire));
+			}
+			str_append(urlstr, ";URLAUTH=");
+			str_append(urlstr, url->uauth_access_application);
+			if (url->uauth_access_user != NULL) {
+				str_append_c(urlstr, '+');
+				uri_append_user_data(urlstr, ";",
+						     url->uauth_access_user);
+			}
+		}
+	}
+}
+
+const char *imap_url_create(const struct imap_url *url)
+{
+	string_t *urlstr = t_str_new(512);
+
+	/* scheme */
+	uri_append_scheme(urlstr, "imap");
+	str_append(urlstr, "//");
+
+	/* user */
+	if (url->userid != NULL || url->auth_type != NULL) {
+		if (url->userid != NULL)
+			uri_append_user_data(urlstr, ";", url->userid);
+		if (url->auth_type != NULL) {
+			str_append(urlstr, ";AUTH=");
+			uri_append_user_data(urlstr, ";", url->auth_type);
+		}
+		str_append_c(urlstr, '@');
+	}
+
+	/* server */
+	if (url->host_name != NULL) {
+		/* assume IPv6 literal if starts with '['; avoid encoding */
+		if (*url->host_name == '[')
+			str_append(urlstr, url->host_name);
+		else
+			uri_append_host_name(urlstr, url->host_name);
+	} else if (url->have_host_ip) {
+		uri_append_host_ip(urlstr, &url->host_ip);
+	} else
+		i_unreached();
+	if (url->have_port)
+		uri_append_port(urlstr, url->port);
+
+	/* Older syntax (RFC 2192) requires this slash at all times */
+	str_append_c(urlstr, '/');
+
+	/* mailbox */
+	if (url->mailbox != NULL)
+		imap_url_append_mailbox(url, urlstr);
+	return str_c(urlstr);
+}
+
 const char *
 imap_url_add_urlauth(const char *rumpurl, const char *mechanism,
 		     const unsigned char *token, size_t token_len)
diff -r 460db6251639 -r 345e96ca65a2 src/lib-imap/imap-url.h
--- a/src/lib-imap/imap-url.h	Thu Sep 13 17:12:59 2012 +0300
+++ b/src/lib-imap/imap-url.h	Fri Sep 14 21:02:23 2012 +0300
@@ -19,7 +19,7 @@
 	uint32_t uid;
 	const char *section;
 	uoff_t partial_offset;
-	uoff_t partial_size;
+	uoff_t partial_size; /* 0 if not set */
 
 	/* message list (uid == 0) */
 	const char *search_program;
@@ -31,9 +31,9 @@
 	const char *uauth_mechanism;
 	const unsigned char *uauth_token;
 	size_t uauth_token_size;
-	time_t uauth_expire;
+	time_t uauth_expire; /* (time_t)-1 if not set */
 
-	unsigned int have_host_ip:1;
+	unsigned int have_host_ip:1; /* url uses IP address */
 	unsigned int have_port:1;
 	unsigned int have_partial:1;
 };
@@ -64,6 +64,8 @@
  * IMAP URL construction
  */
 
+const char *imap_url_create(const struct imap_url *url);
+
 const char *imap_url_add_urlauth(const char *rumpurl, const char *mechanism,
 				 const unsigned char *token, size_t token_len);
 
diff -r 460db6251639 -r 345e96ca65a2 src/lib-imap/test-imap-url.c
--- a/src/lib-imap/test-imap-url.c	Thu Sep 13 17:12:59 2012 +0300
+++ b/src/lib-imap/test-imap-url.c	Fri Sep 14 21:02:23 2012 +0300
@@ -53,12 +53,14 @@
 			.host_name = "127.0.0.1",
 			.userid = "user",
 			.have_host_ip = TRUE }
+#ifdef HAVE_IPV6
 	},{
 		.url = "imap://user@[::1]",
 		.url_parsed = {
 			.host_name = "[::1]",
 			.userid = "user",
 			.have_host_ip = TRUE }
+#endif
 	},{
 		.url = "imap://user@4example.com:423",
 		.url_parsed = {
@@ -738,8 +740,10 @@
 		.url = "imap://[]/INBOX"
 	},{
 		.url = "imap://[v08.234:232:234:234:2221]/INBOX"
+#ifdef HAVE_IPV6
 	},{
 		.url = "imap://[1::34a:34:234::6]/INBOX"
+#endif
 	},{
 		.url = "imap://example%a.com/INBOX"
 	},{
@@ -891,11 +895,74 @@
 
 }
 
+const char *parse_create_url_tests[] = {
+	"imap://host.example.com/",
+	"imap://[::1]/",
+	"imap://10.0.0.1/",
+	"imap://user@host.example.com/",
+	"imap://user@host.example.com:993/",
+	"imap://user;AUTH=PLAIN@host.example.com/",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX/;UID=5",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX;UIDVALIDITY=15/;UID=5",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX;UIDVALIDITY=15/;UID=5"
+		"/;SECTION=TEXT",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX;UIDVALIDITY=15/;UID=5"
+		"/;SECTION=TEXT/;PARTIAL=1",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX;UIDVALIDITY=15/;UID=5"
+		"/;SECTION=TEXT/;PARTIAL=1.14",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX;UIDVALIDITY=15/;UID=5"
+		"/;SECTION=TEXT/;PARTIAL=1.14;URLAUTH=anonymous",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX;UIDVALIDITY=15/;UID=5"
+		"/;SECTION=TEXT/;PARTIAL=1.14;URLAUTH=user+username",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX/?SUBJECT%20%22Frop?%22",
+	"imap://host.%23example.com/",
+	"imap://user%3ba@host.example.com/",
+	"imap://user%40example.com@host.example.com/",
+	"imap://user%40example.com;AUTH=STR%23ANGE@host.example.com/",
+	"imap://user;AUTH=PLAIN@host.example.com/INBOX/Important%3bWork",
+	"imap://user@host.example.com/%23shared/news",
+	"imap://user@host.example.com/INBOX;UIDVALIDITY=15/;UID=5"
+		"/;SECTION=HEADER.FIELDS%20(DATE%20FROM)",
+	"imap://user@host.example.com/INBOX;UIDVALIDITY=15/;UID=5"
+		"/;SECTION=TEXT/;PARTIAL=1.14;URLAUTH=user+user%3bname",
+};
+
+unsigned int parse_create_url_test_count = N_ELEMENTS(parse_create_url_tests);
+
+static void test_imap_url_parse_create(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < parse_create_url_test_count; i++) T_BEGIN {
+		const char *url = parse_create_url_tests[i];
+		struct imap_url *urlp;
+		const char *error = NULL;
+
+		test_begin(t_strdup_printf("imap url parse/create [%d]", i));
+
+		if (imap_url_parse
+			(url, NULL, IMAP_URL_PARSE_ALLOW_URLAUTH, &urlp, &error) < 0)
+			urlp = NULL;
+		test_out_reason(t_strdup_printf("parse  %s", url), urlp != NULL, error);
+		if (urlp != NULL) {
+			const char *urlnew = imap_url_create(urlp);
+			test_out(t_strdup_printf
+				("create %s", urlnew), strcmp(url, urlnew) == 0);
+		}
+
+		test_end();
+	} T_END;
+
+}
+
+
 int main(void)
 {
 	static void (*test_functions[])(void) = {
 		test_imap_url_valid,
 		test_imap_url_invalid,
+		test_imap_url_parse_create,
 		NULL
 	};
 	return test_run(test_functions);
diff -r 460db6251639 -r 345e96ca65a2 src/lib/uri-util.c
--- a/src/lib/uri-util.c	Thu Sep 13 17:12:59 2012 +0300
+++ b/src/lib/uri-util.c	Fri Sep 14 21:02:23 2012 +0300
@@ -50,16 +50,25 @@
  *               / "*" / "+" / "," / ";" / "="               [bit1]
  * gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"   [bit2]
  * pchar         = unreserved / sub-delims / ":" / "@"       [bit0|bit1|bit3]
+ * 'pfchar'      = unreserved / sub-delims / ":" / "@" / "/" 
+ *                                                      [bit0|bit1|bit3|bit5]
  * 'uchar'       = unreserved / sub-delims / ":"             [bit0|bit1|bit4]
- * 'fchar'       = pchar / "/" / "?"                    [bit0|bit1|bit3|bit5]
+ * 'qchar'       = pchar / "/" / "?"               [bit0|bit1|bit3|bit5|bit6]
  *
  */
 
+#define CHAR_MASK_UNRESERVED (1<<0)
+#define CHAR_MASK_SUB_DELIMS (1<<1)
+#define CHAR_MASK_PCHAR ((1<<0)|(1<<1)|(1<<3))
+#define CHAR_MASK_PFCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5))
+#define CHAR_MASK_UCHAR ((1<<0)|(1<<1)|(1<<4))
+#define CHAR_MASK_QCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<6))
+
 static unsigned const char _uri_char_lookup[256] = {
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 00
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 10
 	 0,  2,  0,  4,  2,  0,  2,  2,  2,  2,  2,  2,  2,  1,  1, 36,  // 20
-	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 28,  2,  0,  2,  0, 36,  // 30
+	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 28,  2,  0,  2,  0, 68,  // 30
 	12,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 40
 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  4,  0,  4,  0,  1,  // 50
 	 0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 60
@@ -133,7 +142,7 @@
 	if ((*parser->cur & 0x80) != 0)
 		return 0;
 
-	if (_uri_char_lookup[*parser->cur] & 0x01) {
+	if ((_uri_char_lookup[*parser->cur] & CHAR_MASK_UNRESERVED) != 0) {
 		*ch_r = *parser->cur;
 		parser->cur++;
 		return 1;
@@ -344,7 +353,7 @@
 
 		/* sub-delims */
 		c = *parser->cur;
-		if ((c & 0x80) == 0 && (_uri_char_lookup[c] & 0x02) != 0) {
+		if ((c & 0x80) == 0 && (_uri_char_lookup[c] & CHAR_MASK_SUB_DELIMS) != 0) {


More information about the dovecot-cvs mailing list