dovecot-2.2: lib-imap: Added IMAP URL parser.

dovecot at dovecot.org dovecot at dovecot.org
Sat Jun 2 19:02:27 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/9eef4f7b0187
changeset: 14590:9eef4f7b0187
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Sat Jun 02 17:53:31 2012 +0300
description:
lib-imap: Added IMAP URL parser.

Includes support for IMAP URLAUTH URLs.

Includes extensive testsuite.

Creation of IMAP URL string from struct data is not implemented and
deferred to a future patch when this functionality is needed.

diffstat:

 src/lib-imap/Makefile.am     |    7 +
 src/lib-imap/imap-url.c      |  936 +++++++++++++++++++++++++++++++++++++++++++
 src/lib-imap/imap-url.h      |   70 +++
 src/lib-imap/test-imap-url.c |  900 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1913 insertions(+), 0 deletions(-)

diffs (truncated from 1956 to 300 lines):

diff -r c54dd35e1c0e -r 9eef4f7b0187 src/lib-imap/Makefile.am
--- a/src/lib-imap/Makefile.am	Sat Jun 02 17:15:18 2012 +0300
+++ b/src/lib-imap/Makefile.am	Sat Jun 02 17:53:31 2012 +0300
@@ -16,6 +16,7 @@
 	imap-match.c \
 	imap-parser.c \
 	imap-quote.c \
+	imap-url.c \
 	imap-seqset.c \
 	imap-utf7.c \
 	imap-util.c
@@ -31,6 +32,7 @@
 	imap-parser.h \
 	imap-resp-code.h \
 	imap-quote.h \
+	imap-url.h \
 	imap-seqset.h \
 	imap-utf7.h \
 	imap-util.h
@@ -41,6 +43,7 @@
 test_programs = \
 	test-imap-match \
 	test-imap-parser \
+	test-imap-url \
 	test-imap-utf7 \
 	test-imap-util
 
@@ -58,6 +61,10 @@
 test_imap_parser_LDADD = imap-parser.lo imap-arg.lo $(test_libs)
 test_imap_parser_DEPENDENCIES = imap-parser.lo imap-arg.lo $(test_libs)
 
+test_imap_url_SOURCES = test-imap-url.c
+test_imap_url_LDADD = imap-url.lo  $(test_libs)
+test_imap_url_DEPENDENCIES = imap-url.lo $(test_libs)
+
 test_imap_utf7_SOURCES = test-imap-utf7.c
 test_imap_utf7_LDADD = imap-utf7.lo $(test_libs)
 test_imap_utf7_DEPENDENCIES = imap-utf7.lo $(test_libs)
