[dovecot-cvs] dovecot/src/lib-mail message-header-decode.c, 1.9, 1.10

tss at dovecot.org tss at dovecot.org
Wed Apr 4 08:39:15 EEST 2007


Update of /var/lib/cvs/dovecot/src/lib-mail
In directory talvi:/tmp/cvs-serv18597

Modified Files:
	message-header-decode.c 
Log Message:
Rewrite/cleanup



Index: message-header-decode.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-mail/message-header-decode.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- message-header-decode.c	3 Apr 2007 13:55:08 -0000	1.9
+++ message-header-decode.c	4 Apr 2007 05:39:13 -0000	1.10
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2007 Timo Sirainen */
 
 #include "lib.h"
 #include "base64.h"
@@ -6,116 +6,110 @@
 #include "quoted-printable.h"
 #include "message-header-decode.h"
 
-static bool split_encoded(const unsigned char *data, size_t *size_p,
-			  const char **charset, const char **encoding,
-			  const unsigned char **text, size_t *text_size_r)
-{
-	size_t size, pos, textpos;
-
-	size = *size_p;
-
-	/* get charset */
-	for (pos = 0; pos < size && data[pos] != '?'; pos++) ;
-	if (data[pos] != '?') return FALSE;
-	*charset = t_strndup(data, pos);
-
-	/* get encoding */
-	pos++;
-	if (pos+2 >= size || data[pos+1] != '?')
-		return FALSE;
-
-	if (data[pos] == 'Q' || data[pos] == 'q')
-		*encoding = "Q";
-	else if (data[pos] == 'B' || data[pos] == 'b')
-		*encoding = "B";
-	else
-		return FALSE;
-
-	/* get text */
-	pos += 2;
-	textpos = pos;
-	while (pos < size && data[pos] != '?') pos++;
-	if (data[pos] != '?' || pos+1 >= size || data[pos+1] != '=')
-		return FALSE;
-
-	*text = data + textpos;
-	*text_size_r = pos - textpos;
-	*size_p = pos+2;
-	return TRUE;
-}
-
-static bool
-message_header_decode_encoded(const unsigned char *data, size_t *size,
-			      message_header_decode_callback_t *callback,
-			      void *context)
+static size_t
+message_header_decode_encoded(const unsigned char *data, size_t size,
+			      buffer_t *decodebuf, unsigned int *charsetlen_r)
 {
-	const unsigned char *text;
-	const char *charset, *encoding;
-	buffer_t *decodebuf;
-	size_t text_size;
-	int ret;
-
-	t_push();
+#define QCOUNT 3
+	unsigned int num = 0;
+	size_t i, start_pos[QCOUNT];
 
-	/* first split the string charset?encoding?text?= */
-	if (!split_encoded(data, size, &charset, &encoding,
-			   &text, &text_size)) {
-		t_pop();
-		return TRUE;
+	/* data should contain "charset?encoding?text?=" */
+	for (i = 0; i < size; i++) {
+		if (data[i] == '?') {
+			start_pos[num++] = i;
+			if (num == QCOUNT)
+				break;
+		}
+	}
+	if (i == size || data[i+1] != '=') {
+		/* invalid block */
+		return 0;
 	}
 
-	decodebuf = buffer_create_static_hard(pool_datastack_create(),
-					      text_size);
+	buffer_append(decodebuf, data, start_pos[0]);
+	buffer_append_c(decodebuf, '\0');
+	*charsetlen_r = decodebuf->used;
 
-	if (*encoding == 'Q')
-		quoted_printable_decode(text, text_size, NULL, decodebuf);
-	else {
-		if (base64_decode(text, text_size, NULL, decodebuf) < 0) {
-			/* corrupted encoding */
-			t_pop();
-			return TRUE;
+	switch (data[start_pos[0]+1]) {
+	case 'q':
+	case 'Q':
+		quoted_printable_decode(data + start_pos[1] + 1,
+					start_pos[2] - start_pos[1] - 1,
+					NULL, decodebuf);
+		break;
+	case 'b':
+	case 'B':
+		if (base64_decode(data + start_pos[1] + 1,
+				  start_pos[2] - start_pos[1] - 1,
+				  NULL, decodebuf) < 0) {
+			/* contains invalid data. show what we got so far. */
 		}
+		break;
+	default:
+		/* unknown encoding */
+		return 0;
 	}
 
-	ret = decodebuf->used == 0 ? FALSE :
-		callback(decodebuf->data, decodebuf->used, charset, context);
-
-	t_pop();
-	return ret;
+	return start_pos[2] + 2;
 }
 
 void message_header_decode(const unsigned char *data, size_t size,
 			   message_header_decode_callback_t *callback,
 			   void *context)
 {
-	size_t pos, start_pos, subsize;
+	buffer_t *decodebuf = NULL;
+	unsigned int charsetlen = 0;
+	size_t pos, start_pos;
 
+	/* =?charset?Q|B?text?= */
+	t_push();
 	start_pos = pos = 0;
-	while (pos < size) {
-		if (data[pos] == '=' && pos+1 < size && data[pos+1] == '?') {
-			/* encoded string beginning */
-			if (pos != start_pos) {
-				/* send the unencoded data so far */
-				if (!callback(data + start_pos, pos - start_pos,
-					      NULL, context))
-					return;
-			}
+	for (pos = 0; pos + 1 < size; ) {
+		if (data[pos] != '=' || data[pos+1] != '?') {
+			pos++;
+			continue;
+		}
 
-			pos += 2;
-			subsize = size - pos;
-			if (!message_header_decode_encoded(data + pos, &subsize,
-							   callback, context))
-				return;
+		/* encoded string beginning */
+		if (pos != start_pos) {
+			/* send the unencoded data so far */
+			if (!callback(data + start_pos, pos - start_pos,
+				      NULL, context)) {
+				start_pos = size;
+				break;
+			}
+		}
 
-			pos += subsize;
-			start_pos = pos;
+		if (decodebuf == NULL) {
+			decodebuf =
+				buffer_create_dynamic(pool_datastack_create(),
+						      size - pos);
 		} else {
-			pos++;
+			buffer_set_used_size(decodebuf, 0);
 		}
+
+		pos += 2;
+		pos += message_header_decode_encoded(data + pos, size - pos,
+						     decodebuf, &charsetlen);
+
+		if (decodebuf->used > charsetlen) {
+			/* decodebuf contains <charset> NUL <text> */
+			if (!callback(CONST_PTR_OFFSET(decodebuf->data,
+						       charsetlen),
+				      decodebuf->used - charsetlen,
+				      decodebuf->data, context)) {
+				start_pos = size;
+				break;
+			}
+		}
+
+		start_pos = pos;
 	}
 
-	if (size > start_pos) {
+	if (size != start_pos) {
 		(void)callback(data + start_pos, size - start_pos,
 			       NULL, context);
 	}
+	t_pop();
 }



More information about the dovecot-cvs mailing list