[dovecot-cvs] dovecot/src/lib-imap imap-bodystructure.c,1.29,1.30 imap-envelope.c,1.22,1.23 imap-parser.c,1.37,1.38 imap-parser.h,1.12,1.13 imap-quote.c,1.5,1.6 imap-quote.h,1.3,1.4

cras at procontrol.fi cras at procontrol.fi
Sat Feb 8 12:44:04 EET 2003


Update of /home/cvs/dovecot/src/lib-imap
In directory danu:/tmp/cvs-serv686/lib-imap

Modified Files:
	imap-bodystructure.c imap-envelope.c imap-parser.c 
	imap-parser.h imap-quote.c imap-quote.h 
Log Message:
Don't do x-unknown mime encoding. Correct way is to just send them as
literals to client. ENVELOPE, BODY and BODYSTRUCTURE replies are now always
sent as literals if they contain 8bit text, '"' or '\' characters.

Added option to IMAP parser to return literals with IMAP_ARG_LITERAL type.



Index: imap-bodystructure.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-imap/imap-bodystructure.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- imap-bodystructure.c	6 Jan 2003 17:51:37 -0000	1.29
+++ imap-bodystructure.c	8 Feb 2003 10:44:01 -0000	1.30
@@ -44,16 +44,14 @@
 			break;
 	}
 
-	if (i == value_len) {
-		data->content_type =
-                        imap_quote_value(data->pool, value, value_len);
-	} else {
-		data->content_type =
-                        imap_quote_value(data->pool, value, i);
+	if (i == value_len)
+		data->content_type = imap_quote(data->pool, value, value_len);
+	else {
+		data->content_type = imap_quote(data->pool, value, i);
 
 		i++;
 		data->content_subtype =
-                        imap_quote_value(data->pool, value+i, value_len-i);
+			imap_quote(data->pool, value+i, value_len-i);
 	}
 }
 
@@ -67,13 +65,9 @@
 	if (str_len(data->str) != 0)
 		str_append_c(data->str, ' ');
 
