[gmime] Filter Content-* headers in the parser instead



commit 4d7f5a6ecf2ed036297e9e9ebbb36090b435d676
Author: Jeffrey Stedfast <fejj gnome org>
Date:   Mon Feb 20 10:54:22 2012 -0500

    Filter Content-* headers in the parser instead
    
    2012-02-20  Jeffrey Stedfast  <fejj gnome org>
    
    	* gmime/gmime-parser.c: Instead of filtering Content-* headers
    	inside GMimeObject subclasses, filter them in the parser. This
    way
    	header fetching works as expected in subparts which might have
    	non-standard headers (X-* and whatnot).

 ChangeLog                  |    7 +++
 gmime/gmime-message-part.c |   77 ------------------------------
 gmime/gmime-multipart.c    |   79 -------------------------------
 gmime/gmime-object.c       |    5 ++-
 gmime/gmime-parser.c       |   36 ++++++++------
 gmime/gmime-part.c         |  112 +++++++++++++++++++-------------------------
 6 files changed, 79 insertions(+), 237 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 54898a1..ef67ef8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2012-02-20  Jeffrey Stedfast  <fejj gnome org>
+
+	* gmime/gmime-parser.c: Instead of filtering Content-* headers
+	inside GMimeObject subclasses, filter them in the parser. This way
+	header fetching works as expected in subparts which might have
+	non-standard headers (X-* and whatnot).
+
 2012-02-19  Jeffrey Stedfast  <fejj gnome org>
 
 	* gmime/gmime-encodings.c (g_mime_content_encoding_from_string):
diff --git a/gmime/gmime-message-part.c b/gmime/gmime-message-part.c
index 2ed9d1c..23b9b58 100644
--- a/gmime/gmime-message-part.c
+++ b/gmime/gmime-message-part.c
@@ -47,13 +47,6 @@ static void g_mime_message_part_init (GMimeMessagePart *message_part, GMimeMessa
 static void g_mime_message_part_finalize (GObject *object);
 
 /* GMimeObject class methods */
-static void message_part_prepend_header (GMimeObject *object, const char *header, const char *value);
-static void message_part_append_header (GMimeObject *object, const char *header, const char *value);
-static void message_part_set_header (GMimeObject *object, const char *header, const char *value);
-static const char *message_part_get_header (GMimeObject *object, const char *header);
-static gboolean message_part_remove_header (GMimeObject *object, const char *header);
-static void message_part_set_content_type (GMimeObject *object, GMimeContentType *content_type);
-static char *message_part_get_headers (GMimeObject *object);
 static ssize_t message_part_write_to_stream (GMimeObject *object, GMimeStream *stream);
 
 
@@ -95,13 +88,6 @@ g_mime_message_part_class_init (GMimeMessagePartClass *klass)
 	
 	gobject_class->finalize = g_mime_message_part_finalize;
 	
-	object_class->prepend_header = message_part_prepend_header;
-	object_class->append_header = message_part_append_header;
-	object_class->remove_header = message_part_remove_header;
-	object_class->set_header = message_part_set_header;
-	object_class->get_header = message_part_get_header;
-	object_class->set_content_type = message_part_set_content_type;
-	object_class->get_headers = message_part_get_headers;
 	object_class->write_to_stream = message_part_write_to_stream;
 }
 
