changeset 283:84762660fcac

Use $mailbox_url for in mailbox URLs.
author Timo Sirainen <tss@iki.fi>
date Fri, 31 Aug 2012 00:34:25 +0300
parents 2c02b48c506a
children 78116a036c3f
files src/Makefile.am src/client.c src/imapurl.c src/imapurl.h src/test-exec.c src/tests/catenate src/tests/catenate-multiappend
diffstat 7 files changed, 222 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Wed Aug 29 23:14:39 2012 +0300
+++ b/src/Makefile.am	Fri Aug 31 00:34:25 2012 +0300
@@ -7,6 +7,7 @@
 	client.c \
 	client-state.c \
 	commands.c \
+	imapurl.c \
 	imaptest.c \
 	mailbox.c \
 	mailbox-source.c \
@@ -20,6 +21,7 @@
 	client.h \
 	client-state.h \
 	commands.h \
+	imapurl.h \
 	mailbox.h \
 	mailbox-source.h \
 	mailbox-state.h \
--- a/src/client.c	Wed Aug 29 23:14:39 2012 +0300
+++ b/src/client.c	Fri Aug 31 00:34:25 2012 +0300
@@ -504,7 +504,7 @@
 		}
 
 		if (client->literal_left == 0) {
-			/* skip CRLF */
+			/* end of command - skip CRLF */
 			imap_parser_reset(client->parser);
 
 			data = i_stream_get_data(client->input, &size);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imapurl.c	Fri Aug 31 00:34:25 2012 +0300
@@ -0,0 +1,173 @@
+/* Copyright (C) The IETF Trust (2007).  This version of
+   sample C code is part of RFC XXXX; see the RFC itself
+   for full legal notices.
+
+   Regarding this sample C code (or any portion of it), the authors
+   make no guarantees and are not responsible for any damage
+   resulting from its use.  The authors grant irrevocable permission
+   to anyone to use, modify, and distribute it in any way that does
+   not diminish the rights of anyone else to use, modify, and
+   distribute it, provided that redistributed derivative works do
+   not contain misleading author or version information.
+
+   Derivative works need not be licensed under similar terms.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "imapurl.h"
+
+/* hexadecimal lookup table */
+static const char hex[] = "0123456789ABCDEF";
+
+#define XX 127
+/*
+ * Table for decoding hexadecimal in %encoding
+ */
+static const char index_hex[256] = {
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,XX,XX, XX,XX,XX,XX,
+    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+};
+#define HEXCHAR(c)  (index_hex[(unsigned char)(c)])
+
+/* "gen-delims" excluding "/" but including "%" */
+#define GENERAL_DELIMS_NO_SLASH     ":?#[]@" "%"
+
+/* "gen-delims" (excluding "/", but including "%")
+   plus subset of "sub-delims" */
+#define GENERAL_UNSAFE_NO_SLASH     GENERAL_DELIMS_NO_SLASH ";&=+"
+#define OTHER_UNSAFE                " \"<>\\^`{|}"
+
+/* URL unsafe printable characters */
+static const char mailbox_url_unsafe[] = GENERAL_UNSAFE_NO_SLASH
+                                         OTHER_UNSAFE;
+
+/* UTF7 modified base64 alphabet */
+static const char base64chars[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
+
+#define UNDEFINED 64
+
+/* UTF16 definitions */
+#define UTF16MASK   0x03FFUL
+#define UTF16SHIFT  10
+#define UTF16BASE   0x10000UL
+#define UTF16HIGHSTART   0xD800UL
+#define UTF16HIGHEND     0xDBFFUL
+#define UTF16LOSTART     0xDC00UL
+#define UTF16LOEND  0xDFFFUL
+
+/* Convert an IMAP mailbox to a URL path
+ *  dst needs to have roughly 4 times the storage space of src
+ *    Hex encoding can triple the size of the input
+ *    UTF-7 can be slightly denser than UTF-8
+ *     (worst case: 8 octets UTF-7 becomes 9 octets UTF-8)
+ */
+void imap_mailbox_to_url(char *dst, const char *src)
+{
+    unsigned char c, i, bitcount;
+    unsigned long ucs4, utf16, bitbuf;
+    unsigned char base64[256], utf8[6];
+
+    /* initialize modified base64 decoding table */
+    memset(base64, UNDEFINED, sizeof (base64));
+    for (i = 0; i < sizeof (base64chars); ++i) {
+     base64[(int) base64chars[i]] = i;
+    }
+
+    /* loop until end of string */
+    while (*src != '\0') {
+     c = *src++;
+     /* deal with literal characters and &- */
+     if (c != '&' || *src == '-') {
+         /* NB: There are no "URL safe" characters after the '~' */
+         if (c < ' ' || c > '~' ||
+             strchr(mailbox_url_unsafe, c) != NULL) {
+          /* hex encode if necessary */
+          dst[0] = '%';
+          dst[1] = hex[c >> 4];
+          dst[2] = hex[c & 0x0f];
+          dst += 3;
+         } else {
+          /* encode literally */
+          *dst++ = c;
+         }
+         /* skip over the '-' if this is an &- sequence */
+         if (c == '&') ++src;
+
+     } else {
+        /* convert modified UTF-7 -> UTF-16 -> UCS-4 -> UTF-8 -> HEX */
+         bitbuf = 0;
+         bitcount = 0;
+         ucs4 = 0;
+         while ((c = base64[(unsigned char) *src]) != UNDEFINED) {
+          ++src;
+          bitbuf = (bitbuf << 6) | c;
+          bitcount += 6;
+          /* enough bits for a UTF-16 character? */
+          if (bitcount >= 16) {
+              bitcount -= 16;
+              utf16 = (bitcount ? bitbuf >> bitcount
+                             : bitbuf) & 0xffff;
+              /* convert UTF16 to UCS4 */
+              if
+                    (utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND) {
+               ucs4 = (utf16 - UTF16HIGHSTART) << UTF16SHIFT;
+               continue;
+              } else if
+                    (utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND) {
+               ucs4 += utf16 - UTF16LOSTART + UTF16BASE;
+              } else {
+               ucs4 = utf16;
+              }
+              /* convert UTF-16 range of UCS4 to UTF-8 */
+              if (ucs4 <= 0x7fUL) {
+               utf8[0] = (unsigned char) ucs4;
+               i = 1;
+              } else if (ucs4 <= 0x7ffUL) {
+               utf8[0] = 0xc0 | (unsigned char) (ucs4 >> 6);
+               utf8[1] = 0x80 | (unsigned char) (ucs4 & 0x3f);
+               i = 2;
+              } else if (ucs4 <= 0xffffUL) {
+               utf8[0] = 0xe0 | (unsigned char) (ucs4 >> 12);
+               utf8[1] = 0x80 | (unsigned char) ((ucs4 >> 6) & 0x3f);
+               utf8[2] = 0x80 | (unsigned char) (ucs4 & 0x3f);
+               i = 3;
+              } else {
+               utf8[0] = 0xf0 | (unsigned char) (ucs4 >> 18);
+               utf8[1] = 0x80 | (unsigned char) ((ucs4 >> 12) & 0x3f);
+               utf8[2] = 0x80 | (unsigned char) ((ucs4 >> 6) & 0x3f);
+               utf8[3] = 0x80 | (unsigned char) (ucs4 & 0x3f);
+               i = 4;
+              }
+              /* convert utf8 to hex */
+              for (c = 0; c < i; ++c) {
+               dst[0] = '%';
+               dst[1] = hex[utf8[c] >> 4];
+               dst[2] = hex[utf8[c] & 0x0f];
+               dst += 3;
+              }
+          }
+         }
+         /* skip over trailing '-' in modified UTF-7 encoding */
+         if (*src == '-') ++src;
+     }
+    }
+    /* terminate destination string */
+    *dst = '\0';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imapurl.h	Fri Aug 31 00:34:25 2012 +0300
@@ -0,0 +1,6 @@
+#ifndef IMAPURL_H
+#define IMAPURL_H
+
+void imap_mailbox_to_url(char *dst, const char *src);
+
+#endif
--- a/src/test-exec.c	Wed Aug 29 23:14:39 2012 +0300
+++ b/src/test-exec.c	Fri Aug 31 00:34:25 2012 +0300
@@ -11,6 +11,7 @@
 #include "mailbox-source.h"
 #include "client.h"
 #include "commands.h"
+#include "imapurl.h"
 #include "test-parser.h"
 #include "test-exec.h"
 
@@ -1037,6 +1038,7 @@
 	struct test_exec_context *ctx;
 	unsigned int i;
 	const char *key, *value;
+	char *url;
 	pool_t pool;
 
 	pool = pool_alloconly_create("test exec context", 2048);
@@ -1074,6 +1076,13 @@
 	key = "mailbox";
 	value = p_strdup(pool, ctx->clients[0]->storage->name);
 	hash_table_insert(ctx->variables, key, value);
+
+	key = "mailbox_url";
+	url = p_malloc(pool, strlen(value)*4+1);
+	imap_mailbox_to_url(url, value);
+	value = url;
+
+	hash_table_insert(ctx->variables, key, value);
 	return 0;
 }
 
--- a/src/tests/catenate	Wed Aug 29 23:14:39 2012 +0300
+++ b/src/tests/catenate	Fri Aug 31 00:34:25 2012 +0300
@@ -36,19 +36,19 @@
 
 ok create ${mailbox}2
 
-ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox/;uid=$uid/;section=header" text {{{
+ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid/;section=header" text {{{
 body1
 }}})
 
-ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox;uidvalidity=$uidv/;uid=$uid/;section=header" text {{{
+ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=$uidv/;uid=$uid/;section=header" text {{{
 body2
 }}})
 
-ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox/;uid=$uid2/;section=text" text {{{
+ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid2/;section=text" text {{{
 body3
 }}})
 
-ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox/;uid=$uid2/;section=1" text {{{
+ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid2/;section=1" text {{{
 body4
 }}})
 
@@ -57,7 +57,7 @@
 Subject: test header
 
 
-}}} url "/$mailbox/;uid=$uid/;section=1" text {{{
+}}} url "/$mailbox_url/;uid=$uid/;section=1" text {{{
 
 suffix
 }}})
@@ -73,7 +73,7 @@
 body6
 }}})
 
-ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox/;uid=$uid2/;partial=100000.1" text {{{
+ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid2/;partial=100000.1" text {{{
 Hdr: foo
 
 body7
@@ -83,7 +83,7 @@
 # Try invalid URLs
 #
 
-no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header" text {{{
+no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
 body
 
 }}})
@@ -91,12 +91,12 @@
 no append ${mailbox}2 (\seen \flagged) catenate (text {{{
 hdr: 1
 
-}}} url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header")
+}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header")
 
 no append ${mailbox}2 (\seen \flagged) catenate (text {{{
 hdr: 1
 
-}}} url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
 hdr: 2
 
 }}})
