dovecot-2.2: lib-imap: Replaced last traces of imap_quote*() wit...

dovecot at dovecot.org dovecot at dovecot.org
Wed Oct 24 11:30:22 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/b89dae6aead4
changeset: 15250:b89dae6aead4
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Oct 24 11:30:09 2012 +0300
description:
lib-imap: Replaced last traces of imap_quote*() with imap_append_string_for_humans()
Also the imap_append_*string() functions now decide whether to use
quoted-string or literal based on the output string length (if both would
work).

diffstat:

 src/lib-imap/imap-envelope.c |   21 ++-
 src/lib-imap/imap-quote.c    |  260 ++++++++++++++++++++++--------------------
 src/lib-imap/imap-quote.h    |   20 +--
 3 files changed, 158 insertions(+), 143 deletions(-)

diffs (truncated from 368 to 300 lines):

diff -r c849ae6603f2 -r b89dae6aead4 src/lib-imap/imap-envelope.c
--- a/src/lib-imap/imap-envelope.c	Wed Oct 24 11:28:38 2012 +0300
+++ b/src/lib-imap/imap-envelope.c	Wed Oct 24 11:30:09 2012 +0300
@@ -147,18 +147,18 @@
 		*addr_p = message_address_parse(pool, hdr->full_value,
 						hdr->full_value_len,
 						(unsigned int)-1, TRUE);
-	} else if (str_p != NULL) {
+	} else if (str_p != NULL) T_BEGIN {
+		string_t *str = t_str_new(128);
+
 		if (str_p != &d->subject) {
-			string_t *str = t_str_new(128);
-
 			imap_append_string(str,
 				t_strndup(hdr->full_value, hdr->full_value_len));
-			*str_p = p_strdup(pool, str_c(str));
 		} else {
-			*str_p = imap_quote(pool, hdr->full_value,
-					    hdr->full_value_len, TRUE);
+			imap_append_string_for_humans(str,
+				hdr->full_value, hdr->full_value_len);
 		}
-	}
+		*str_p = p_strdup(pool, str_c(str));
+	} T_END;
 }
 
 static void imap_write_address(string_t *str, struct message_address *addr)