diff -r c54dd35e1c0e -r 9eef4f7b0187 src/lib-imap/imap-url.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-imap/imap-url.c	Sat Jun 02 17:53:31 2012 +0300
@@ -0,0 +1,936 @@
+/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "str-sanitize.h"
+#include "hex-binary.h"
+#include "network.h"
+#include "iso8601-date.h"
+#include "uri-util.h"
+
+#include "imap-url.h"
+
+#include <ctype.h>
+
+/*
+ * IMAP URL parsing
+ */
+
+/*
+IMAP URL Grammar overview
+
+RFC5092 Section 11:
+
+imapurl          = "imap://" iserver ipath-query
+                   ; Defines an absolute IMAP URL
+iserver          = [iuserinfo "@"] host [ ":" port ]
+                   ; This is the same as "authority" defined in [URI-GEN].
+iuserinfo        = enc-user [iauth] / [enc-user] iauth
+                   ; conforms to the generic syntax of "userinfo" as
+                   ; defined in [URI-GEN].
+enc-user         = 1*achar
+                   ; %-encoded version of [IMAP4] authorization identity or
+                   ; "userid".
+iauth            = ";AUTH=" ( "*" / enc-auth-type )
+enc-auth-type    = 1*achar
+                   ; %-encoded version of [IMAP4] "auth-type"
+ipath-query      = ["/" [ icommand ]]
+                   ; Corresponds to "path-abempty [ "?" query ]" in
+                   ; [URI-GEN]
+icommand         = imessagelist /
+                   imessagepart [iurlauth]
+imessagelist     = imailbox-ref [ "?" enc-search ]
+                   ; "enc-search" is [URI-GEN] "query".
+imessagepart     = imailbox-ref iuid [isection] [ipartial]
+imailbox-ref     = enc-mailbox [uidvalidity]
+uidvalidity      = ";UIDVALIDITY=" nz-number
+                   ; See [IMAP4] for "nz-number" definition
+iuid             = "/" iuid-only
+iuid-only        = ";UID=" nz-number
+                   ; See [IMAP4] for "nz-number" definition
+isection         = "/" isection-only
+isection-only    = ";SECTION=" enc-section
+ipartial         = "/" ipartial-only
+ipartial-only    = ";PARTIAL=" partial-range
+enc-search       = 1*bchar
+                   ; %-encoded version of [IMAPABNF]
+                   ; "search-program".  Note that IMAP4
+                   ; literals may not be used in
+                   ; a "search-program", i.e., only
+                   ; quoted or non-synchronizing
+                   ; literals (if the server supports
+                   ; LITERAL+ [LITERAL+]) are allowed.
+enc-mailbox      = 1*bchar
+                   ; %-encoded version of [IMAP4] "mailbox"
+enc-section      = 1*bchar
+                   ; %-encoded version of [IMAP4] "section-spec"
+partial-range    = number ["." nz-number]
+                   ; partial FETCH.  The first number is
+                   ; the offset of the first byte,
+                   ; the second number is the length of
+                   ; the fragment.
+bchar            = achar / ":" / "@" / "/"
+achar            = uchar / "&" / "="
+                   ;; Same as [URI-GEN] 'unreserved / sub-delims /
+                   ;; pct-encoded', but ";" is disallowed.
+uchar            = unreserved / sub-delims-sh / pct-encoded
+sub-delims-sh    = "!" / "$" / "'" / "(" / ")" /
+                   "*" / "+" / ","
+                   ;; Same as [URI-GEN] sub-delims,
+                   ;; but without ";", "&" and "=".
+
+The following rules are only used in the presence of the IMAP
+[URLAUTH] extension:
+
+authimapurl      = "imap://" iserver "/" imessagepart
+                   ; Same as "imapurl" when "[icommand]" is
+                   ; "imessagepart"
+authimapurlfull  = authimapurl iurlauth
+                   ; Same as "imapurl" when "[icommand]" is
+                   ; "imessagepart iurlauth"
+authimapurlrump  = authimapurl iurlauth-rump
+
+iurlauth         = iurlauth-rump iua-verifier
+enc-urlauth      = 32*HEXDIG
+iua-verifier     = ":" uauth-mechanism ":" enc-urlauth
+iurlauth-rump    = [expire] ";URLAUTH=" access
+access           = ("submit+" enc-user) / ("user+" enc-user) /
+                   "authuser" / "anonymous"
+expire           = ";EXPIRE=" date-time
+                   ; date-time is defined in [DATETIME]
+uauth-mechanism  = "INTERNAL" / 1*(ALPHA / DIGIT / "-" / ".")
+                   ; Case-insensitive.
+
+[URI-GEN] RFC3986 Appendix A:
+
+Implemented in src/lib/uri-util.c
+
+*/
+
+/*
+ * Imap URL parser
+ */
+
+struct imap_url_parser {
+	struct uri_parser parser;
+
+	enum imap_url_parse_flags flags;
+
+	struct imap_url *url;
+	struct imap_url *base;
+
+	unsigned int relative:1;
+};
+
+static int
+imap_url_parse_number(struct uri_parser *parser, const char *data,
+		      uint32_t *number_r)
+{
+	uint32_t number = 0;
+	const char *p = data;
+
+	/* [IMAP4] RFC3501, Section 9
+	 *
+	 * number          = 1*DIGIT
+	 *                   ; Unsigned 32-bit integer
+	 *                   ; (0 <= n < 4,294,967,296)
+	 */
+
+	if (i_isdigit(*p)) {
+		do {
+			uint32_t prev = number;
+
+			number = number * 10 + (*p - '0');
+			if (number < prev) {
+				parser->error = "IMAP number is too high";
+				return -1;
+			}
+			p++;
+		} while (i_isdigit(*p));
+
+		if (*p == '\0') {
+			if (number_r != NULL)
+				*number_r = number;
+			return 1;
+		}
+	}
+
+	parser->error = t_strdup_printf(
+		"Value '%s' is not a valid IMAP number", data);
+	return -1;
+}
+
+static int
+imap_url_parse_offset(struct uri_parser *parser, const char *data,
+		      uoff_t *number_r)
+{
+	uoff_t number = 0;
+	const char *p = data;
+
+	/* Syntax for big (uoff_t) numbers. Not strictly IMAP syntax, but this
+	   is handled similarly for Dovecot IMAP FETCH BODY partial <.>
+	   implementation. */
+	if (i_isdigit(*p)) {
+		do {
+			uoff_t prev = number;
+
+			number = number * 10 + (*p - '0');
+			if (number < prev) {
+				parser->error = "IMAP number is too high";
+				return -1;
+			}
+			p++;
+		} while (i_isdigit(*p));
+
+		if (*p == '\0') {
+			if (number_r != NULL)
+				*number_r = number;
+			return 1;
+		}
+	}
+
+	parser->error = t_strdup_printf(
+		"Value '%s' is not a valid IMAP number", data);
+	return -1;
+}
+
+static int imap_url_parse_iserver(struct imap_url_parser *url_parser)
+{
+	struct uri_parser *parser = &url_parser->parser;
+	struct uri_authority auth;
+	struct imap_url *url = url_parser->url;
+	const char *data;
+	int ret = 0;
+
+	/* imapurl          = "imap://" iserver {...}
+	 * inetwork-path    = "//" iserver {...}
+	 * iserver          = [iuserinfo "@"] host [":" port]
+	 *                    ; This is the same as "authority" defined
+	 *                    ; in [URI-GEN].
+	 * iuserinfo        = enc-user [iauth] / [enc-user] iauth
+	 *                    ; conforms to the generic syntax of "userinfo" as
+	 *                    ; defined in [URI-GEN].
+	 * enc-user         = 1*achar
+	 *                    ; %-encoded version of [IMAP4] authorization identity or
+	 *                    ; "userid".
+	 * iauth            = ";AUTH=" ( "*" / enc-auth-type )
+	 * enc-auth-type    = 1*achar
+	 *                    ; %-encoded version of [IMAP4] "auth-type"
+	 */
+
+	/* "//" iserver */
+	if ((ret = uri_parse_authority(parser, &auth)) <= 0)
+		return ret;
+
+	/* iuserinfo        = enc-user [iauth] / [enc-user] iauth */
+	if (auth.enc_userinfo != NULL) {
+		const char *p;
+
+		/* Scan for ";AUTH=" */
+		p = strchr(auth.enc_userinfo, ';');
+		if (p != NULL) {
+			if (strncasecmp(p, ";AUTH=",6) != 0) {
+				parser->error = t_strdup_printf(
+					"Stray ';' in userinfo `%s'",
+					auth.enc_userinfo);
+				return -1;
+			}
+
+			if (strchr(p+1, ';') != NULL) {
+				parser->error = "Stray ';' after `;AUTH='";
+				return -1;
+			}
+		}
+
+		/* enc-user */
+		if (url != NULL && p != auth.enc_userinfo) {
+			if (!uri_data_decode(parser, auth.enc_userinfo, p, &data))
+				return -1;
+			url->userid = p_strdup(parser->pool, data);
+		}
+
+		/* ( "*" / enc-auth-type ) */
+		if (p != NULL) {
+			p += 6;
+			if (*p == '\0') {
+				parser->error = "Empty auth-type value after ';AUTH='";


More information about the dovecot-cvs mailing list