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