changeset 15245:42f99a4fc763

lib-imap: Changed public IS_ATOM*() macros to match RFC 3501 exactly. Move the imap-parser specific "atom plus some more" parsing macro inside imap-parser.c so it's not used by anyone else.
author Timo Sirainen <tss@iki.fi>
date Wed, 24 Oct 2012 10:05:37 +0300
parents ff86acd4eef5
children d9c44aafd163
files src/lib-imap/imap-arg.h src/lib-imap/imap-parser.c src/lib-storage/mailbox-keywords.c
diffstat 3 files changed, 40 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-imap/imap-arg.h	Wed Oct 24 09:39:52 2012 +0300
+++ b/src/lib-imap/imap-arg.h	Wed Oct 24 10:05:37 2012 +0300
@@ -3,19 +3,32 @@
 
 #include "array.h"
 
-/* We use this macro to read atoms from input. It should probably contain
-   everything some day, but for now we can't handle some input otherwise:
+/* ABNF:
+
+   CHAR           =  %x01-7F
+   CTL            =  %x00-1F / %x7F
+   SP             =  %x20
+   DQUOTE         =  %x22 */
 
-   ']' is required for parsing section (FETCH BODY[])
-   '%', '*' and ']' are valid list-chars for LIST patterns
-   '\' is used in flags */
-#define IS_ATOM_SPECIAL_INPUT(c) \
-	((c) == '(' || (c) == ')' || (c) == '{' || \
-	 (c) == '"' || (c) <= 32 || (c) == 0x7f)
+/* ASTRING-CHAR   = ATOM-CHAR / resp-specials */
+#define IS_ASTRING_CHAR(c) (IS_ATOM_CHAR(c) || IS_RESP_SPECIAL(c))
+/* ATOM-CHAR       = <any CHAR except atom-specials> */
+#define IS_ATOM_CHAR(c) (!IS_ATOM_SPECIAL(c))
+/* atom-specials   = "(" / ")" / "{" / SP / CTL / list-wildcards /
+                     quoted-specials / resp-specials
+   Since atoms are only 7bit, we'll also optimize a bit by assuming 8bit chars
+   are also atom-specials. */
+#define IS_ATOM_SPECIAL(c) \
+	((unsigned char)(c) <= 0x20 || (unsigned char)(c) >= 0x7f || \
+	 (c) == '(' || (c) == ')' || (c) == '{' || IS_LIST_WILDCARD(c) || \
+	 IS_QUOTED_SPECIAL(c) || IS_RESP_SPECIAL(c))
 
-#define IS_ATOM_SPECIAL(c) \
-	(IS_ATOM_SPECIAL_INPUT(c) || \
-	 (c) == ']' || (c) == '%' || (c) == '*' || (c) == '\\')
+/* list-wildcards  = "%" / "*" */
+#define IS_LIST_WILDCARD(c) ((c) == '%' || (c) == '*')
+/* quoted-specials = DQUOTE / "\" */
+#define IS_QUOTED_SPECIAL(c) ((c) == '\"' || (c) == '\\')
+/* resp-specials   = "]" */
+#define IS_RESP_SPECIAL(c) ((c) == ']')
 
 enum imap_arg_type {
 	IMAP_ARG_NIL = 0,
--- a/src/lib-imap/imap-parser.c	Wed Oct 24 09:39:52 2012 +0300
+++ b/src/lib-imap/imap-parser.c	Wed Oct 24 10:05:37 2012 +0300
@@ -6,6 +6,16 @@
 #include "strescape.h"
 #include "imap-parser.h"
 
+/* We use this macro to read atoms from input. It should probably contain
+   everything some day, but for now we can't handle some input otherwise:
+
+   ']' is required for parsing section (FETCH BODY[])
+   '%', '*' and ']' are valid list-chars for LIST patterns
+   '\' is used in flags */
+#define IS_ATOM_PARSER_INPUT(c) \
+	((c) == '(' || (c) == ')' || (c) == '{' || \
+	 (c) == '"' || (c) <= 32 || (c) == 0x7f)
+
 #define is_linebreak(c) \
 	((c) == '\r' || (c) == '\n')
 
@@ -280,7 +290,7 @@
 {
 	const char *error;
 
-	if (IS_ATOM_SPECIAL_INPUT((unsigned char)chr))
+	if (IS_ATOM_PARSER_INPUT((unsigned char)chr))
 		error = "Invalid characters in atom";
 	else if ((chr & 0x80) != 0)
 		error = "8bit data in atom";
--- a/src/lib-storage/mailbox-keywords.c	Wed Oct 24 09:39:52 2012 +0300
+++ b/src/lib-storage/mailbox-keywords.c	Wed Oct 24 10:05:37 2012 +0300
@@ -117,12 +117,11 @@
 	/* these are IMAP-specific restrictions, but for now IMAP is all we
 	   care about */
 	for (i = 0; keyword[i] != '\0'; i++) {
-		if (IS_ATOM_SPECIAL((unsigned char)keyword[i])) {
-			*error_r = "Invalid characters in keyword";
-			return FALSE;
-		}
-		if ((unsigned char)keyword[i] >= 0x80) {
-			*error_r = "8bit characters in keyword";
+		if (!IS_ATOM_CHAR(keyword[i])) {
+			if ((unsigned char)keyword[i] < 0x80)
+				*error_r = "Invalid characters in keyword";
+			else
+				*error_r = "8bit characters in keyword";
 			return FALSE;
 		}
 	}