@@ -171,7 +171,12 @@
 	str_append_c(str, '(');
 	while (addr != NULL) {
 		str_append_c(str, '(');
-		imap_quote_append_string(str, addr->name, TRUE);
+		if (addr->name == NULL)
+			str_append(str, "NIL");
+		else {
+			imap_append_string_for_humans(str,
+				(const void *)addr->name, strlen(addr->name));
+		}
 		str_append_c(str, ' ');
 		imap_append_nstring(str, addr->route);
 		str_append_c(str, ' ');
diff -r c849ae6603f2 -r b89dae6aead4 src/lib-imap/imap-quote.c
--- a/src/lib-imap/imap-quote.c	Wed Oct 24 11:28:38 2012 +0300
+++ b/src/lib-imap/imap-quote.c	Wed Oct 24 11:30:09 2012 +0300
@@ -5,124 +5,15 @@
 #include "imap-arg.h"
 #include "imap-quote.h"
 
-void imap_quote_append(string_t *str, const unsigned char *value,
-		       size_t value_len, bool fix_text)
-{
-	size_t i, extra = 0;
-	bool last_lwsp = TRUE, literal = FALSE, modify = FALSE;
-
-	if (value == NULL) {
-		str_append(str, "NIL");
-		return;
-	}
-
-	if (value_len == (size_t)-1)
-		value_len = strlen((const char *) value);
-
-	for (i = 0; i < value_len; i++) {
-		switch (value[i]) {
-		case 0:
-			/* it's converted to 8bit char */
-			literal = TRUE;
-			last_lwsp = FALSE;
-			modify = TRUE;
-			break;
-		case '\t':
-			modify = TRUE;
-			/* fall through */
-		case ' ':
-			if (last_lwsp && fix_text) {
-				modify = TRUE;
-				extra++;
-			}
-			last_lwsp = TRUE;
-			break;
-		case 13:
-		case 10:
-			if (!fix_text)
-				literal = TRUE;
-			extra++;
-			modify = TRUE;
-			break;
-		default:
-			if ((value[i] & 0x80) != 0 ||
-			    value[i] == '"' || value[i] == '\\')
-				literal = TRUE;
-			last_lwsp = FALSE;
-		}
-	}
-
-	if (!fix_text) {
-		extra = 0;
-		modify = FALSE;
-	}
-
-	if (!literal) {
-		/* no 8bit chars or imapspecials, return as "string" */
-		str_append_c(str, '"');
-	} else {
-		/* return as literal */
-		str_printfa(str, "{%"PRIuSIZE_T"}\r\n", value_len - extra);
-	}
-
-	if (!modify)
-		str_append_n(str, value, value_len);
-	else {
-		last_lwsp = TRUE;
-		for (i = 0; i < value_len; i++) {
-			switch (value[i]) {
-			case 0:
-				str_append_c(str, 128);
-				last_lwsp = FALSE;
-				break;
-			case ' ':
-			case '\t':
-				if (!last_lwsp)
-					str_append_c(str, ' ');
-				last_lwsp = TRUE;
-				break;
-			case 13:
-			case 10:
-				break;
-			default:
-				last_lwsp = FALSE;
-				str_append_c(str, value[i]);
-				break;
-			}
-		}
-	}
-
-	if (!literal)
-		str_append_c(str, '"');
-}
-
-static const char *
-imap_quote_internal(pool_t pool, const unsigned char *value,
-		    size_t value_len, bool fix_text)
-{
-	string_t *str;
-
-	str = t_str_new(value_len + MAX_INT_STRLEN + 5);
-	imap_quote_append(str, value, value_len, fix_text);
-	return pool->datastack_pool ? str_c(str) :
-		p_strndup(pool, str_data(str), str_len(str));
-}
-
-const char *imap_quote(pool_t pool, const unsigned char *value,
-		       size_t value_len, bool fix_text)
-{
-	const char *ret;
-
-	if (value == NULL)
-		return "NIL";
-
-	if (pool->datastack_pool)
-		ret = imap_quote_internal(pool, value, value_len, fix_text);
-	else T_BEGIN {
-		ret = imap_quote_internal(pool, value, value_len, fix_text);
-	} T_END;
-	return ret;
-}
+/* If we have quoted-specials (<">, <\>) in a string, the minimum quoted-string
+   overhead is 3 bytes ("\") while the minimum literal overhead is 5 bytes
+   ("{n}\r\n"). But the literal overhead also depends on the string size. If
+   the string length is less than 10, literal catches up to quoted-string after
+   3 quoted-specials. If the string length is 10..99, it catches up after 4
+   quoted-specials, and so on. We'll assume that the string lengths are usually
+   in double digits, so we'll switch to literals after seeing 4
+   quoted-specials. */
+#define QUOTED_MAX_ESCAPE_CHARS 4
 
 void imap_append_string(string_t *dest, const char *src)
 {
@@ -149,9 +40,52 @@
 		str_append(dest, src);
 }
 
+static void
+imap_append_literal(string_t *dest, const char *src, unsigned int pos)
+{
+	unsigned int full_len = pos + strlen(src+pos);
+
+	str_printfa(dest, "{%u}\r\n", full_len);
+	buffer_append(dest, src, full_len);
+}
+
 void imap_append_nstring(string_t *dest, const char *src)
 {
-	imap_quote_append_string(dest, src, FALSE);
+	unsigned int i, escape_count = 0;
+
+	if (src == NULL) {
+		str_append(dest, "NIL");
+		return;
+	}
+
+	/* first check if we can (or want to) write this as quoted or
+	   as literal.
+
+	   quoted-specials = DQUOTE / "\"
+	   QUOTED-CHAR     = <any TEXT-CHAR except quoted-specials> /
+	                     "\" quoted-specials
+	   TEXT-CHAR       = <any CHAR except CR and LF>
+	*/
+	for (i = 0; src[i] != '\0'; i++) {
+		switch (src[i]) {
+		case '"':
+		case '\\':
+			if (escape_count++ < QUOTED_MAX_ESCAPE_CHARS)
+				break;
+			/* fall through */
+		case 13:
+		case 10:
+			imap_append_literal(dest, src, i);
+			return;
+		default:
+			if ((unsigned char)src[i] >= 0x80) {
+				imap_append_literal(dest, src, i);
+				return;
+			}
+			break;
+		}
+	}
+	imap_append_quoted(dest, src);
 }
 
 void imap_append_quoted(string_t *dest, const char *src)
@@ -159,8 +93,8 @@
 	str_append_c(dest, '"');
 	for (; *src != '\0'; src++) {
 		switch (*src) {
-		case '\r':
-		case '\n':
+		case 13:
+		case 10:
 			/* not allowed */
 			break;
 		case '"':
@@ -180,3 +114,87 @@
 	}
 	str_append_c(dest, '"');
 }
+
+void imap_append_string_for_humans(string_t *dest,
+				   const unsigned char *src, size_t size)
+{
+	size_t i, pos, remove_count = 0;
+	bool last_lwsp = TRUE, modify = FALSE;
+
+	/* first check if there is anything to change */
+	for (i = 0; i < size; i++) {
+		switch (src[i]) {
+		case 0:
+			/* convert NUL to #0x80 */
+			last_lwsp = FALSE;
+			modify = TRUE;
+			break;
+		case '\t':
+			modify = TRUE;
+			/* fall through */
+		case ' ':
+			if (last_lwsp) {
+				modify = TRUE;
+				remove_count++;
+			}
+			last_lwsp = TRUE;
+			break;
+		case 13:
+		case 10:
+			remove_count++;
+			modify = TRUE;
+			break;
+		case '"':
+		case '\\':
+			modify = TRUE;
+			last_lwsp = FALSE;
+			break;
+		default:
+			if ((src[i] & 0x80) != 0)
+				modify = TRUE;
+			last_lwsp = FALSE;
+			break;
+		}
+	}
+	if (last_lwsp) {
+		modify = TRUE;
+		remove_count++;
+	}
+	if (!modify) {
+		/* fast path: we can simply write it as quoted string
+		   without any escaping */
+		str_append_c(dest, '"');
+		str_append_n(dest, src, size);


More information about the dovecot-cvs mailing list