-	str_append_c(data->str, '"');
-	str_append_n(data->str, name, name_len);
-	str_append(data->str, "\" ");
-
-	str_append_c(data->str, '"');
-	str_append_n(data->str, value, value_len);
-	str_append_c(data->str, '"');
+	imap_quote_append(data->str, name, name_len);
+	str_append_c(data->str, ' ');
+	imap_quote_append(data->str, value, value_len);
 }
 
 static void parse_content_transfer_encoding(const unsigned char *value,
@@ -82,7 +76,7 @@
         struct message_part_body_data *data = context;
 
 	data->content_transfer_encoding =
-		imap_quote_value(data->pool, value, value_len);
+		imap_quote(data->pool, value, value_len);
 }
 
 static void parse_content_disposition(const unsigned char *value,
@@ -90,8 +84,7 @@
 {
         struct message_part_body_data *data = context;
 
-	data->content_disposition =
-		imap_quote_value(data->pool, value, value_len);
+	data->content_disposition = imap_quote(data->pool, value, value_len);
 }
 
 static void parse_content_language(const unsigned char *value, size_t value_len,
@@ -178,7 +171,7 @@
 		if (memcasecmp(name, "Content-ID", 10) == 0 &&
 		    part_data->content_id == NULL) {
 			part_data->content_id =
-				imap_quote_value(pool, value, value_len);
+				imap_quote(pool, value, value_len);
 		}
 		break;
 
@@ -186,7 +179,7 @@
 		if (memcasecmp(name, "Content-MD5", 11) == 0 &&
 		    part_data->content_md5 == NULL) {
 			part_data->content_md5 =
-				imap_quote_value(pool, value, value_len);
+				imap_quote(pool, value, value_len);
 		}
 		break;
 
@@ -212,7 +205,7 @@
 		if (memcasecmp(name, "Content-Description", 19) == 0 &&
 		    part_data->content_description == NULL) {
 			part_data->content_description =
-				imap_quote_value(pool, value, value_len);
+				imap_quote(pool, value, value_len);
 		}
 		if (memcasecmp(name, "Content-Disposition", 19) == 0 &&
 		    part_data->content_disposition_params == NULL) {
@@ -468,29 +461,45 @@
 	return str_c(str);
 }
 
+static int str_append_imap_arg(string_t *str, const struct imap_arg *arg)
+{
+	switch (arg->type) {
+	case IMAP_ARG_NIL:
+		str_append(str, "NIL");
+		break;
+	case IMAP_ARG_ATOM:
+		str_append(str, IMAP_ARG_STR(arg));
+		break;
+	case IMAP_ARG_STRING:
+		str_append_c(str, '"');
+		str_append(str, IMAP_ARG_STR(arg));
+		str_append_c(str, '"');
+		break;
+	case IMAP_ARG_LITERAL: {
+		const char *argstr = IMAP_ARG_STR(arg);
+
+		str_printfa(str, "{%"PRIuSIZE_T"}", strlen(argstr));
+		str_append(str, argstr);
+		break;
+	}
+	default:
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 static int imap_write_list(const struct imap_arg *args, string_t *str)
 {
 	/* don't do any typechecking, just write it out */
 	str_append_c(str, '(');
 	while (args->type != IMAP_ARG_EOL) {
-		switch (args->type) {
-		case IMAP_ARG_NIL:
-			str_append(str, "NIL");
-			break;
-		case IMAP_ARG_ATOM:
-			str_append(str, IMAP_ARG_STR(args));
-			break;
-		case IMAP_ARG_STRING:
-			str_append_c(str, '"');
-			str_append(str, IMAP_ARG_STR(args));
-			str_append_c(str, '"');
-			break;
-		case IMAP_ARG_LIST:
+		if (!str_append_imap_arg(str, args)) {
+			if (args->type != IMAP_ARG_LIST)
+				return FALSE;
+
 			if (!imap_write_list(IMAP_ARG_LIST(args)->args, str))
 				return FALSE;
-			break;
-		default:
-			return FALSE;
 		}
 		args++;
 
@@ -522,23 +531,24 @@
 
 	if (multipart) {
 		/* next is subtype of Content-Type. rest is skipped. */
-		if (args->type != IMAP_ARG_STRING)
-			return FALSE;
-
-		str_printfa(str, " \"%s\"", IMAP_ARG_STR(args));
-		return TRUE;
+		str_append_c(str, ' ');
+		return str_append_imap_arg(str, args);
 	}
 
 	/* "content type" "subtype" */
-	if (args[0].type != IMAP_ARG_STRING || args[1].type != IMAP_ARG_STRING)
+	if (args[0].type == IMAP_ARG_NIL || args[1].type == IMAP_ARG_NIL)
+		return FALSE;
+
+	if (!str_append_imap_arg(str, &args[0]))
+		return FALSE;
+	str_append_c(str, ' ');
+	if (!str_append_imap_arg(str, &args[1]))
 		return FALSE;
 
 	text = strcasecmp(IMAP_ARG_STR(&args[0]), "text") == 0;
 	message_rfc822 = strcasecmp(IMAP_ARG_STR(&args[0]), "message") == 0 &&
 		strcasecmp(IMAP_ARG_STR(&args[1]), "rfc822") == 0;
 
-	str_printfa(str, "\"%s\" \"%s\"", IMAP_ARG_STR(&args[0]),
-		    IMAP_ARG_STR(&args[1]));
 	args += 2;
 
 	/* ("content type param key" "value" ...) | NIL */
@@ -550,9 +560,11 @@
 			    subargs[1].type != IMAP_ARG_STRING)
 				return FALSE;
 
-			str_printfa(str, "\"%s\" \"%s\"",
-				    IMAP_ARG_STR(&subargs[0]),
-				    IMAP_ARG_STR(&subargs[1]));
+			if (!str_append_imap_arg(str, &subargs[0]))
+				return FALSE;
+			str_append_c(str, ' ');
+			if (!str_append_imap_arg(str, &subargs[1]))
+				return FALSE;
 
 			subargs += 2;
 			if (subargs->type == IMAP_ARG_EOL)
@@ -569,16 +581,10 @@
 
 	/* "content id" "content description" "transfer encoding" size */
 	for (i = 0; i < 4; i++, args++) {
-		if (args->type == IMAP_ARG_NIL) {
-			str_append(str, " NIL");
-		} else if (args->type == IMAP_ARG_ATOM) {
-			str_append_c(str, ' ');
-			str_append(str, IMAP_ARG_STR(args));
-		} else if (args->type == IMAP_ARG_STRING) {
-			str_printfa(str, " \"%s\"", IMAP_ARG_STR(args));
-		} else {
+		str_append_c(str, ' ');
+
+		if (!str_append_imap_arg(str, args))
 			return FALSE;
-		}
 	}
 
 	if (text) {
@@ -631,8 +637,8 @@
 	(void)i_stream_read(input);
 
 	parser = imap_parser_create(input, NULL, 0, (size_t)-1);
-	ret = imap_parser_read_args(parser, 0, IMAP_PARSE_FLAG_NO_UNESCAPE,
-				    &args);
+	ret = imap_parser_read_args(parser, 0, IMAP_PARSE_FLAG_NO_UNESCAPE |
+				    IMAP_PARSE_FLAG_LITERAL_TYPE, &args);
 
 	if (ret <= 0 || !imap_parse_bodystructure_args(args, str))
 		value = NULL;

Index: imap-envelope.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-imap/imap-envelope.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- imap-envelope.c	20 Jan 2003 14:52:51 -0000	1.22
+++ imap-envelope.c	8 Feb 2003 10:44:01 -0000	1.23
@@ -54,7 +54,7 @@
 			d->from = message_address_parse(pool, value,
 							value_len, 0);
 		} else if (memcasecmp(name, "Date", 4) == 0 && d->date == NULL)
-			d->date = imap_quote_value(pool, value, value_len);
+			d->date = imap_quote(pool, value, value_len);
 		break;
 	case 6:
 		if (memcasecmp(name, "Sender", 6) == 0 && d->sender == NULL) {
@@ -64,7 +64,7 @@
 		break;
 	case 7:
 		if (memcasecmp(name, "Subject", 7) == 0 && d->subject == NULL)
-			d->subject = imap_quote_value(pool, value, value_len);
+			d->subject = imap_quote(pool, value, value_len);
 		break;
 	case 8:
 		if (memcasecmp(name, "Reply-To", 8) == 0 &&
@@ -75,17 +75,13 @@
 		break;
 	case 10:
 		if (memcasecmp(name, "Message-Id", 10) == 0 &&
-		    d->message_id == NULL) {
-			d->message_id =
-				imap_quote_value(pool, value, value_len);
-		}
+		    d->message_id == NULL)
+			d->message_id = imap_quote(pool, value, value_len);
 		break;
 	case 11:
 		if (memcasecmp(name, "In-Reply-To", 11) == 0 &&
-		    d->in_reply_to == NULL) {
-			d->in_reply_to =
-				imap_quote_value(pool, value, value_len);
-		}
+		    d->in_reply_to == NULL)
+			d->in_reply_to = imap_quote(pool, value, value_len);
 		break;
 	}
 

Index: imap-parser.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-imap/imap-parser.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- imap-parser.c	1 Feb 2003 10:29:17 -0000	1.37
+++ imap-parser.c	8 Feb 2003 10:44:01 -0000	1.38
@@ -230,16 +230,19 @@
 		}
 		break;
 	case ARG_PARSE_LITERAL_DATA:
-		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) == 0) {
-			/* simply save the string */
-			arg->type = IMAP_ARG_STRING;
-			arg->_data.str = p_strndup(parser->pool, data, size);
-		} else {
+		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) != 0) {
 			/* save literal size */
 			arg->type = parser->literal_nonsync ?
 				IMAP_ARG_LITERAL_SIZE_NONSYNC :
 				IMAP_ARG_LITERAL_SIZE;
 			arg->_data.literal_size = parser->literal_size;
+		} else if ((parser->flags &
+			    IMAP_PARSE_FLAG_LITERAL_TYPE) != 0) {
+			arg->type = IMAP_ARG_LITERAL;
+			arg->_data.str = p_strndup(parser->pool, data, size);
+		} else {
+			arg->type = IMAP_ARG_STRING;
+			arg->_data.str = p_strndup(parser->pool, data, size);
 		}
 		break;
 	default:

Index: imap-parser.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-imap/imap-parser.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- imap-parser.h	23 Jan 2003 03:28:46 -0000	1.12
+++ imap-parser.h	8 Feb 2003 10:44:01 -0000	1.13
@@ -9,15 +9,20 @@
 	IMAP_PARSE_FLAG_LITERAL_SIZE	= 0x01,
 	/* Don't remove '\' chars from string arguments */
 	IMAP_PARSE_FLAG_NO_UNESCAPE	= 0x02,
+	/* Return literals as IMAP_ARG_LITERAL instead of IMAP_ARG_STRING */
+	IMAP_PARSE_FLAG_LITERAL_TYPE	= 0x04
 };
 
 enum imap_arg_type {
 	IMAP_ARG_NIL = 0,
 	IMAP_ARG_ATOM,
 	IMAP_ARG_STRING,
+	IMAP_ARG_LIST,
+
+	/* literals are returned as IMAP_ARG_STRING by default */
+	IMAP_ARG_LITERAL,
 	IMAP_ARG_LITERAL_SIZE,
 	IMAP_ARG_LITERAL_SIZE_NONSYNC,
-	IMAP_ARG_LIST,
 
 	IMAP_ARG_EOL /* end of argument list */
 };