@@ -104,10 +104,10 @@
 no append ${mailbox}2 (\seen \flagged) catenate (text {{{
 hdr: 1
 
-}}} url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
 hdr: 2
 
-}}} url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
 hdr: 3
 
 }}})
@@ -115,10 +115,10 @@
 no append ${mailbox}2 (\seen \flagged) catenate (text {{{
 hdr: 1
 
-}}} url "/$mailbox/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url/;uid=$uid/;section=header" text {{{
 hdr: 2
 
-}}} url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
 hdr: 3
 
 }}})
@@ -126,16 +126,16 @@
 no append ${mailbox}2 (\seen \flagged) catenate (text {{{
 hdr: 1
 
-}}} url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
 hdr: 2
 
-}}} url "/$mailbox/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url/;uid=$uid/;section=header" text {{{
 hdr: 3
 
 }}})
 
-no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header" url "/$mailbox/;uid=$uid/;section=header")
-no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox/;uid=$uid/;section=header" url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header")
+no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" url "/$mailbox_url/;uid=$uid/;section=header")
+no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid/;section=header" url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header")
 
 #
 # verify previous appends
@@ -186,26 +186,26 @@
 # Try appending to nonexistent mailbox
 #
 
-append ${mailbox}nonexistent catenate (url "/$mailbox/;uid=$uid/;section=1")
+append ${mailbox}nonexistent catenate (url "/$mailbox_url/;uid=$uid/;section=1")
 no [trycreate]
 
-append ${mailbox}nonexistent catenate (url "/$mailbox/;uid=$uid/;section=1" text {{{
+append ${mailbox}nonexistent catenate (url "/$mailbox_url/;uid=$uid/;section=1" text {{{
 hello
 }}})
 no [trycreate]
 
 append ${mailbox}nonexistent catenate (text {{{
 hello
-}}} url "/$mailbox/;uid=$uid/;section=1")
+}}} url "/$mailbox_url/;uid=$uid/;section=1")
 no [trycreate]
 
 append ${mailbox}nonexistent (\seen \flagged) catenate (text {{{
 hdr1: 1
 
-}}} url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
 hdr2: 2
 
-}}} url "/$mailbox/;uid=$uid/;section=header" text {{{
+}}} url "/$mailbox_url/;uid=$uid/;section=header" text {{{
 hdr3: 3
 
 }}})
--- a/src/tests/catenate-multiappend	Wed Aug 29 23:14:39 2012 +0300
+++ b/src/tests/catenate-multiappend	Fri Aug 31 00:34:25 2012 +0300
@@ -26,23 +26,23 @@
 Second body
 }}})
 
-ok append ${mailbox} catenate (url "/$mailbox/;uid=$uid/;section=header" text {{{
+ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid/;section=header" text {{{
 body1
-}}}) catenate (url "/$mailbox/;uid=$uid2/;section=header" text {{{
+}}}) catenate (url "/$mailbox_url/;uid=$uid2/;section=header" text {{{
 body2
 }}})
 
-ok append ${mailbox} catenate (url "/$mailbox/;uid=$uid") catenate (url "/$mailbox/;uid=$uid2/;section=header" text {{{
+ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid") catenate (url "/$mailbox_url/;uid=$uid2/;section=header" text {{{
 body3
 }}})
 
-ok append ${mailbox} catenate (url "/$mailbox/;uid=$uid/;section=header") {{{
+ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid/;section=header") {{{
 New: Message
 
 body4
 }}}
 
-ok append ${mailbox} catenate (url "/$mailbox/;uid=$uid/;section=header") (\answered) {{{
+ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid/;section=header") (\answered) {{{
 New: Message
 
 body5
@@ -96,17 +96,17 @@
 # Try invalid URLs
 #
 
-no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header") catenate (url "/$mailbox/;uid=$uid")
+no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (url "/$mailbox_url/;uid=$uid")
 
-no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header") catenate (url "/$mailbox/;uid=$uid" text {{{
+no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (url "/$mailbox_url/;uid=$uid" text {{{
 hello
 }}})
 
-no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header") catenate (text {{{
+no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (text {{{
 hello
 }}})
 
-no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox;uidvalidity=12345/;uid=$uid/;section=header") {{{
+no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") {{{
 hello
 }}}