@@ -122,69 +108,6 @@ g_mime_message_part_finalize (GObject *object)
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static void
-message_part_prepend_header (GMimeObject *object, const char *header, const char *value)
-{
-	/* RFC 1864 states that you cannot set a Content-MD5 on a message part */
-	if (!g_ascii_strcasecmp ("Content-MD5", header))
-		return;
-	
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a message part */
-	if (!g_ascii_strncasecmp ("Content-", header, 8))
-		GMIME_OBJECT_CLASS (parent_class)->prepend_header (object, header, value);
-}
-
-static void
-message_part_append_header (GMimeObject *object, const char *header, const char *value)
-{
-	/* RFC 1864 states that you cannot set a Content-MD5 on a message part */
-	if (!g_ascii_strcasecmp ("Content-MD5", header))
-		return;
-	
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a message part */
-	if (!g_ascii_strncasecmp ("Content-", header, 8))
-		GMIME_OBJECT_CLASS (parent_class)->append_header (object, header, value);
-}
-
-static void
-message_part_set_header (GMimeObject *object, const char *header, const char *value)
-{
-	/* RFC 1864 states that you cannot set a Content-MD5 on a message part */
-	if (!g_ascii_strcasecmp ("Content-MD5", header))
-		return;
-	
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a message part */
-	if (!g_ascii_strncasecmp ("Content-", header, 8))
-		GMIME_OBJECT_CLASS (parent_class)->set_header (object, header, value);
-}
-
-static const char *
-message_part_get_header (GMimeObject *object, const char *header)
-{
-	return GMIME_OBJECT_CLASS (parent_class)->get_header (object, header);
-}
-
-static gboolean
-message_part_remove_header (GMimeObject *object, const char *header)
-{
-	return GMIME_OBJECT_CLASS (parent_class)->remove_header (object, header);
-}
-
-static void
-message_part_set_content_type (GMimeObject *object, GMimeContentType *content_type)
-{
-	GMIME_OBJECT_CLASS (parent_class)->set_content_type (object, content_type);
-}
-
-static char *
-message_part_get_headers (GMimeObject *object)
-{
-	return GMIME_OBJECT_CLASS (parent_class)->get_headers (object);
-}
-
 static ssize_t
 message_part_write_to_stream (GMimeObject *object, GMimeStream *stream)
 {
diff --git a/gmime/gmime-multipart.c b/gmime/gmime-multipart.c
index a1da42a..415b621 100644
--- a/gmime/gmime-multipart.c
+++ b/gmime/gmime-multipart.c
@@ -55,13 +55,6 @@ static void g_mime_multipart_init (GMimeMultipart *multipart, GMimeMultipartClas
 static void g_mime_multipart_finalize (GObject *object);
 
 /* GMimeObject class methods */
-static void multipart_prepend_header (GMimeObject *object, const char *header, const char *value);
-static void multipart_append_header (GMimeObject *object, const char *header, const char *value);
-static void multipart_set_header (GMimeObject *object, const char *header, const char *value);
-static const char *multipart_get_header (GMimeObject *object, const char *header);
-static gboolean multipart_remove_header (GMimeObject *object, const char *header);
-static void multipart_set_content_type (GMimeObject *object, GMimeContentType *content_type);
-static char *multipart_get_headers (GMimeObject *object);
 static ssize_t multipart_write_to_stream (GMimeObject *object, GMimeStream *stream);
 static void multipart_encode (GMimeObject *object, GMimeEncodingConstraint constraint);
 
@@ -117,13 +110,6 @@ g_mime_multipart_class_init (GMimeMultipartClass *klass)
 	
 	gobject_class->finalize = g_mime_multipart_finalize;
 	
-	object_class->prepend_header = multipart_prepend_header;
-	object_class->append_header = multipart_append_header;
-	object_class->remove_header = multipart_remove_header;
-	object_class->set_header = multipart_set_header;
-	object_class->get_header = multipart_get_header;
-	object_class->set_content_type = multipart_set_content_type;
-	object_class->get_headers = multipart_get_headers;
 	object_class->write_to_stream = multipart_write_to_stream;
 	object_class->encode = multipart_encode;
 	
@@ -165,71 +151,6 @@ g_mime_multipart_finalize (GObject *object)
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static void
-multipart_prepend_header (GMimeObject *object, const char *header, const char *value)
-{
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a multipart */
-	if (!g_ascii_strncasecmp ("Content-", header, 8))
-		GMIME_OBJECT_CLASS (parent_class)->prepend_header (object, header, value);
-}
-
-static void
-multipart_append_header (GMimeObject *object, const char *header, const char *value)
-{
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a multipart */
-	if (!g_ascii_strncasecmp ("Content-", header, 8))
-		GMIME_OBJECT_CLASS (parent_class)->append_header (object, header, value);
-}
-
-static void
-multipart_set_header (GMimeObject *object, const char *header, const char *value)
-{
-	/* RFC 1864 states that you cannot set a Content-MD5 on a multipart */
-	if (!g_ascii_strcasecmp ("Content-MD5", header))
-		return;
-	
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a multipart */
-	if (!g_ascii_strncasecmp ("Content-", header, 8))
-		GMIME_OBJECT_CLASS (parent_class)->set_header (object, header, value);
-}
-
-static const char *
-multipart_get_header (GMimeObject *object, const char *header)
-{
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a multipart */
-	if (!g_ascii_strncasecmp ("Content-", header, 8))
-		return GMIME_OBJECT_CLASS (parent_class)->get_header (object, header);
-	else
-		return NULL;
-}
-
-static gboolean
-multipart_remove_header (GMimeObject *object, const char *header)
-{
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a multipart */
-	if (g_ascii_strncasecmp ("Content-", header, 8) != 0)
-		return FALSE;
-	
-	return GMIME_OBJECT_CLASS (parent_class)->remove_header (object, header);
-}
-
-static void
-multipart_set_content_type (GMimeObject *object, GMimeContentType *content_type)
-{
-	GMIME_OBJECT_CLASS (parent_class)->set_content_type (object, content_type);
-}
-
-static char *
-multipart_get_headers (GMimeObject *object)
-{
-	return GMIME_OBJECT_CLASS (parent_class)->get_headers (object);
-}
-
 static ssize_t
 multipart_write_to_stream (GMimeObject *object, GMimeStream *stream)
 {
diff --git a/gmime/gmime-object.c b/gmime/gmime-object.c
index e57d285..d1f42ef 100644
--- a/gmime/gmime-object.c
+++ b/gmime/gmime-object.c
@@ -728,8 +728,11 @@ process_header (GMimeObject *object, const char *header, const char *value)
 	GMimeContentType *content_type;
 	guint i;
 	
+	if (g_ascii_strncasecmp (header, "Content-", 8) != 0)
+		return FALSE;
+	
 	for (i = 0; i < G_N_ELEMENTS (content_headers); i++) {
-		if (!g_ascii_strcasecmp (content_headers[i], header))
+		if (!g_ascii_strcasecmp (content_headers[i] + 8, header + 8))
 			break;
 	}
 	
diff --git a/gmime/gmime-parser.c b/gmime/gmime-parser.c
index 28b66bf..bbbfbc9 100644
--- a/gmime/gmime-parser.c
+++ b/gmime/gmime-parser.c
@@ -92,9 +92,9 @@ static void parser_init (GMimeParser *parser, GMimeStream *stream);
 static void parser_close (GMimeParser *parser);
 
 static GMimeObject *parser_construct_leaf_part (GMimeParser *parser, ContentType *content_type,
-						int *found);
+						gboolean toplevel, int *found);
 static GMimeObject *parser_construct_multipart (GMimeParser *parser, ContentType *content_type,
-						int *found);
+						gboolean toplevel, int *found);
 
 static GObjectClass *parent_class = NULL;
 
@@ -1570,15 +1570,16 @@ parser_scan_message_part (GMimeParser *parser, GMimeMessagePart *mpart, int *fou
 	message = g_mime_message_new (FALSE);
 	header = priv->headers;
 	while (header) {
-		g_mime_object_append_header ((GMimeObject *) message, header->name, header->value);
+		if (g_ascii_strncasecmp (header->name, "Content-", 8) != 0)
+			g_mime_object_append_header ((GMimeObject *) message, header->name, header->value);
 		header = header->next;
 	}
 	
 	content_type = parser_content_type (parser);
 	if (content_type_is_type (content_type, "multipart", "*"))
-		object = parser_construct_multipart (parser, content_type, found);
+		object = parser_construct_multipart (parser, content_type, TRUE, found);
 	else
-		object = parser_construct_leaf_part (parser, content_type, found);
+		object = parser_construct_leaf_part (parser, content_type, TRUE, found);
 	
 	content_type_destroy (content_type);
 	message->mime_part = object;
@@ -1592,7 +1593,7 @@ parser_scan_message_part (GMimeParser *parser, GMimeMessagePart *mpart, int *fou
 }
 
 static GMimeObject *
-parser_construct_leaf_part (GMimeParser *parser, ContentType *content_type, int *found)
+parser_construct_leaf_part (GMimeParser *parser, ContentType *content_type, gboolean toplevel, int *found)
 {
 	struct _GMimeParserPrivate *priv = parser->priv;
 	GMimeObject *object;
@@ -1613,7 +1614,8 @@ parser_construct_leaf_part (GMimeParser *parser, ContentType *content_type, int
 	
 	header = priv->headers;
 	while (header) {
-		g_mime_object_append_header (object, header->name, header->value);
+		if (!toplevel || !g_ascii_strncasecmp (header->name, "Content-", 8))
+			g_mime_object_append_header (object, header->name, header->value);
 		header = header->next;
 	}
 	
@@ -1732,9 +1734,9 @@ parser_scan_multipart_subparts (GMimeParser *parser, GMimeMultipart *multipart)
 		
 		content_type = parser_content_type (parser);
 		if (content_type_is_type (content_type, "multipart", "*"))
-			subpart = parser_construct_multipart (parser, content_type, &found);
+			subpart = parser_construct_multipart (parser, content_type, FALSE, &found);
 		else
-			subpart = parser_construct_leaf_part (parser, content_type, &found);
+			subpart = parser_construct_leaf_part (parser, content_type, FALSE, &found);
 		
 		g_mime_multipart_add (multipart, subpart);
 		content_type_destroy (content_type);
@@ -1745,7 +1747,7 @@ parser_scan_multipart_subparts (GMimeParser *parser, GMimeMultipart *multipart)
 }
 
 static GMimeObject *
-parser_construct_multipart (GMimeParser *parser, ContentType *content_type, int *found)
+parser_construct_multipart (GMimeParser *parser, ContentType *content_type, gboolean toplevel, int *found)
 {
 	struct _GMimeParserPrivate *priv = parser->priv;
 	GMimeMultipart *multipart;
@@ -1760,7 +1762,8 @@ parser_construct_multipart (GMimeParser *parser, ContentType *content_type, int
 	
 	header = priv->headers;
 	while (header) {
-		g_mime_object_append_header (object, header->name, header->value);
+		if (!toplevel || !g_ascii_strncasecmp (header->name, "Content-", 8))
+			g_mime_object_append_header (object, header->name, header->value);
 		header = header->next;
 	}
 	
@@ -1830,9 +1833,9 @@ parser_construct_part (GMimeParser *parser)
 	
 	content_type = parser_content_type (parser);
 	if (content_type_is_type (content_type, "multipart", "*"))
-		object = parser_construct_multipart (parser, content_type, &found);
+		object = parser_construct_multipart (parser, content_type, TRUE, &found);
 	else
-		object = parser_construct_leaf_part (parser, content_type, &found);
+		object = parser_construct_leaf_part (parser, content_type, TRUE, &found);
 	
 	content_type_destroy (content_type);
 	
@@ -1891,7 +1894,8 @@ parser_construct_message (GMimeParser *parser)
 				content_length = ULONG_MAX;
 		}
 		
-		g_mime_object_append_header ((GMimeObject *) message, header->name, header->value);
+		if (g_ascii_strncasecmp (header->name, "Content-", 8) != 0)
+			g_mime_object_append_header ((GMimeObject *) message, header->name, header->value);
 		header = header->next;
 	}
 	
@@ -1903,9 +1907,9 @@ parser_construct_message (GMimeParser *parser)
 	
 	content_type = parser_content_type (parser);
 	if (content_type_is_type (content_type, "multipart", "*"))
-		object = parser_construct_multipart (parser, content_type, &found);
+		object = parser_construct_multipart (parser, content_type, TRUE, &found);
 	else
-		object = parser_construct_leaf_part (parser, content_type, &found);
+		object = parser_construct_leaf_part (parser, content_type, TRUE, &found);
 	
 	content_type_destroy (content_type);
 	message->mime_part = object;
diff --git a/gmime/gmime-part.c b/gmime/gmime-part.c
index 4bcc8f9..afc59b8 100644
--- a/gmime/gmime-part.c
+++ b/gmime/gmime-part.c
@@ -37,6 +37,7 @@
 #include "gmime-filter-best.h"
 #include "gmime-filter-crlf.h"
 #include "gmime-filter-md5.h"
+#include "gmime-table-private.h"
 
 #define d(x)
 
@@ -60,9 +61,7 @@ static void g_mime_part_finalize (GObject *object);
 static void mime_part_prepend_header (GMimeObject *object, const char *header, const char *value);
 static void mime_part_append_header (GMimeObject *object, const char *header, const char *value);
 static void mime_part_set_header (GMimeObject *object, const char *header, const char *value);
-static const char *mime_part_get_header (GMimeObject *object, const char *header);
 static gboolean mime_part_remove_header (GMimeObject *object, const char *header);
-static char *mime_part_get_headers (GMimeObject *object);
 static ssize_t mime_part_write_to_stream (GMimeObject *object, GMimeStream *stream);
 static void mime_part_encode (GMimeObject *object, GMimeEncodingConstraint constraint);
 
@@ -112,8 +111,6 @@ g_mime_part_class_init (GMimePartClass *klass)
 	object_class->append_header = mime_part_append_header;
 	object_class->remove_header = mime_part_remove_header;
 	object_class->set_header = mime_part_set_header;
-	object_class->get_header = mime_part_get_header;
-	object_class->get_headers = mime_part_get_headers;
 	object_class->write_to_stream = mime_part_write_to_stream;
 	object_class->encode = mime_part_encode;
 	
@@ -162,23 +159,41 @@ static const char *content_headers[] = {
 };
 
 
+static void
+copy_atom (const char *src, char *dest, size_t n)
+{
+	register const char *inptr = src;
+	register char *outptr = dest;
+	char *outend = dest + n;
+	
+	while (is_lwsp (*inptr))
+		inptr++;
+	
+	while (is_atom (*inptr) && outptr < outend)
+		*outptr++ = *inptr++;
+	
+	*outptr = '\0';
+}
+
 static gboolean
 process_header (GMimeObject *object, const char *header, const char *value)
 {
 	GMimePart *mime_part = (GMimePart *) object;
-	char *text;
+	char encoding[32];
 	guint i;
 	
+	if (g_ascii_strncasecmp (header, "Content-", 8) != 0)
+		return FALSE;
+	
 	for (i = 0; i < G_N_ELEMENTS (content_headers); i++) {
-		if (!g_ascii_strcasecmp (content_headers[i], header))
+		if (!g_ascii_strcasecmp (content_headers[i] + 8, header + 8))
 			break;
 	}
 	
 	switch (i) {
 	case HEADER_CONTENT_TRANSFER_ENCODING:
-		text = g_mime_strdup_trim (value);
-		mime_part->encoding = g_mime_content_encoding_from_string (text);
-		g_free (text);
+		copy_atom (value, encoding, sizeof (encoding) - 1);
+		mime_part->encoding = g_mime_content_encoding_from_string (encoding);
 		break;
 	case HEADER_CONTENT_DESCRIPTION:
 		/* FIXME: we should decode this */
@@ -204,11 +219,6 @@ process_header (GMimeObject *object, const char *header, const char *value)
 static void
 mime_part_prepend_header (GMimeObject *object, const char *header, const char *value)
 {
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a mime part */
-	if (g_ascii_strncasecmp ("Content-", header, 8) != 0)
-		return;
-	
 	if (!process_header (object, header, value))
 		GMIME_OBJECT_CLASS (parent_class)->prepend_header (object, header, value);
 	else
@@ -218,11 +228,6 @@ mime_part_prepend_header (GMimeObject *object, const char *header, const char *v
 static void
 mime_part_append_header (GMimeObject *object, const char *header, const char *value)
 {
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a mime part */
-	if (g_ascii_strncasecmp ("Content-", header, 8) != 0)
-		return;
-	
 	if (!process_header (object, header, value))
 		GMIME_OBJECT_CLASS (parent_class)->append_header (object, header, value);
 	else
@@ -232,69 +237,48 @@ mime_part_append_header (GMimeObject *object, const char *header, const char *va
 static void
 mime_part_set_header (GMimeObject *object, const char *header, const char *value)
 {
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a mime part */
-	if (g_ascii_strncasecmp ("Content-", header, 8) != 0)
-		return;
-	
 	if (!process_header (object, header, value))
 		GMIME_OBJECT_CLASS (parent_class)->set_header (object, header, value);
 	else
 		g_mime_header_list_set (object->headers, header, value);
 }
 
-static const char *
-mime_part_get_header (GMimeObject *object, const char *header)
-{
-	/* Make sure that the header is a Content-* header, else it
-           doesn't belong on a mime part */
-	if (!g_ascii_strncasecmp ("Content-", header, 8))
-		return GMIME_OBJECT_CLASS (parent_class)->get_header (object, header);
-	else
-		return NULL;
-}
-
 static gboolean
 mime_part_remove_header (GMimeObject *object, const char *header)
 {
 	GMimePart *mime_part = (GMimePart *) object;
 	guint i;
 	
-	for (i = 0; i < G_N_ELEMENTS (content_headers); i++) {
-		if (!g_ascii_strcasecmp (content_headers[i], header))
+	if (!g_ascii_strncasecmp (header, "Content-", 8)) {
+		for (i = 0; i < G_N_ELEMENTS (content_headers); i++) {
+			if (!g_ascii_strcasecmp (content_headers[i] + 8, header + 8))
+				break;
+		}
+		
+		switch (i) {
+		case HEADER_CONTENT_TRANSFER_ENCODING:
+			mime_part->encoding = GMIME_CONTENT_ENCODING_DEFAULT;
 			break;
-	}
-	
-	switch (i) {
-	case HEADER_CONTENT_TRANSFER_ENCODING:
-		mime_part->encoding = GMIME_CONTENT_ENCODING_DEFAULT;
-		break;
-	case HEADER_CONTENT_DESCRIPTION:
-		/* FIXME: we should decode this */
-		g_free (mime_part->content_description);
-		mime_part->content_description = NULL;
-		break;
-	case HEADER_CONTENT_LOCATION:
-		g_free (mime_part->content_location);
-		mime_part->content_location = NULL;
-		break;
-	case HEADER_CONTENT_MD5:
-		g_free (mime_part->content_md5);
-		mime_part->content_md5 = NULL;
-		break;
-	default:
-		break;
+		case HEADER_CONTENT_DESCRIPTION:
+			g_free (mime_part->content_description);
+			mime_part->content_description = NULL;
+			break;
+		case HEADER_CONTENT_LOCATION:
+			g_free (mime_part->content_location);
+			mime_part->content_location = NULL;
+			break;
+		case HEADER_CONTENT_MD5:
+			g_free (mime_part->content_md5);
+			mime_part->content_md5 = NULL;
+			break;
+		default:
+			break;
+		}
 	}
 	
 	return GMIME_OBJECT_CLASS (parent_class)->remove_header (object, header);
 }
 
-static char *
-mime_part_get_headers (GMimeObject *object)
-{
-	return GMIME_OBJECT_CLASS (parent_class)->get_headers (object);
-}
-
 static ssize_t
 write_content (GMimePart *part, GMimeStream *stream)
 {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]