@@ -37,7 +42,8 @@
 
 #define IMAP_ARG_STR(arg) \
 	((arg)->type == IMAP_ARG_NIL ? NULL : \
-	 (arg)->type == IMAP_ARG_ATOM || (arg)->type == IMAP_ARG_STRING ? \
+	 (arg)->type == IMAP_ARG_ATOM || (arg)->type == IMAP_ARG_STRING || \
+	 (arg)->type == IMAP_ARG_LITERAL ? \
 	 (arg)->_data.str : _imap_arg_str_error(arg))
 
 #define IMAP_ARG_LITERAL_SIZE(arg) \

Index: imap-quote.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-imap/imap-quote.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- imap-quote.c	5 Jan 2003 13:09:52 -0000	1.5
+++ imap-quote.c	8 Feb 2003 10:44:01 -0000	1.6
@@ -4,177 +4,50 @@
 #include "str.h"
 #include "imap-quote.h"
 
-#define IS_BREAK_CHAR(c) \
-	((c) == ' ' || (c) == '\t' || \
-	 (c) == ',' || (c) == ':' || (c) == ';' || (c) == '@' || \
-	 (c) == '<' || (c) == '>' || (c) == '(' || (c) == ')' || \
-	 (c) == '[' || (c) == ']' || (c) == '=')
-
-#define IS_BREAK_OR_CRLF_CHAR(c) \
-	(IS_BREAK_CHAR(c) || (c) == '\r' || (c) == '\n')
-
-static size_t next_token_quoted(const unsigned char *value, size_t len,
-				int *need_qp, int *quoted)
+void imap_quote_append(string_t *str, const unsigned char *value,
+		       size_t value_len)
 {
 	size_t i;
 
-	*need_qp = FALSE;
-	*quoted = TRUE;
-
-	for (i = *quoted ? 0 : 1; i < len; i++) {
-		if (value[i] & 0x80)
-			*need_qp = TRUE;
-
-		if (value[i] == '"' || value[i] == '\r' || value[i] == '\n') {
-			i++;
-			*quoted = value[i] == '"';
+	for (i = 0; i < value_len; i++) {
+		if (value[i] == 0) {
+			value_len = i;
 			break;
 		}
-	}
-
-	return i;
-}
-
-static size_t next_token(const unsigned char *value, size_t len,
-			 int *need_qp, int *quoted, int qp_on)
-{
-	size_t i = 0;
-
-	if (value[0] == '"' || *quoted)
-		return next_token_quoted(value, len, need_qp, quoted);
-
-	*need_qp = FALSE;
-
-	if (qp_on) {
-		/* skip spaces, so we don't end up QP'ing word at a time */
-		for (i = 0; i < len; i++) {
-			if (value[i] != ' ')
-				break;
-		}
-
-		if (i == len)
-			return i;
-	}
-
-	if (IS_BREAK_OR_CRLF_CHAR(value[i])) {
-		/* return all break-chars in one token */
-		for (i++; i < len; i++) {
-			if (!IS_BREAK_CHAR(value[i]))
-				break;
-		}
-
-		return i;
-	}
-
-	/* then stop at break-char */
-	for (; i < len; i++) {
-		if (value[i] & 0x80)
-			*need_qp = TRUE;
 
-		if (IS_BREAK_OR_CRLF_CHAR(value[i]))
+		if ((value[i] & 0x80) != 0)
 			break;
 	}
 
-	return i;
-}
-
-static void append_quoted_qp(string_t *str, const unsigned char *value,
-			     size_t len)
-{
-	size_t i;
-	unsigned char c;
-
-	/* do this the easy way, it's already broken behaviour to leave the
-	   8bit text in mailbox, so we shouldn't need to try too hard to make
-	   it readable. Keep 'A'..'Z', 'a'..'z' and '0'..'9', QP rest */
-
-	for (i = 0; i < len; i++) {
-		if (value[i] == ' ')
-			str_append_c(str, '_');
-		else if ((value[i] >= 'A' && value[i] <= 'Z') ||
-			 (value[i] >= 'a' && value[i] <= 'z') ||
-			 (value[i] >= '0' && value[i] <= '9')) {
-			str_append_c(str, value[i]);
-		} else {
-			str_append_c(str, '=');
-			c = value[i] >> 4;
-			str_append_c(str, c < 10 ? (c+'0') : (c-10+'A'));
-			c = value[i] & 0x0f;
-			str_append_c(str, c < 10 ? (c+'0') : (c-10+'A'));
-		}
-	}
-}
-
-static void append_quoted(string_t *str, const unsigned char *value, size_t len)
-{
-	size_t i;
-
-	for (i = 0; i < len; i++) {
-		if (value[i] == '\\' || value[i] == '"')
-			str_append_c(str, '\\');
-		str_append_c(str, value[i]);
+	if (i == value_len) {
+		/* no 8bit chars, return as "string" */
+		str_append_c(str, '"');
+		str_append_n(str, value, value_len);
+		str_append_c(str, '"');
+	} else {
+		/* return as literal */
+		str_printfa(str, "{%"PRIuSIZE_T"}\r\n", value_len);
+		str_append_n(str, value, value_len);
 	}
 }
 
-/* does two things: 1) escape '\' and '"' characters, 2) 8bit text -> QP */
-static string_t *get_quoted_str(const unsigned char *value, size_t value_len)
+const char *imap_quote_str_nil(const char *value)
 {
 	string_t *str;
-	size_t token_len;
-	int qp, need_qp, quoted;
-
-	str = t_str_new(value_len * 2);
-	qp = FALSE;
-	quoted = FALSE;
 
-	str_append_c(str, '"');
-	while (value_len > 0) {
-		token_len = next_token(value, value_len, &need_qp, &quoted, qp);
-		i_assert(token_len > 0 && token_len <= value_len);
-
-		/* header may be split to multiple lines, we don't want them */
-		while (token_len > 0 && (value[0] == '\r' ||
-					 value[0] == '\n')) {
-			value++;
-			token_len--;
-			value_len--;
-		}
-
-		if (need_qp && !qp) {
-			str_append(str, "=?x-unknown?Q?");
-			qp = TRUE;
-		} else if (!need_qp && qp) {
-			str_append(str, "?=");
-			qp = FALSE;
-		}
-
-		if (need_qp)
-			append_quoted_qp(str, value, token_len);
-		else
-			append_quoted(str, value, token_len);
-
-		value += token_len;
-		value_len -= token_len;
-	}
-
-	if (qp) str_append(str, "?=");
-	str_append_c(str, '"');
-
-	return str;
-}
+	if (value == NULL)
+		return "NIL";
 
-const char *imap_quote_str_nil(const char *value)
-{
-	return value == NULL ? "NIL" :
-		str_c(get_quoted_str((const unsigned char *) value,
-				     strlen(value)));
+	str = t_str_new(512);
+	imap_quote_append(str, (const unsigned char *) value, (size_t)-1);
+	return str_c(str);
 }
 
-char *imap_quote_value(pool_t pool, const unsigned char *value,
-		       size_t value_len)
+char *imap_quote(pool_t pool, const unsigned char *value, size_t value_len)
 {
 	string_t *str;
 
-	str = get_quoted_str(value, value_len);
+	str = t_str_new(value_len + MAX_INT_STRLEN + 5);
+	imap_quote_append(str, value, value_len);
 	return p_strndup(pool, str_data(str), str_len(str));
 }

Index: imap-quote.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-imap/imap-quote.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- imap-quote.h	5 Jan 2003 13:09:52 -0000	1.3
+++ imap-quote.h	8 Feb 2003 10:44:01 -0000	1.4
@@ -1,11 +1,15 @@
 #ifndef __IMAP_QUOTE_H
 #define __IMAP_QUOTE_H
 
-/* If value is non-NULL, return it "quoted", otherwise return NIL unquoted. */
-const char *imap_quote_str_nil(const char *value);
+/* Return value suitable for sending to client, either as quoted-string or
+   literal. */
+char *imap_quote(pool_t pool, const unsigned char *value, size_t value_len);
 
-/* Return value quoted and allocated from specified pool. */
-char *imap_quote_value(pool_t pool, const unsigned char *value,
+/* Append to existing string. */
+void imap_quote_append(string_t *str, const unsigned char *value,
 		       size_t value_len);
+
+/* If value is NULL, return NIL. */
+const char *imap_quote_str_nil(const char *value);
 
 #endif




More information about the dovecot-cvs mailing list