[gmime: 13/21] GMimeHeader::value is now the unfolded and decoded version



commit 9397272212b61553f1735b1cfc584112f7c85b67
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Sun Mar 26 07:04:50 2017 -0400

    GMimeHeader::value is now the unfolded and decoded version
    
    There is no longer any need to call g_mime_utils_header_decode_text()
    on the value returned by get_value() and no longer any need to
    call g_mime_utils_header_encode_text() when setting/appending a
    header.

 gmime/gmime-header.c          |  740 +++++++++++++++++++++++++++++++++--------
 gmime/gmime-header.h          |   43 ++-
 gmime/gmime-internal.h        |   16 +-
 gmime/gmime-message-partial.c |    5 +-
 gmime/gmime-message.c         |  451 +------------------------
 gmime/gmime-object.c          |  129 ++------
 gmime/gmime-object.h          |    6 +-
 gmime/gmime-parser.c          |   92 ++----
 gmime/gmime-part.c            |   20 +-
 tests/test-headers.c          |    8 +-
 tests/test-pgpmime.c          |    6 +-
 tests/test-smime.c            |    2 +-
 12 files changed, 708 insertions(+), 810 deletions(-)
---
diff --git a/gmime/gmime-header.c b/gmime/gmime-header.c
index d31adae..039e17b 100644
--- a/gmime/gmime-header.c
+++ b/gmime/gmime-header.c
@@ -27,7 +27,10 @@
 #include <ctype.h>
 
 #include "gmime-stream-filter.h"
+#include "gmime-table-private.h"
+#include "gmime-parse-utils.h"
 #include "gmime-stream-mem.h"
+#include "internet-address.h"
 #include "gmime-internal.h"
 #include "gmime-common.h"
 #include "gmime-header.h"
@@ -46,6 +49,32 @@
  **/
 
 
+static struct {
+       const char *name;
+       GMimeHeaderRawValueFormatter formatter;
+} formatters[] = {
+       { "Received",            g_mime_header_format_received            },
+       { "Sender",              g_mime_header_format_addrlist            },
+       { "From",                g_mime_header_format_addrlist            },
+       { "Reply-To",            g_mime_header_format_addrlist            },
+       { "To",                  g_mime_header_format_addrlist            },
+       { "Cc",                  g_mime_header_format_addrlist            },
+       { "Bcc",                 g_mime_header_format_addrlist            },
+       { "Message-Id",          g_mime_header_format_message_id          },
+       { "In-Reply-To",         g_mime_header_format_references          },
+       { "References",          g_mime_header_format_references          },
+       { "Resent-Sender",       g_mime_header_format_addrlist            },
+       { "Resent-From",         g_mime_header_format_addrlist            },
+       { "Resent-Reply-To",     g_mime_header_format_addrlist            },
+       { "Resent-To",           g_mime_header_format_addrlist            },
+       { "Resent-Cc",           g_mime_header_format_addrlist            },
+       { "Resent-Bcc",          g_mime_header_format_addrlist            },
+       { "Resent-Message-Id",   g_mime_header_format_message_id          },
+       { "Content-Type",        g_mime_header_format_content_type        },
+       { "Content-Disposition", g_mime_header_format_content_disposition },
+};
+
+
 static void g_mime_header_class_init (GMimeHeaderClass *klass);
 static void g_mime_header_init (GMimeHeader *header, GMimeHeaderClass *klass);
 static void g_mime_header_finalize (GObject *object);
@@ -91,6 +120,8 @@ static void
 g_mime_header_init (GMimeHeader *header, GMimeHeaderClass *klass)
 {
        header->changed = g_mime_event_new (header);
+       header->formatter = NULL;
+       header->options = NULL;
        header->raw_value = NULL;
        header->raw_name = NULL;
        header->value = NULL;
@@ -115,9 +146,11 @@ g_mime_header_finalize (GObject *object)
 
 /**
  * g_mime_header_new:
+ * @options: a #GMimeParserOptions
  * @name: header name
  * @value: header value
  * @raw_value: raw header value
+ * @charset: a charset
  * @offset: file/stream offset for the start of the header (or %-1 if unknown)
  *
  * Creates a new #GMimeHeader.
@@ -125,17 +158,33 @@ g_mime_header_finalize (GObject *object)
  * Returns: a new #GMimeHeader with the specified values.
  **/
 static GMimeHeader *
-g_mime_header_new (const char *name, const char *value, const char *raw_name, const char *raw_value, gint64 
offset)
+g_mime_header_new (GMimeParserOptions *options, const char *name, const char *value,
+                  const char *raw_name, const char *raw_value, const char *charset,
+                  gint64 offset)
 {
+       GMimeHeaderRawValueFormatter formatter;
        GMimeHeader *header;
+       guint i;
        
        header = g_object_newv (GMIME_TYPE_HEADER, 0, NULL);
        header->raw_value = raw_value ? g_strdup (raw_value) : NULL;
+       header->value = value ? g_strdup (value) : NULL;
        header->raw_name = g_strdup (raw_name);
-       header->value = g_strdup (value);
        header->name = g_strdup (name);
+       header->options = options;
        header->offset = offset;
        
+       formatter = g_mime_header_format_default;
+       for (i = 0; i < G_N_ELEMENTS (formatters); i++) {
+               if (!g_ascii_strcasecmp (formatters[i].name, name)) {
+                       formatter = header->formatter = formatters[i].formatter;
+                       break;
+               }
+       }
+       
+       if (!raw_value && value)
+               header->raw_value = formatter (header, NULL, header->value, charset);
+       
        return header;
 }
 
@@ -157,6 +206,37 @@ g_mime_header_get_name (GMimeHeader *header)
 }
 
 
+static char *
+unfold (const char *value)
+{
+       register const char *inptr = value;
+       const char *start, *inend;
+       char *str, *outptr;
+       
+       while (is_lwsp (*inptr))
+               inptr++;
+       
+       start = inptr;
+       while (*inptr) {
+               if (!is_lwsp (*inptr++))
+                       inend = inptr;
+       }
+       
+       outptr = str = g_malloc ((size_t) (inend - start) + 1);
+       inptr = start;
+       
+       while (inptr < inend) {
+               if (*inptr != '\r' && *inptr != '\n')
+                       *outptr++ = *inptr;
+               inptr++;
+       }
+       
+       *outptr = '\0';
+       
+       return str;
+}
+
+
 /**
  * g_mime_header_get_value:
  * @header: a #GMimeHeader
@@ -171,8 +251,16 @@ g_mime_header_get_name (GMimeHeader *header)
 const char *
 g_mime_header_get_value (GMimeHeader *header)
 {
+       char *buf;
+       
        g_return_val_if_fail (GMIME_IS_HEADER (header), NULL);
        
+       if (!header->value && header->raw_value) {
+               buf = unfold (header->raw_value);
+               header->value = g_mime_utils_header_decode_text (header->options, buf);
+               g_free (buf);
+       }
+       
        return header->value;
 }
 
@@ -180,24 +268,28 @@ g_mime_header_get_value (GMimeHeader *header)
 /**
  * g_mime_header_set_value:
  * @header: a #GMimeHeader
+ * @options: a #GMimeFormatOptions
  * @value: the new header value
+ * @charset: a charset
  *
  * Sets the header's value.
- *
- * Note: @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
  **/
 void
-g_mime_header_set_value (GMimeHeader *header, const char *value)
+g_mime_header_set_value (GMimeHeader *header, GMimeFormatOptions *options, const char *value, const char 
*charset)
 {
+       GMimeHeaderRawValueFormatter formatter;
+       char *buf;
+       
        g_return_if_fail (GMIME_IS_HEADER (header));
        g_return_if_fail (value != NULL);
        
+       formatter = header->formatter ? header->formatter : g_mime_header_format_default;
+       buf = g_mime_strdup_trim (value);
        g_free (header->raw_value);
-       header->raw_value = NULL;
-       
        g_free (header->value);
-       header->value = g_strdup (value);
+       
+       header->raw_value = formatter (header, options, buf, charset);
+       header->value = buf;
        
        g_mime_event_emit (header->changed, NULL);
 }
@@ -282,24 +374,9 @@ _g_mime_header_set_offset (GMimeHeader *header, gint64 offset)
        header->offset = offset;
 }
 
-static ssize_t
-default_writer (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-               const char *name, const char *value)
-{
-       ssize_t nwritten;
-       char *val;
-       
-       val = g_mime_utils_header_printf (options, format, "%s: %s\n", name, value);
-       nwritten = g_mime_stream_write_string (stream, val);
-       g_free (val);
-       
-       return nwritten;
-}
-
 
 /**
  * g_mime_header_write_to_stream:
- * @headers: the #GMimeHeaderList that contains @header
  * @header: a #GMimeHeader
  * @options: a #GMimeFormatOptions
  * @stream: a #GMimeStream
@@ -309,37 +386,453 @@ default_writer (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeSt
  * Returns: the number of bytes written, or %-1 on fail.
  **/
 ssize_t
-g_mime_header_write_to_stream (GMimeHeaderList *headers, GMimeHeader *header,
-                              GMimeFormatOptions *options, GMimeStream *stream)
+g_mime_header_write_to_stream (GMimeHeader *header, GMimeFormatOptions *options, GMimeStream *stream)
 {
        ssize_t nwritten, total = 0;
-       GMimeHeaderWriter writer;
        char *val;
        
-       g_return_val_if_fail (GMIME_IS_HEADER_LIST (headers), -1);
        g_return_val_if_fail (GMIME_IS_HEADER (header), -1);
        g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
        
-       if (header->raw_value) {
-               val = g_strdup_printf ("%s:%s", header->raw_name, header->raw_value);
-               nwritten = g_mime_stream_write_string (stream, val);
-               g_free (val);
+       if (!header->raw_value)
+               return 0;
+       
+       val = g_strdup_printf ("%s:%s", header->raw_name, header->raw_value);
+       nwritten = g_mime_stream_write_string (stream, val);
+       g_free (val);
+       
+       if (nwritten == -1)
+               return -1;
+       
+       total += nwritten;
+       
+       return total;
+}
+
+
+char *
+g_mime_header_format_content_disposition (GMimeHeader *header, GMimeFormatOptions *options, const char 
*value, const char *charset)
+{
+       GMimeContentDisposition *disposition;
+       GString *str;
+       guint n;
+       
+       str = g_string_new (header->raw_name);
+       g_string_append_c (str, ':');
+       n = str->len;
+       
+       g_string_append_c (str, ' ');
+       
+       disposition = g_mime_content_disposition_parse (header->options, value);
+       g_string_append (str, disposition->disposition);
+       
+       g_mime_param_list_encode (disposition->params, options, TRUE, str);
+       g_object_unref (disposition);
+       
+       memmove (str->str, str->str + n, (str->len - n) + 1);
+       
+       return g_string_free (str, FALSE);
+}
+
+
+char *
+g_mime_header_format_content_type (GMimeHeader *header, GMimeFormatOptions *options, const char *value, 
const char *charset)
+{
+       GMimeContentType *content_type;
+       GString *str;
+       guint n;
+       
+       str = g_string_new (header->raw_name);
+       g_string_append_c (str, ':');
+       n = str->len;
+       
+       content_type = g_mime_content_type_parse (header->options, value);
+       
+       g_string_append_c (str, ' ');
+       g_string_append (str, content_type->type ? content_type->type : "text");
+       g_string_append_c (str, '/');
+       g_string_append (str, content_type->subtype ? content_type->subtype : "plain");
+       
+       g_mime_param_list_encode (content_type->params, options, TRUE, str);
+       g_object_unref (content_type);
+       
+       memmove (str->str, str->str + n, (str->len - n) + 1);
+       
+       return g_string_free (str, FALSE);
+}
+
+
+char *
+g_mime_header_format_message_id (GMimeHeader *header, GMimeFormatOptions *options, const char *value, const 
char *charset)
+{
+       const char *newline = g_mime_format_options_get_newline (options);
+       
+       return g_strdup_printf (" %s%s", value, newline);
+}
+
+
+char *
+g_mime_header_format_references (GMimeHeader *header, GMimeFormatOptions *options, const char *value, const 
char *charset)
+{
+       GMimeReferences *references, *reference;
+       const char *newline;
+       guint cur, len, n;
+       GString *str;
+       
+       /* Note: we don't want to break in the middle of msgid tokens as
+          it seems to break a lot of clients (and servers) */
+       newline = g_mime_format_options_get_newline (options);
+       references = g_mime_references_decode (value);
+       str = g_string_new (header->raw_name);
+       g_string_append_c (str, ':');
+       cur = n = str->len;
+       
+       reference = references;
+       while (reference != NULL) {
+               len = strlen (reference->msgid);
+               if (cur > 1 && cur + len + 3 >= GMIME_FOLD_LEN) {
+                       g_string_append (str, newline);
+                       g_string_append_c (str, '\t');
+                       cur = 1;
+               } else {
+                       g_string_append_c (str, ' ');
+                       cur++;
+               }
                
-               if (nwritten == -1)
-                       return -1;
+               g_string_append_c (str, '<');
+               g_string_append_len (str, reference->msgid, len);
+               g_string_append_c (str, '>');
+               cur += len + 2;
                
-               total += nwritten;
-       } else if (header->value) {
-               if (!(writer = g_hash_table_lookup (headers->writers, header->name)))
-                       writer = default_writer;
+               reference = reference->next;
+       }
+       
+       g_mime_references_clear (&references);
+       
+       g_string_append (str, newline);
+       
+       memmove (str->str, str->str + n, (str->len - n) + 1);
+       
+       return g_string_free (str, FALSE);
+}
+
+
+char *
+g_mime_header_format_addrlist (GMimeHeader *header, GMimeFormatOptions *options, const char *value, const 
char *charset)
+{
+       InternetAddressList *addrlist;
+       const char *newline;
+       GString *str;
+       guint n;
+       
+       newline = g_mime_format_options_get_newline (options);
+       str = g_string_new (header->raw_name);
+       g_string_append_c (str, ':');
+       n = str->len;
+       
+       g_string_append_c (str, ' ');
+       
+       if (value && (addrlist = internet_address_list_parse (header->options, value))) {
+               internet_address_list_writer (addrlist, options, str);
+               g_object_unref (addrlist);
+       }
+       
+       g_string_append (str, newline);
+       
+       memmove (str->str, str->str + n, (str->len - n) + 1);
+       
+       return g_string_free (str, FALSE);
+}
+
+
+typedef void (* token_skip_t) (const char **in);
+
+struct _received_token {
+       char *token;
+       size_t len;
+       token_skip_t skip;
+};
+
+static void skip_cfws_atom (const char **in);
+static void skip_domain    (const char **in);
+static void skip_addr      (const char **in);
+static void skip_msgid     (const char **in);
+
+static struct _received_token received_tokens[] = {
+       { "from ", 5, skip_domain    },
+       { "by ",   3, skip_domain    },
+       { "via ",  4, skip_cfws_atom },
+       { "with ", 5, skip_cfws_atom },
+       { "id ",   3, skip_msgid     },
+       { "for ",  4, skip_addr      }
+};
+
+static void
+skip_cfws_atom (const char **in)
+{
+       skip_cfws (in);
+       skip_atom (in);
+}
+
+static void
+skip_domain_subliteral (const char **in)
+{
+       const char *inptr = *in;
+       
+       while (*inptr && *inptr != '.' && *inptr != ']') {
+               if (is_dtext (*inptr)) {
+                       inptr++;
+               } else if (is_lwsp (*inptr)) {
+                       skip_cfws (&inptr);
+               } else {
+                       break;
+               }
+       }
+       
+       *in = inptr;
+}
+
+static void
+skip_domain_literal (const char **in)
+{
+       const char *inptr = *in;
+       
+       skip_cfws (&inptr);
+       while (*inptr && *inptr != ']') {
+               skip_domain_subliteral (&inptr);
+               if (*inptr && *inptr != ']')
+                       inptr++;
+       }
+       
+       *in = inptr;
+}
+
+static void
+skip_domain (const char **in)
+{
+       const char *save, *inptr = *in;
+       
+       while (inptr && *inptr) {
+               skip_cfws (&inptr);
+               if (*inptr == '[') {
+                       /* domain literal */
+                       inptr++;
+                       skip_domain_literal (&inptr);
+                       if (*inptr == ']')
+                               inptr++;
+               } else {
+                       skip_atom (&inptr);
+               }
                
-               if ((nwritten = writer (headers->options, options, stream, header->name, header->value)) == 
-1)
-                       return -1;
+               save = inptr;
+               skip_cfws (&inptr);
+               if (*inptr != '.') {
+                       inptr = save;
+                       break;
+               }
                
-               total += nwritten;
+               inptr++;
        }
        
-       return total;
+       *in = inptr;
+}
+
+static void
+skip_addrspec (const char **in)
+{
+       const char *inptr = *in;
+       
+       skip_cfws (&inptr);
+       skip_word (&inptr);
+       skip_cfws (&inptr);
+       
+       while (*inptr == '.') {
+               inptr++;
+               skip_cfws (&inptr);
+               skip_word (&inptr);
+               skip_cfws (&inptr);
+       }
+       
+       if (*inptr == '@') {
+               inptr++;
+               skip_domain (&inptr);
+       }
+       
+       *in = inptr;
+}
+
+static void
+skip_addr (const char **in)
+{
+       const char *inptr = *in;
+       
+       skip_cfws (&inptr);
+       if (*inptr == '<') {
+               inptr++;
+               skip_addrspec (&inptr);
+               if (*inptr == '>')
+                       inptr++;
+       } else {
+               skip_addrspec (&inptr);
+       }
+       
+       *in = inptr;
+}
+
+static void
+skip_msgid (const char **in)
+{
+       const char *inptr = *in;
+       
+       skip_cfws (&inptr);
+       if (*inptr == '<') {
+               inptr++;
+               skip_addrspec (&inptr);
+               if (*inptr == '>')
+                       inptr++;
+       } else {
+               skip_atom (&inptr);
+       }
+       
+       *in = inptr;
+}
+
+struct _received_part {
+       struct _received_part *next;
+       const char *start;
+       size_t len;
+};
+
+
+
+char *
+g_mime_header_format_received (GMimeHeader *header, GMimeFormatOptions *options, const char *value, const 
char *charset)
+{
+       struct _received_part *parts, *part, *tail;
+       const char *inptr, *lwsp = NULL;
+       const char *newline;
+       guint len, n, i;
+       GString *str;
+       
+       newline = g_mime_format_options_get_newline (options);
+       
+       while (is_lwsp (*value))
+               value++;
+       
+       if (*value == '\0')
+               return g_strdup (newline);
+       
+       str = g_string_new (header->raw_name);
+       g_string_append_c (str, ':');
+       n = str->len;
+       
+       g_string_append_c (str, ' ');
+       len = str->len;
+       
+       tail = parts = part = g_alloca (sizeof (struct _received_part));
+       part->start = inptr = value;
+       part->next = NULL;
+       
+       while (*inptr) {
+               for (i = 0; i < G_N_ELEMENTS (received_tokens); i++) {
+                       if (!strncmp (inptr, received_tokens[i].token, received_tokens[i].len)) {
+                               if (inptr > part->start) {
+                                       g_assert (lwsp != NULL);
+                                       part->len = lwsp - part->start;
+                                       
+                                       part = g_alloca (sizeof (struct _received_part));
+                                       part->start = inptr;
+                                       part->next = NULL;
+                                       
+                                       tail->next = part;
+                                       tail = part;
+                               }
+                               
+                               inptr += received_tokens[i].len;
+                               received_tokens[i].skip (&inptr);
+                               
+                               lwsp = inptr;
+                               while (is_lwsp (*inptr))
+                                       inptr++;
+                               
+                               if (*inptr == ';') {
+                                       inptr++;
+                                       
+                                       part->len = inptr - part->start;
+                                       
+                                       lwsp = inptr;
+                                       while (is_lwsp (*inptr))
+                                               inptr++;
+                                       
+                                       part = g_alloca (sizeof (struct _received_part));
+                                       part->start = inptr;
+                                       part->next = NULL;
+                                       
+                                       tail->next = part;
+                                       tail = part;
+                               }
+                               
+                               break;
+                       }
+               }
+               
+               if (i == G_N_ELEMENTS (received_tokens)) {
+                       while (*inptr && !is_lwsp (*inptr))
+                               inptr++;
+                       
+                       lwsp = inptr;
+                       while (is_lwsp (*inptr))
+                               inptr++;
+               }
+               
+               if (*inptr == '(') {
+                       skip_comment (&inptr);
+                       
+                       lwsp = inptr;
+                       while (is_lwsp (*inptr))
+                               inptr++;
+               }
+       }
+       
+       part->len = lwsp - part->start;
+       
+       lwsp = NULL;
+       part = parts;
+       do {
+               len += lwsp ? part->start - lwsp : 0;
+               if (len + part->len > GMIME_FOLD_LEN && part != parts) {
+                       g_string_append (str, newline);
+                       g_string_append_c (str, '\t');
+                       len = 1;
+               } else if (lwsp) {
+                       g_string_append_len (str, lwsp, (size_t) (part->start - lwsp));
+               }
+               
+               g_string_append_len (str, part->start, part->len);
+               lwsp = part->start + part->len;
+               len += part->len;
+               
+               part = part->next;
+       } while (part != NULL);
+       
+       g_string_append (str, newline);
+       
+       memmove (str->str, str->str + n, (str->len - n) + 1);
+       
+       return g_string_free (str, FALSE);
+}
+
+
+char *
+g_mime_header_format_default (GMimeHeader *header, GMimeFormatOptions *options, const char *value, const 
char *charset)
+{
+       char *encoded, *raw_value;
+       
+       encoded = g_mime_utils_header_encode_text (options, value, charset);
+       raw_value = _g_mime_utils_unstructured_header_fold (header->options, options, header->raw_name, 
encoded);
+       g_free (encoded);
+       
+       return raw_value;
 }
 
 
@@ -401,9 +894,6 @@ g_mime_header_list_class_init (GMimeHeaderListClass *klass)
 static void
 g_mime_header_list_init (GMimeHeaderList *list, GMimeHeaderListClass *klass)
 {
-       list->writers = g_hash_table_new_full (g_mime_strcase_hash,
-                                              g_mime_strcase_equal,
-                                              g_free, NULL);
        list->hash = g_hash_table_new (g_mime_strcase_hash,
                                       g_mime_strcase_equal);
        list->changed = g_mime_event_new (list);
@@ -426,7 +916,6 @@ g_mime_header_list_finalize (GObject *object)
        g_ptr_array_free (headers->array, TRUE);
        
        g_mime_parser_options_free (headers->options);
-       g_hash_table_destroy (headers->writers);
        g_hash_table_destroy (headers->hash);
        g_mime_event_free (headers->changed);
        
@@ -543,16 +1032,29 @@ g_mime_header_list_contains (GMimeHeaderList *headers, const char *name)
 }
 
 
+/**
+ * g_mime_header_list_prepend:
+ * @headers: a #GMimeHeaderList
+ * @name: header name
+ * @value: header value
+ * @charset: a charset
+ *
+ * Prepends a header. If @value is %NULL, a space will be set aside
+ * for it (useful for setting the order of headers before values can
+ * be obtained for them) otherwise the header will be unset.
+ **/
 void
-_g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value,
-                            const char *raw_name, const char *raw_value, gint64 offset)
+g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value, const char 
*charset)
 {
        GMimeHeaderListChangedEventArgs args;
        unsigned char *dest, *src;
        GMimeHeader *header;
        guint n;
        
-       header = g_mime_header_new (name, value, raw_name, raw_value, offset);
+       g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
+       g_return_if_fail (name != NULL);
+       
+       header = g_mime_header_new (headers->options, name, value, name, NULL, charset, -1);
        g_mime_event_add (header->changed, (GMimeEventCallback) header_changed, headers);
        g_hash_table_replace (headers->hash, header->name, header);
        
@@ -576,37 +1078,14 @@ _g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const c
 }
 
 
-/**
- * g_mime_header_list_prepend:
- * @headers: a #GMimeHeaderList
- * @name: header name
- * @value: header value
- *
- * Prepends a header. If @value is %NULL, a space will be set aside
- * for it (useful for setting the order of headers before values can
- * be obtained for them) otherwise the header will be unset.
- *
- * Note: @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
- **/
 void
-g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value)
-{
-       g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
-       g_return_if_fail (name != NULL);
-       
-       _g_mime_header_list_prepend (headers, name, value, name, NULL, -1);
-}
-
-
-void
-_g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value,
-                           const char *raw_name, const char *raw_value, gint64 offset)
+_g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *raw_name,
+                           const char *raw_value, gint64 offset)
 {
        GMimeHeaderListChangedEventArgs args;
        GMimeHeader *header;
        
-       header = g_mime_header_new (name, value, raw_name, raw_value, offset);
+       header = g_mime_header_new (headers->options, name, NULL, raw_name, raw_value, NULL, offset);
        g_mime_event_add (header->changed, (GMimeEventCallback) header_changed, headers);
        g_ptr_array_add (headers->array, header);
        
@@ -625,21 +1104,32 @@ _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const ch
  * @headers: a #GMimeHeaderList
  * @name: header name
  * @value: header value
+ * @charset: a charset
  *
  * Appends a header. If @value is %NULL, a space will be set aside for it
  * (useful for setting the order of headers before values can be
  * obtained for them) otherwise the header will be unset.
- *
- * Note: @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
  **/
 void
-g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value)
+g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value, const char 
*charset)
 {
+       GMimeHeaderListChangedEventArgs args;
+       GMimeHeader *header;
+       
        g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
        g_return_if_fail (name != NULL);
        
-       _g_mime_header_list_append (headers, name, value, name, NULL, -1);
+       header = g_mime_header_new (headers->options, name, value, name, NULL, charset, -1);
+       g_mime_event_add (header->changed, (GMimeEventCallback) header_changed, headers);
+       g_ptr_array_add (headers->array, header);
+       
+       if (!g_hash_table_lookup (headers->hash, name))
+               g_hash_table_insert (headers->hash, header->name, header);
+       
+       args.action = GMIME_HEADER_LIST_CHANGED_ACTION_ADDED;
+       args.header = header;
+       
+       g_mime_event_emit (headers->changed, &args);
 }
 
 
@@ -664,25 +1154,34 @@ g_mime_header_list_get_header (GMimeHeaderList *headers, const char *name)
 }
 
 
+/**
+ * g_mime_header_list_set:
+ * @headers: a #GMimeHeaderList
+ * @name: header name
+ * @value: header value
+ * @charset: a charset
+ *
+ * Set the value of the specified header. If @value is %NULL and the
+ * header, @name, had not been previously set, a space will be set
+ * aside for it (useful for setting the order of headers before values
+ * can be obtained for them) otherwise the header will be unset.
+ *
+ * Note: If there are multiple headers with the specified field name,
+ * the first instance of the header will be replaced and further
+ * instances will be removed.
+ **/
 void
-_g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value,
-                        const char *raw_name, const char *raw_value, gint64 offset)
+g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value, const char *charset)
 {
        GMimeHeaderListChangedEventArgs args;
        GMimeHeader *header, *hdr;
        guint i;
        
+       g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
+       g_return_if_fail (name != NULL);
+       
        if ((header = g_hash_table_lookup (headers->hash, name))) {
-               g_free (header->raw_value);
-               header->raw_value = raw_value ? g_strdup (raw_value) : NULL;
-               
-               g_free (header->raw_name);
-               header->raw_name = g_strdup (raw_name);
-               
-               g_free (header->value);
-               header->value = g_strdup (value);
-               
-               header->offset = offset;
+               g_mime_header_set_value (header, NULL, value, charset);
                
                for (i = headers->array->len - 1; i > 0; i--) {
                        hdr = (GMimeHeader *) headers->array->pdata[i];
@@ -703,40 +1202,12 @@ _g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char
                
                g_mime_event_emit (headers->changed, &args);
        } else {
-               _g_mime_header_list_append (headers, name, value, raw_name, raw_value, offset);
+               g_mime_header_list_append (headers, name, value, charset);
        }
 }
 
 
 /**
- * g_mime_header_list_set:
- * @headers: a #GMimeHeaderList
- * @name: header name
- * @value: header value
- *
- * Set the value of the specified header. If @value is %NULL and the
- * header, @name, had not been previously set, a space will be set
- * aside for it (useful for setting the order of headers before values
- * can be obtained for them) otherwise the header will be unset.
- *
- * Note: If there are multiple headers with the specified field name,
- * the first instance of the header will be replaced and further
- * instances will be removed.
- *
- * Additionally, @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
- **/
-void
-g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value)
-{
-       g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
-       g_return_if_fail (name != NULL);
-       
-       _g_mime_header_list_set (headers, name, value, name, NULL, -1);
-}
-
-
-/**
  * g_mime_header_list_get_header_at:
  * @headers: a #GMimeHeaderList
  * @index: the 0-based index of the header
@@ -892,7 +1363,7 @@ g_mime_header_list_write_to_stream (GMimeHeaderList *headers, GMimeFormatOptions
                header = (GMimeHeader *) headers->array->pdata[i];
                
                if (!g_mime_format_options_is_hidden_header (options, header->name)) {
-                       if ((nwritten = g_mime_header_write_to_stream (headers, header, options, filtered)) 
== -1)
+                       if ((nwritten = g_mime_header_write_to_stream (header, options, filtered)) == -1)
                                return -1;
                        
                        total += nwritten;
@@ -937,28 +1408,3 @@ g_mime_header_list_to_string (GMimeHeaderList *headers, GMimeFormatOptions *opti
        
        return str;
 }
-
-
-/**
- * g_mime_header_list_register_writer:
- * @headers: a #GMimeHeaderList
- * @name: header name
- * @writer: writer function
- *
- * Changes the function used to write @name headers to @writer (or the
- * default if @writer is %NULL). This is useful if you want to change
- * the default header folding style for a particular header.
- **/
-void
-g_mime_header_list_register_writer (GMimeHeaderList *headers, const char *name, GMimeHeaderWriter writer)
-{
-       gpointer okey, oval;
-       
-       g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
-       g_return_if_fail (name != NULL);
-       
-       g_hash_table_remove (headers->writers, name);
-       
-       if (writer)
-               g_hash_table_insert (headers->writers, g_strdup (name), writer);
-}
diff --git a/gmime/gmime-header.h b/gmime/gmime-header.h
index 0a01596..4e56008 100644
--- a/gmime/gmime-header.h
+++ b/gmime/gmime-header.h
@@ -51,20 +51,26 @@ typedef struct _GMimeHeaderListClass GMimeHeaderListClass;
 
 
 /**
- * GMimeHeaderWriter:
- * @options: The #GMimeParserOptions
- * @format: The #GMimeFormatOptions
- * @stream: The output stream.
- * @name: The field name.
- * @value: The field value.
+ * GMimeHeaderRawValueFormatter:
+ * @header: a #GMimeHeader
+ * @options: a #GMimeFormatOptions
+ * @value: an unencoded header value
+ * @charset: a charset
  *
- * Function signature for the callback to
- * g_mime_header_list_register_writer().
+ * Function callback for encoding and formatting a header value.
  *
- * Returns: the number of bytes written or %-1 on error.
+ * Returns: the encoded and formatted raw header value.
  **/
-typedef ssize_t (* GMimeHeaderWriter) (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream 
*stream,
-                                      const char *name, const char *value);
+typedef char * (* GMimeHeaderRawValueFormatter) (GMimeHeader *header, GMimeFormatOptions *options,
+                                                const char *value, const char *charset);
+
+char *g_mime_header_format_content_disposition (GMimeHeader *header, GMimeFormatOptions *options, const char 
*value, const char *charset);
+char *g_mime_header_format_content_type (GMimeHeader *header, GMimeFormatOptions *options, const char 
*value, const char *charset);
+char *g_mime_header_format_message_id (GMimeHeader *header, GMimeFormatOptions *options, const char *value, 
const char *charset);
+char *g_mime_header_format_references (GMimeHeader *header, GMimeFormatOptions *options, const char *value, 
const char *charset);
+char *g_mime_header_format_addrlist (GMimeHeader *header, GMimeFormatOptions *options, const char *value, 
const char *charset);
+char *g_mime_header_format_received (GMimeHeader *header, GMimeFormatOptions *options, const char *value, 
const char *charset);
+char *g_mime_header_format_default (GMimeHeader *header, GMimeFormatOptions *options, const char *value, 
const char *charset);
 
 
 /**
@@ -80,6 +86,8 @@ struct _GMimeHeader {
        char *name, *value;
        
        /* < private > */
+       GMimeHeaderRawValueFormatter formatter;
+       GMimeParserOptions *options;
        gpointer changed;
        char *raw_value;
        char *raw_name;
@@ -98,14 +106,13 @@ const char *g_mime_header_get_name (GMimeHeader *header);
 const char *g_mime_header_get_raw_name (GMimeHeader *header);
 
 const char *g_mime_header_get_value (GMimeHeader *header);
-void g_mime_header_set_value (GMimeHeader *header, const char *value);
+void g_mime_header_set_value (GMimeHeader *header, GMimeFormatOptions *options, const char *value, const 
char *charset);
 
 const char *g_mime_header_get_raw_value (GMimeHeader *header);
 
 gint64 g_mime_header_get_offset (GMimeHeader *header);
 
-ssize_t g_mime_header_write_to_stream (GMimeHeaderList *headers, GMimeHeader *header,
-                                      GMimeFormatOptions *options, GMimeStream *stream);
+ssize_t g_mime_header_write_to_stream (GMimeHeader *header, GMimeFormatOptions *options, GMimeStream 
*stream);
 
 
 /**
@@ -118,7 +125,6 @@ struct _GMimeHeaderList {
        
        /* < private > */
        GMimeParserOptions *options;
-       GHashTable *writers;
        gpointer changed;
        GHashTable *hash;
        GPtrArray *array;
@@ -137,15 +143,14 @@ GMimeHeaderList *g_mime_header_list_new (GMimeParserOptions *options);
 void g_mime_header_list_clear (GMimeHeaderList *headers);
 int g_mime_header_list_get_count (GMimeHeaderList *headers);
 gboolean g_mime_header_list_contains (GMimeHeaderList *headers, const char *name);
-void g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value);
-void g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value);
-void g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value);
+void g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value, const char 
*charset);
+void g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value, const char 
*charset);
+void g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value, const char 
*charset);
 GMimeHeader *g_mime_header_list_get_header (GMimeHeaderList *headers, const char *name);
 GMimeHeader *g_mime_header_list_get_header_at (GMimeHeaderList *headers, int index);
 gboolean g_mime_header_list_remove (GMimeHeaderList *headers, const char *name);
 void g_mime_header_list_remove_at (GMimeHeaderList *headers, int index);
 
-void g_mime_header_list_register_writer (GMimeHeaderList *headers, const char *name, GMimeHeaderWriter 
writer);
 ssize_t g_mime_header_list_write_to_stream (GMimeHeaderList *headers, GMimeFormatOptions *options, 
GMimeStream *stream);
 char *g_mime_header_list_to_string (GMimeHeaderList *headers, GMimeFormatOptions *options);
 
diff --git a/gmime/gmime-internal.h b/gmime/gmime-internal.h
index 031687e..ab2373a 100644
--- a/gmime/gmime-internal.h
+++ b/gmime/gmime-internal.h
@@ -59,23 +59,15 @@ G_GNUC_INTERNAL void _g_mime_header_set_offset (GMimeHeader *header, gint64 offs
 /* GMimeHeaderList */
 G_GNUC_INTERNAL GMimeParserOptions *_g_mime_header_list_get_options (GMimeHeaderList *headers);
 G_GNUC_INTERNAL void _g_mime_header_list_set_options (GMimeHeaderList *headers, GMimeParserOptions *options);
-G_GNUC_INTERNAL void _g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char 
*value,
-                                                 const char *raw_name, const char *raw_value, gint64 offset);
-G_GNUC_INTERNAL void _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char 
*value,
-                                                const char *raw_name, const char *raw_value, gint64 offset);
-G_GNUC_INTERNAL void _g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value,
-                                             const char *raw_name, const char *raw_value, gint64 offset);
+G_GNUC_INTERNAL void _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char 
*raw_name,
+                                                const char *raw_value, gint64 offset);
 
 /* GMimeObject */
 G_GNUC_INTERNAL void _g_mime_object_block_header_list_changed (GMimeObject *object);
 G_GNUC_INTERNAL void _g_mime_object_unblock_header_list_changed (GMimeObject *object);
 G_GNUC_INTERNAL void _g_mime_object_set_content_type (GMimeObject *object, GMimeContentType *content_type);
-G_GNUC_INTERNAL void _g_mime_object_prepend_header (GMimeObject *object, const char *name, const char *value,
-                                                   const char *raw_name, const char *raw_value, gint64 
offset);
-G_GNUC_INTERNAL void _g_mime_object_append_header (GMimeObject *object, const char *name, const char *value,
-                                                  const char *raw_name, const char *raw_value, gint64 
offset);
-G_GNUC_INTERNAL void _g_mime_object_set_header (GMimeObject *object, const char *name, const char *value,
-                                               const char *raw_name, const char *raw_value, gint64 offset);
+G_GNUC_INTERNAL void _g_mime_object_append_header (GMimeObject *object, const char *name, const char 
*raw_name,
+                                                  const char *raw_value, gint64 offset);
 
 /* utils */
 G_GNUC_INTERNAL char *_g_mime_utils_unstructured_header_fold (GMimeParserOptions *options, 
GMimeFormatOptions *format,
diff --git a/gmime/gmime-message-partial.c b/gmime/gmime-message-partial.c
index 62a94ab..26dd17c 100644
--- a/gmime/gmime-message-partial.c
+++ b/gmime/gmime-message-partial.c
@@ -321,7 +321,7 @@ g_mime_message_partial_reconstruct_message (GMimeMessagePartial **partials, size
 static GMimeMessage *
 message_partial_message_new (GMimeMessage *base)
 {
-       const char *name, *value, *raw_name, *raw_value;
+       const char *name, *raw_name, *raw_value;
        GMimeHeaderList *headers;
        GMimeMessage *message;
        GMimeHeader *header;
@@ -339,10 +339,9 @@ message_partial_message_new (GMimeMessage *base)
                raw_value = g_mime_header_get_raw_value (header);
                raw_name = g_mime_header_get_raw_name (header);
                offset = g_mime_header_get_offset (header);
-               value = g_mime_header_get_value (header);
                name = g_mime_header_get_name (header);
                
-               _g_mime_object_append_header ((GMimeObject *) message, name, value, raw_name, raw_value, 
offset);
+               _g_mime_object_append_header ((GMimeObject *) message, name, raw_name, raw_value, offset);
        }
        
        return message;
diff --git a/gmime/gmime-message.c b/gmime/gmime-message.c
index 3bad84d..ad6f7e0 100644
--- a/gmime/gmime-message.c
+++ b/gmime/gmime-message.c
@@ -65,20 +65,6 @@ static ssize_t message_write_to_stream (GMimeObject *object, GMimeFormatOptions
                                        gboolean content_only, GMimeStream *stream);
 static void message_encode (GMimeObject *object, GMimeEncodingConstraint constraint);
 
-/*static ssize_t write_structured (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream 
*stream,
-  const char *name, const char *value);*/
-static ssize_t write_references (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream 
*stream,
-                                const char *name, const char *value);
-static ssize_t write_addrspec (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-                              const char *name, const char *value);
-static ssize_t write_received (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-                              const char *name, const char *value);
-static ssize_t write_subject (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-                             const char *name, const char *value);
-static ssize_t write_msgid (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-                           const char *name, const char *value);
-
-
 static void sender_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
 static void from_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
 static void reply_to_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
@@ -219,25 +205,6 @@ g_mime_message_init (GMimeMessage *message, GMimeMessageClass *klass)
                message->addrlists[i] = internet_address_list_new ();
                connect_changed_event (message, i);
        }
-       
-       g_mime_header_list_register_writer (headers, "Reply-To", write_addrspec);
-       g_mime_header_list_register_writer (headers, "Sender", write_addrspec);
-       g_mime_header_list_register_writer (headers, "From", write_addrspec);
-       g_mime_header_list_register_writer (headers, "To", write_addrspec);
-       g_mime_header_list_register_writer (headers, "Cc", write_addrspec);
-       g_mime_header_list_register_writer (headers, "Bcc", write_addrspec);
-       
-       g_mime_header_list_register_writer (headers, "Resent-Reply-To", write_addrspec);
-       g_mime_header_list_register_writer (headers, "Resent-Sender", write_addrspec);
-       g_mime_header_list_register_writer (headers, "Resent-From", write_addrspec);
-       g_mime_header_list_register_writer (headers, "Resent-To", write_addrspec);
-       g_mime_header_list_register_writer (headers, "Resent-Cc", write_addrspec);
-       g_mime_header_list_register_writer (headers, "Resent-Bcc", write_addrspec);
-       
-       g_mime_header_list_register_writer (headers, "Subject", write_subject);
-       g_mime_header_list_register_writer (headers, "Received", write_received);
-       g_mime_header_list_register_writer (headers, "Message-Id", write_msgid);
-       g_mime_header_list_register_writer (headers, "References", write_references);
 }
 
 static void
@@ -264,386 +231,6 @@ g_mime_message_finalize (GObject *object)
 }
 
 
-typedef void (* token_skip_t) (const char **in);
-
-struct _received_token {
-       char *token;
-       size_t len;
-       token_skip_t skip;
-};
-
-static void skip_cfws_atom (const char **in);
-static void skip_domain    (const char **in);
-static void skip_addr      (const char **in);
-static void skip_msgid     (const char **in);
-
-static struct _received_token received_tokens[] = {
-       { "from ", 5, skip_domain    },
-       { "by ",   3, skip_domain    },
-       { "via ",  4, skip_cfws_atom },
-       { "with ", 5, skip_cfws_atom },
-       { "id ",   3, skip_msgid     },
-       { "for ",  4, skip_addr      }
-};
-
-static void
-skip_cfws_atom (const char **in)
-{
-       skip_cfws (in);
-       skip_atom (in);
-}
-
-static void
-skip_domain_subliteral (const char **in)
-{
-       const char *inptr = *in;
-       
-       while (*inptr && *inptr != '.' && *inptr != ']') {
-               if (is_dtext (*inptr)) {
-                       inptr++;
-               } else if (is_lwsp (*inptr)) {
-                       skip_cfws (&inptr);
-               } else {
-                       break;
-               }
-       }
-       
-       *in = inptr;
-}
-
-static void
-skip_domain_literal (const char **in)
-{
-       const char *inptr = *in;
-       
-       skip_cfws (&inptr);
-       while (*inptr && *inptr != ']') {
-               skip_domain_subliteral (&inptr);
-               if (*inptr && *inptr != ']')
-                       inptr++;
-       }
-       
-       *in = inptr;
-}
-
-static void
-skip_domain (const char **in)
-{
-       const char *save, *inptr = *in;
-       
-       while (inptr && *inptr) {
-               skip_cfws (&inptr);
-               if (*inptr == '[') {
-                       /* domain literal */
-                       inptr++;
-                       skip_domain_literal (&inptr);
-                       if (*inptr == ']')
-                               inptr++;
-               } else {
-                       skip_atom (&inptr);
-               }
-               
-               save = inptr;
-               skip_cfws (&inptr);
-               if (*inptr != '.') {
-                       inptr = save;
-                       break;
-               }
-               
-               inptr++;
-       }
-       
-       *in = inptr;
-}
-
-static void
-skip_addrspec (const char **in)
-{
-       const char *inptr = *in;
-       
-       skip_cfws (&inptr);
-       skip_word (&inptr);
-       skip_cfws (&inptr);
-       
-       while (*inptr == '.') {
-               inptr++;
-               skip_cfws (&inptr);
-               skip_word (&inptr);
-               skip_cfws (&inptr);
-       }
-       
-       if (*inptr == '@') {
-               inptr++;
-               skip_domain (&inptr);
-       }
-       
-       *in = inptr;
-}
-
-static void
-skip_addr (const char **in)
-{
-       const char *inptr = *in;
-       
-       skip_cfws (&inptr);
-       if (*inptr == '<') {
-               inptr++;
-               skip_addrspec (&inptr);
-               if (*inptr == '>')
-                       inptr++;
-       } else {
-               skip_addrspec (&inptr);
-       }
-       
-       *in = inptr;
-}
-
-static void
-skip_msgid (const char **in)
-{
-       const char *inptr = *in;
-       
-       skip_cfws (&inptr);
-       if (*inptr == '<') {
-               inptr++;
-               skip_addrspec (&inptr);
-               if (*inptr == '>')
-                       inptr++;
-       } else {
-               skip_atom (&inptr);
-       }
-       
-       *in = inptr;
-}
-
-
-struct _received_part {
-       struct _received_part *next;
-       const char *start;
-       size_t len;
-};
-
-static ssize_t
-write_received (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-               const char *name, const char *value)
-{
-       struct _received_part *parts, *part, *tail;
-       const char *inptr, *lwsp = NULL;
-       ssize_t nwritten;
-       GString *str;
-       size_t len;
-       guint i;
-       
-       while (is_lwsp (*value))
-               value++;
-       
-       if (*value == '\0')
-               return 0;
-       
-       str = g_string_new (name);
-       g_string_append_len (str, ": ", 2);
-       len = 10;
-       
-       tail = parts = part = g_alloca (sizeof (struct _received_part));
-       part->start = inptr = value;
-       part->next = NULL;
-       
-       while (*inptr) {
-               for (i = 0; i < G_N_ELEMENTS (received_tokens); i++) {
-                       if (!strncmp (inptr, received_tokens[i].token, received_tokens[i].len)) {
-                               if (inptr > part->start) {
-                                       g_assert (lwsp != NULL);
-                                       part->len = lwsp - part->start;
-                                       
-                                       part = g_alloca (sizeof (struct _received_part));
-                                       part->start = inptr;
-                                       part->next = NULL;
-                                       
-                                       tail->next = part;
-                                       tail = part;
-                               }
-                               
-                               inptr += received_tokens[i].len;
-                               received_tokens[i].skip (&inptr);
-                               
-                               lwsp = inptr;
-                               while (is_lwsp (*inptr))
-                                       inptr++;
-                               
-                               if (*inptr == ';') {
-                                       inptr++;
-                                       
-                                       part->len = inptr - part->start;
-                                       
-                                       lwsp = inptr;
-                                       while (is_lwsp (*inptr))
-                                               inptr++;
-                                       
-                                       part = g_alloca (sizeof (struct _received_part));
-                                       part->start = inptr;
-                                       part->next = NULL;
-                                       
-                                       tail->next = part;
-                                       tail = part;
-                               }
-                               
-                               break;
-                       }
-               }
-               
-               if (i == G_N_ELEMENTS (received_tokens)) {
-                       while (*inptr && !is_lwsp (*inptr))
-                               inptr++;
-                       
-                       lwsp = inptr;
-                       while (is_lwsp (*inptr))
-                               inptr++;
-               }
-               
-               if (*inptr == '(') {
-                       skip_comment (&inptr);
-                       
-                       lwsp = inptr;
-                       while (is_lwsp (*inptr))
-                               inptr++;
-               }
-       }
-       
-       part->len = lwsp - part->start;
-       
-       lwsp = NULL;
-       part = parts;
-       do {
-               len += lwsp ? part->start - lwsp : 0;
-               if (len + part->len > GMIME_FOLD_LEN && part != parts) {
-                       g_string_append (str, "\n\t");
-                       len = 1;
-               } else if (lwsp) {
-                       g_string_append_len (str, lwsp, (size_t) (part->start - lwsp));
-               }
-               
-               g_string_append_len (str, part->start, part->len);
-               lwsp = part->start + part->len;
-               len += part->len;
-               
-               part = part->next;
-       } while (part != NULL);
-       
-       g_string_append_c (str, '\n');
-       
-       nwritten = g_mime_stream_write (stream, str->str, str->len);
-       g_string_free (str, TRUE);
-       
-       return nwritten;
-}
-
-static ssize_t
-write_subject (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-              const char *name, const char *value)
-{
-       char *folded;
-       ssize_t n;
-       
-       folded = _g_mime_utils_unstructured_header_fold (options, format, name, value);
-       n = g_mime_stream_write_string (stream, folded);
-       g_free (folded);
-       
-       return n;
-}
-
-static ssize_t
-write_msgid (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-            const char *name, const char *value)
-{
-       /* Note: we don't want to wrap the Message-Id header - seems to
-          break a lot of clients (and servers) */
-       return g_mime_stream_printf (stream, "%s: %s\n", name, value);
-}
-
-static ssize_t
-write_references (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-                 const char *name, const char *value)
-{
-       GMimeReferences *references, *reference;
-       ssize_t nwritten;
-       GString *folded;
-       size_t len, n;
-       
-       /* Note: we don't want to break in the middle of msgid tokens as
-          it seems to break a lot of clients (and servers) */
-       references = g_mime_references_decode (value);
-       folded = g_string_new (name);
-       g_string_append_c (folded, ':');
-       len = folded->len;
-       
-       reference = references;
-       while (reference != NULL) {
-               n = strlen (reference->msgid);
-               if (len > 1 && len + n + 3 >= GMIME_FOLD_LEN) {
-                       g_string_append_len (folded, "\n\t", 2);
-                       len = 1;
-               } else {
-                       g_string_append_c (folded, ' ');
-                       len++;
-               }
-               
-               g_string_append_c (folded, '<');
-               g_string_append_len (folded, reference->msgid, n);
-               g_string_append_c (folded, '>');
-               len += n + 2;
-               
-               reference = reference->next;
-       }
-       
-       g_mime_references_clear (&references);
-       
-       g_string_append_len (folded, "\n", 1);
-       nwritten = g_mime_stream_write (stream, folded->str, folded->len);
-       g_string_free (folded, TRUE);
-       
-       return nwritten;
-}
-
-#if 0
-static ssize_t
-write_structured (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-                 const char *name, const char *value)
-{
-       char *folded;
-       ssize_t n;
-       
-       folded = _g_mime_utils_structured_header_fold (options, format, name, value);
-       n = g_mime_stream_write_string (stream, folded);
-       g_free (folded);
-       
-       return n;
-}
-#endif
-
-static ssize_t
-write_addrspec (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-               const char *name, const char *value)
-{
-       InternetAddressList *addrlist;
-       GString *str;
-       ssize_t n;
-       
-       str = g_string_new (name);
-       g_string_append (str, ": ");
-       
-       if (value && (addrlist = internet_address_list_parse (options, value))) {
-               internet_address_list_writer (addrlist, format, str);
-               g_object_unref (addrlist);
-       }
-       
-       g_string_append_c (str, '\n');
-       
-       n = g_mime_stream_write (stream, str->str, str->len);
-       g_string_free (str, TRUE);
-       
-       return n;
-}
-
 enum {
        HEADER_SENDER,
        HEADER_FROM,
@@ -694,7 +281,7 @@ message_update_addresses (GMimeMessage *message, GMimeParserOptions *options, GM
                if (g_ascii_strcasecmp (address_types[type].name, name) != 0)
                        continue;
                
-               if ((value = g_mime_header_get_value (header))) {
+               if ((value = g_mime_header_get_raw_value (header))) {
                        if ((list = internet_address_list_parse (options, value))) {
                                internet_address_list_append (addrlist, list);
                                g_object_unref (list);
@@ -745,7 +332,7 @@ process_header (GMimeObject *object, GMimeHeader *header)
                g_free (message->subject);
                
                if ((value = g_mime_header_get_value (header)))
-                       message->subject = g_mime_utils_header_decode_text (options, value);
+                       message->subject = g_strdup (value);
                else
                        message->subject = NULL;
                break;
@@ -884,7 +471,7 @@ write_headers_to_stream (GMimeObject *object, GMimeFormatOptions *options, GMime
                        
                        if (offset >= 0 && offset < body_offset) {
                                if (!g_mime_format_options_is_hidden_header (options, header->name)) {
-                                       if ((nwritten = g_mime_header_write_to_stream (object->headers, 
header, options, stream)) == -1)
+                                       if ((nwritten = g_mime_header_write_to_stream (header, options, 
stream)) == -1)
                                                return -1;
                                        
                                        total += nwritten;
@@ -893,7 +480,7 @@ write_headers_to_stream (GMimeObject *object, GMimeFormatOptions *options, GMime
                                index++;
                        } else {
                                if (!g_mime_format_options_is_hidden_header (options, header->name)) {
-                                       if ((nwritten = g_mime_header_write_to_stream (mime_part->headers, 
body_header, options, stream)) == -1)
+                                       if ((nwritten = g_mime_header_write_to_stream (body_header, options, 
stream)) == -1)
                                                return -1;
                                        
                                        total += nwritten;
@@ -907,7 +494,7 @@ write_headers_to_stream (GMimeObject *object, GMimeFormatOptions *options, GMime
                        header = g_mime_header_list_get_header_at (object->headers, index);
                        
                        if (!g_mime_format_options_is_hidden_header (options, header->name)) {
-                               if ((nwritten = g_mime_header_write_to_stream (object->headers, header, 
options, stream)) == -1)
+                               if ((nwritten = g_mime_header_write_to_stream (header, options, stream)) == 
-1)
                                        return -1;
                                
                                total += nwritten;
@@ -920,7 +507,7 @@ write_headers_to_stream (GMimeObject *object, GMimeFormatOptions *options, GMime
                        header = g_mime_header_list_get_header_at (mime_part->headers, body_index);
                        
                        if (!g_mime_format_options_is_hidden_header (options, header->name)) {
-                               if ((nwritten = g_mime_header_write_to_stream (mime_part->headers, header, 
options, stream)) == -1)
+                               if ((nwritten = g_mime_header_write_to_stream (header, options, stream)) == 
-1)
                                        return -1;
                                
                                total += nwritten;
@@ -1030,7 +617,7 @@ g_mime_message_new (gboolean pretty_headers)
                
                _g_mime_object_block_header_list_changed ((GMimeObject *) message);
                for (i = 0; i < G_N_ELEMENTS (rfc822_headers); i++) 
-                       g_mime_header_list_set (headers, rfc822_headers[i], NULL);
+                       g_mime_header_list_set (headers, rfc822_headers[i], NULL, NULL);
                _g_mime_object_unblock_header_list_changed ((GMimeObject *) message);
        }
        
@@ -1150,7 +737,7 @@ sync_internet_address_list (InternetAddressList *list, GMimeMessage *message, co
        string = internet_address_list_to_string (list, options, TRUE);
        
        _g_mime_object_block_header_list_changed (object);
-       g_mime_header_list_set (object->headers, name, string);
+       g_mime_object_set_header (object, name, string, NULL);
        _g_mime_object_unblock_header_list_changed (object);
        
        g_free (string);
@@ -1297,19 +884,10 @@ g_mime_message_get_all_recipients (GMimeMessage *message)
 void
 g_mime_message_set_subject (GMimeMessage *message, const char *subject, const char *charset)
 {
-       GMimeFormatOptions *options;
-       char *encoded;
-       
        g_return_if_fail (GMIME_IS_MESSAGE (message));
        g_return_if_fail (subject != NULL);
        
-       g_free (message->subject);
-       message->subject = g_mime_strdup_trim (subject);
-       
-       options = g_mime_format_options_get_default ();
-       encoded = g_mime_utils_header_encode_text (options, message->subject, charset);
-       g_mime_object_set_header ((GMimeObject *) message, "Subject", encoded);
-       g_free (encoded);
+       g_mime_object_set_header ((GMimeObject *) message, "Subject", subject, charset);
 }
 
 
@@ -1351,7 +929,7 @@ g_mime_message_set_date (GMimeMessage *message, time_t date, int tz_offset)
        message->tz_offset = tz_offset;
        
        str = g_mime_utils_header_format_date (date, tz_offset);
-       g_mime_object_set_header (GMIME_OBJECT (message), "Date", str);
+       g_mime_object_set_header ((GMimeObject *) message, "Date", str, NULL);
        g_free (str);
 }
 
@@ -1417,7 +995,7 @@ g_mime_message_set_date_as_string (GMimeMessage *message, const char *str)
        message->date = date;
        
        buf = g_mime_utils_header_format_date (date, tz_offset);
-       g_mime_object_set_header (GMIME_OBJECT (message), "Date", buf);
+       g_mime_object_set_header ((GMimeObject *) message, "Date", buf, NULL);
        g_free (buf);
 }
 
@@ -1437,11 +1015,8 @@ g_mime_message_set_message_id (GMimeMessage *message, const char *message_id)
        g_return_if_fail (GMIME_IS_MESSAGE (message));
        g_return_if_fail (message_id != NULL);
        
-       g_free (message->message_id);
-       message->message_id = g_mime_strdup_trim (message_id);
-       
        msgid = g_strdup_printf ("<%s>", message_id);
-       g_mime_object_set_header (GMIME_OBJECT (message), "Message-Id", msgid);
+       g_mime_object_set_header ((GMimeObject *) message, "Message-Id", msgid, NULL);
        g_free (msgid);
 }
 
@@ -1508,7 +1083,7 @@ g_mime_message_set_mime_part (GMimeMessage *message, GMimeObject *mime_part)
                int i;
                
                if (!g_mime_header_list_contains (headers, "MIME-Version"))
-                       g_mime_header_list_append (headers, "MIME-Version", "1.0");
+                       g_mime_header_list_append (headers, "MIME-Version", "1.0", NULL);
                
                for (i = 0; i < g_mime_header_list_get_count (mime_part->headers); i++) {
                        header = g_mime_header_list_get_header_at (mime_part->headers, i);
diff --git a/gmime/gmime-object.c b/gmime/gmime-object.c
index 5e94da1..cff90d4 100644
--- a/gmime/gmime-object.c
+++ b/gmime/gmime-object.c
@@ -73,11 +73,6 @@ static char *object_get_headers (GMimeObject *object, GMimeFormatOptions *option
 static ssize_t object_write_to_stream (GMimeObject *object, GMimeFormatOptions *options, gboolean 
content_only, GMimeStream *stream);
 static void object_encode (GMimeObject *object, GMimeEncodingConstraint constraint);
 
-static ssize_t write_content_type (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream 
*stream,
-                                  const char *name, const char *value);
-static ssize_t write_disposition (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream 
*stream,
-                                 const char *name, const char *value);
-
 static void header_list_changed (GMimeHeaderList *headers, GMimeHeaderListChangedEventArgs *args, 
GMimeObject *object);
 static void content_type_changed (GMimeContentType *content_type, gpointer args, GMimeObject *object);
 static void content_disposition_changed (GMimeContentDisposition *disposition, gpointer args, GMimeObject 
*object);
@@ -146,9 +141,6 @@ g_mime_object_init (GMimeObject *object, GMimeObjectClass *klass)
        object->content_type = NULL;
        object->disposition = NULL;
        object->content_id = NULL;
-       
-       g_mime_header_list_register_writer (object->headers, "Content-Type", write_content_type);
-       g_mime_header_list_register_writer (object->headers, "Content-Disposition", write_disposition);
 }
 
 
@@ -209,7 +201,6 @@ object_header_changed (GMimeObject *object, GMimeHeader *header)
        const char *name, *value;
        guint i;
        
-       value = g_mime_header_get_value (header);
        name = g_mime_header_get_name (header);
        
        if (g_ascii_strncasecmp (name, "Content-", 8) != 0)
@@ -222,16 +213,19 @@ object_header_changed (GMimeObject *object, GMimeHeader *header)
        
        switch (i) {
        case HEADER_CONTENT_DISPOSITION:
+               value = g_mime_header_get_value (header);
                disposition = g_mime_content_disposition_parse (options, value);
                _g_mime_object_set_content_disposition (object, disposition);
                g_object_unref (disposition);
                break;
        case HEADER_CONTENT_TYPE:
+               value = g_mime_header_get_value (header);
                content_type = g_mime_content_type_parse (options, value);
                _g_mime_object_set_content_type (object, content_type);
                g_object_unref (content_type);
                break;
        case HEADER_CONTENT_ID:
+               value = g_mime_header_get_value (header);
                g_free (object->content_id);
                object->content_id = g_mime_utils_decode_message_id (value);
                break;
@@ -309,31 +303,6 @@ header_list_changed (GMimeHeaderList *headers, GMimeHeaderListChangedEventArgs *
        }
 }
 
-static ssize_t
-write_content_type (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-                   const char *name, const char *value)
-{
-       GMimeContentType *content_type;
-       ssize_t nwritten;
-       char *raw_value;
-       GString *str;
-       
-       str = g_string_new (name);
-       g_string_append_c (str, ':');
-       
-       content_type = g_mime_content_type_parse (options, value);
-       raw_value = g_mime_content_type_encode (content_type, format);
-       g_object_unref (content_type);
-       
-       g_string_append (str, raw_value);
-       g_free (raw_value);
-       
-       nwritten = g_mime_stream_write (stream, str->str, str->len);
-       g_string_free (str, TRUE);
-       
-       return nwritten;
-}
-
 void
 _g_mime_object_block_header_list_changed (GMimeObject *object)
 {
@@ -390,7 +359,7 @@ content_type_changed (GMimeContentType *content_type, gpointer args, GMimeObject
        value = unfold_raw_value (raw_value);
        
        _g_mime_object_block_header_list_changed (object);
-       g_mime_header_list_set (object->headers, "Content-Type", value);
+       g_mime_header_list_set (object->headers, "Content-Type", value, NULL);
        header = g_mime_header_list_get_header (object->headers, "Content-Type");
        _g_mime_header_set_raw_value (header, raw_value);
        _g_mime_object_unblock_header_list_changed (object);
@@ -398,30 +367,6 @@ content_type_changed (GMimeContentType *content_type, gpointer args, GMimeObject
        g_free (value);
 }
 
-static ssize_t
-write_disposition (GMimeParserOptions *options, GMimeFormatOptions *format, GMimeStream *stream,
-                  const char *name, const char *value)
-{
-       GMimeContentDisposition *disposition;
-       ssize_t nwritten;
-       char *raw_value;
-       GString *str;
-       
-       str = g_string_new (name);
-       g_string_append_c (str, ':');
-       
-       disposition = g_mime_content_disposition_parse (options, value);
-       g_string_append (str, disposition->disposition);
-       
-       g_mime_param_list_encode (disposition->params, format, TRUE, str);
-       g_object_unref (disposition);
-       
-       nwritten = g_mime_stream_write (stream, str->str, str->len);
-       g_string_free (str, TRUE);
-       
-       return nwritten;
-}
-
 static void
 content_disposition_changed (GMimeContentDisposition *disposition, gpointer args, GMimeObject *object)
 {
@@ -436,7 +381,7 @@ content_disposition_changed (GMimeContentDisposition *disposition, gpointer args
                raw_value = g_mime_content_disposition_encode (object->disposition, options);
                value = unfold_raw_value (raw_value);
                
-               g_mime_header_list_set (object->headers, "Content-Disposition", value);
+               g_mime_header_list_set (object->headers, "Content-Disposition", value, NULL);
                header = g_mime_header_list_get_header (object->headers, "Content-Disposition");
                _g_mime_header_set_raw_value (header, raw_value);
                g_free (raw_value);
@@ -901,7 +846,7 @@ g_mime_object_set_content_id (GMimeObject *object, const char *content_id)
        
        msgid = g_strdup_printf ("<%s>", content_id);
        _g_mime_object_block_header_list_changed (object);
-       g_mime_header_list_set (object->headers, "Content-Id", msgid);
+       g_mime_header_list_set (object->headers, "Content-Id", msgid, NULL);
        _g_mime_object_unblock_header_list_changed (object);
        g_free (msgid);
 }
@@ -924,39 +869,30 @@ g_mime_object_get_content_id (GMimeObject *object)
 }
 
 
-void
-_g_mime_object_prepend_header (GMimeObject *object, const char *header, const char *value,
-                              const char *raw_name, const char *raw_value, gint64 offset)
-{
-       _g_mime_header_list_prepend (object->headers, header, value, raw_name, raw_value, offset);
-}
-
-
 /**
  * g_mime_object_prepend_header:
  * @object: a #GMimeObject
  * @header: header name
  * @value: header value
+ * @charset: a charset
  *
- * Prepends a raw, unprocessed header to the MIME object.
- *
- * Note: @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
+ * Prepends a new header to the header list.
  **/
 void
-g_mime_object_prepend_header (GMimeObject *object, const char *header, const char *value)
+g_mime_object_prepend_header (GMimeObject *object, const char *header, const char *value, const char 
*charset)
 {
        g_return_if_fail (GMIME_IS_OBJECT (object));
+       g_return_if_fail (header != NULL);
        
-       g_mime_header_list_prepend (object->headers, header, value);
+       g_mime_header_list_prepend (object->headers, header, value, charset);
 }
 
 
 void
-_g_mime_object_append_header (GMimeObject *object, const char *header, const char *value,
-                             const char *raw_name, const char *raw_value, gint64 offset)
+_g_mime_object_append_header (GMimeObject *object, const char *header, const char *raw_name,
+                             const char *raw_value, gint64 offset)
 {
-       _g_mime_header_list_append (object->headers, header, value, raw_name, raw_value, offset);
+       _g_mime_header_list_append (object->headers, header, raw_name, raw_value, offset);
 }
 
 
@@ -965,26 +901,17 @@ _g_mime_object_append_header (GMimeObject *object, const char *header, const cha
  * @object: a #GMimeObject
  * @header: header name
  * @value: header value
+ * @charset: a charset
  *
- * Appends a raw, unprocessed header to the MIME object.
- *
- * Note: @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
+ * Appends a new header to the header list.
  **/
 void
-g_mime_object_append_header (GMimeObject *object, const char *header, const char *value)
+g_mime_object_append_header (GMimeObject *object, const char *header, const char *value, const char *charset)
 {
        g_return_if_fail (GMIME_IS_OBJECT (object));
+       g_return_if_fail (header != NULL);
        
-       g_mime_header_list_append (object->headers, header, value);
-}
-
-
-void
-_g_mime_object_set_header (GMimeObject *object, const char *header, const char *value,
-                          const char *raw_name, const char *raw_value, gint64 offset)
-{
-       _g_mime_header_list_set (object->headers, header, value, raw_name, raw_value, offset);
+       g_mime_header_list_append (object->headers, header, value, charset);
 }
 
 
@@ -993,18 +920,17 @@ _g_mime_object_set_header (GMimeObject *object, const char *header, const char *
  * @object: a #GMimeObject
  * @header: header name
  * @value: header value
+ * @charset: a charset
  *
- * Sets an arbitrary raw, unprocessed header on the MIME object.
- *
- * Note: @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
+ * Sets a header to the specified value.
  **/
 void
-g_mime_object_set_header (GMimeObject *object, const char *header, const char *value)
+g_mime_object_set_header (GMimeObject *object, const char *header, const char *value, const char *charset)
 {
        g_return_if_fail (GMIME_IS_OBJECT (object));
+       g_return_if_fail (header != NULL);
        
-       g_mime_header_list_set (object->headers, header, value);
+       g_mime_header_list_set (object->headers, header, value, charset);
 }
 
 
@@ -1013,13 +939,10 @@ g_mime_object_set_header (GMimeObject *object, const char *header, const char *v
  * @object: a #GMimeObject
  * @header: header name
  *
- * Gets the raw, unprocessed value of the first header with the specified name.
+ * Gets the value of the first header with the specified name.
  *
- * Returns: the raw, unprocessed value of the requested header if it
+ * Returns: the value of the requested header if it
  * exists or %NULL otherwise.
- *
- * Note: The returned value should be decoded with a function such as
- * g_mime_utils_header_decode_text() before displaying to the user.
  **/
 const char *
 g_mime_object_get_header (GMimeObject *object, const char *header)
diff --git a/gmime/gmime-object.h b/gmime/gmime-object.h
index f02d069..c29534b 100644
--- a/gmime/gmime-object.h
+++ b/gmime/gmime-object.h
@@ -122,9 +122,9 @@ const char *g_mime_object_get_content_disposition_parameter (GMimeObject *object
 void g_mime_object_set_content_id (GMimeObject *object, const char *content_id);
 const char *g_mime_object_get_content_id (GMimeObject *object);
 
-void g_mime_object_prepend_header (GMimeObject *object, const char *header, const char *value);
-void g_mime_object_append_header (GMimeObject *object, const char *header, const char *value);
-void g_mime_object_set_header (GMimeObject *object, const char *header, const char *value);
+void g_mime_object_prepend_header (GMimeObject *object, const char *header, const char *value, const char 
*charset);
+void g_mime_object_append_header (GMimeObject *object, const char *header, const char *value, const char 
*charset);
+void g_mime_object_set_header (GMimeObject *object, const char *header, const char *value, const char 
*charset);
 const char *g_mime_object_get_header (GMimeObject *object, const char *header);
 gboolean g_mime_object_remove_header (GMimeObject *object, const char *header);
 
diff --git a/gmime/gmime-parser.c b/gmime/gmime-parser.c
index c346603..d4cef20 100644
--- a/gmime/gmime-parser.c
+++ b/gmime/gmime-parser.c
@@ -102,8 +102,8 @@ typedef struct _boundary_stack {
 } BoundaryStack;
 
 typedef struct {
-       char *raw_name, *raw_value;
-       char *name, *value;
+       char *raw_name, *name;
+       char *raw_value;
        gint64 offset;
 } Header;
 
@@ -184,11 +184,6 @@ struct _GMimeParserPrivate {
        char *headerptr;
        size_t headerleft;
        
-       /* raw header buffer */
-       char *rawbuf;
-       char *rawptr;
-       size_t rawleft;
-       
        BoundaryStack *bounds;
        
        short int state;
@@ -275,7 +270,7 @@ parser_find_header (GMimeParser *parser, const char *name, gint64 *offset)
                if (offset)
                        *offset = header->offset;
                
-               return header->value;
+               return header->raw_value;
        }
        
        return NULL;
@@ -291,7 +286,6 @@ parser_free_headers (struct _GMimeParserPrivate *priv)
                header = priv->headers->pdata[i];
                
                g_free (header->name);
-               g_free (header->value);
                g_free (header->raw_name);
                g_free (header->raw_value);
                g_slice_free (Header, header);
@@ -394,10 +388,6 @@ parser_init (GMimeParser *parser, GMimeStream *stream)
        priv->headerleft = HEADER_INIT_SIZE - 1;
        priv->headerptr = priv->headerbuf;
        
-       priv->rawbuf = g_malloc (HEADER_INIT_SIZE);
-       priv->rawleft = HEADER_INIT_SIZE - 1;
-       priv->rawptr = priv->rawbuf;
-       
        priv->message_headers_begin = -1;
        priv->message_headers_end = -1;
        
@@ -425,7 +415,6 @@ parser_close (GMimeParser *parser)
        g_byte_array_free (priv->marker, TRUE);
        
        g_free (priv->headerbuf);
-       g_free (priv->rawbuf);
        
        parser_free_headers (priv);
        g_ptr_array_free (priv->headers, TRUE);
@@ -862,23 +851,6 @@ next_alloc_size (size_t n)
        priv->headerleft -= len;                                          \
 } G_STMT_END
 
-#define raw_header_append(priv, start, len) G_STMT_START {                \
-       if (priv->rawleft <= len) {                                       \
-               size_t hlen, hoff;                                        \
-                                                                         \
-               hoff = priv->rawptr - priv->rawbuf;                       \
-               hlen = next_alloc_size (hoff + len + 1);                  \
-                                                                         \
-               priv->rawbuf = g_realloc (priv->rawbuf, hlen);            \
-               priv->rawptr = priv->rawbuf + hoff;                       \
-               priv->rawleft = (hlen - 1) - hoff;                        \
-       }                                                                 \
-                                                                         \
-       memcpy (priv->rawptr, start, len);                                \
-       priv->rawptr += len;                                              \
-       priv->rawleft -= len;                                             \
-} G_STMT_END
-
 static void
 header_parse (GMimeParser *parser)
 {
@@ -900,17 +872,15 @@ header_parse (GMimeParser *parser)
                
                priv->headerleft += priv->headerptr - priv->headerbuf;
                priv->headerptr = priv->headerbuf;
-               
-               priv->rawleft += priv->rawptr - priv->rawbuf;
-               priv->rawptr = priv->rawbuf;
-               
                return;
        }
        
        header = g_slice_new (Header);
        g_ptr_array_add (priv->headers, header);
        
-       header->value = g_mime_strdup_trim (inptr + 1);
+       header->raw_name = g_strndup (priv->headerbuf, (size_t) (inptr - priv->headerbuf));
+       header->raw_value = g_strdup (inptr + 1);
+       header->offset = priv->header_offset;
        
        /* now walk backwards over lwsp characters */
        while (inptr > priv->headerbuf && is_blank (inptr[-1]))
@@ -918,24 +888,11 @@ header_parse (GMimeParser *parser)
        
        header->name = g_strndup (priv->headerbuf, (size_t) (inptr - priv->headerbuf));
        
-       *priv->rawptr = ':';
-       inptr = priv->rawbuf;
-       while (*inptr != ':')
-               inptr++;
-       *priv->rawptr = '\0';
-       
-       header->raw_name = g_strndup (priv->rawbuf, (size_t) (inptr - priv->rawbuf));
-       header->raw_value = g_strdup (inptr + 1);
-       header->offset = priv->header_offset;
-       
        priv->headerleft += priv->headerptr - priv->headerbuf;
        priv->headerptr = priv->headerbuf;
        
-       priv->rawleft += priv->rawptr - priv->rawbuf;
-       priv->rawptr = priv->rawbuf;
-       
        if (priv->regex && g_regex_match (priv->regex, header->name, 0, NULL))
-               priv->header_cb (parser, header->name, header->value,
+               priv->header_cb (parser, header->name, header->raw_value,
                                 header->offset, priv->user_data);
 }
 
@@ -1114,7 +1071,6 @@ parser_step_headers (GMimeParser *parser)
                                        len--;
                                }
                                
-                               raw_header_append (priv, start, len);
                                header_append (priv, start, len);
                                left = (ssize_t) (inend - inptr);
                                priv->midline = TRUE;
@@ -1122,7 +1078,7 @@ parser_step_headers (GMimeParser *parser)
                                goto refill;
                        }
                        
-                       raw_header_append (priv, start, len);
+                       header_append (priv, start, len);
                        
                        if (inptr > start && inptr[-1] == '\r')
                                len--;
@@ -1131,10 +1087,8 @@ parser_step_headers (GMimeParser *parser)
                        if (!priv->midline && len == 0)
                                goto headers_end;
                        
-                       header_append (priv, start, len);
-                       
                        /* inptr has to be less than inend - 1 */
-                       raw_header_append (priv, "\n", 1);
+                       header_append (priv, "\n", 1);
                        priv->midline = FALSE;
                        continuation = TRUE;
                        inptr++;
@@ -1150,7 +1104,6 @@ parser_step_headers (GMimeParser *parser)
        
        len = (size_t) (inend - inptr);
        header_append (priv, inptr, len);
-       raw_header_append (priv, inptr, len);
        
  headers_end:
        
@@ -1680,8 +1633,8 @@ parser_scan_message_part (GMimeParser *parser, GMimeParserOptions *options, GMim
                header = priv->headers->pdata[i];
                
                if (g_ascii_strncasecmp (header->name, "Content-", 8) != 0) {
-                       _g_mime_object_append_header ((GMimeObject *) message, header->name, header->value,
-                                                     header->raw_name, header->raw_value, header->offset);
+                       _g_mime_object_append_header ((GMimeObject *) message, header->name, header->raw_name,
+                                                     header->raw_value, header->offset);
                }
        }
        
@@ -1722,9 +1675,8 @@ parser_construct_leaf_part (GMimeParser *parser, GMimeParserOptions *options, Co
                header = priv->headers->pdata[i];
                
                if (!toplevel || !g_ascii_strncasecmp (header->name, "Content-", 8)) {
-                       _g_mime_object_append_header (object, header->name, header->value,
-                                                     header->raw_name, header->raw_value,
-                                                     header->offset);
+                       _g_mime_object_append_header (object, header->name, header->raw_name,
+                                                     header->raw_value, header->offset);
                }
        }
        
@@ -1866,9 +1818,8 @@ parser_construct_multipart (GMimeParser *parser, GMimeParserOptions *options, Co
                header = priv->headers->pdata[i];
                
                if (!toplevel || !g_ascii_strncasecmp (header->name, "Content-", 8)) {
-                       _g_mime_object_append_header (object, header->name, header->value,
-                                                     header->raw_name, header->raw_value,
-                                                     header->offset);
+                       _g_mime_object_append_header (object, header->name, header->raw_name,
+                                                     header->raw_value, header->offset);
                }
        }
        
@@ -1973,6 +1924,7 @@ parser_construct_message (GMimeParser *parser, GMimeParserOptions *options)
        GMimeObject *object;
        GMimeStream *stream;
        BoundaryType found;
+       const char *inptr;
        Header *header;
        char *endptr;
        guint i;
@@ -1996,14 +1948,18 @@ parser_construct_message (GMimeParser *parser, GMimeParserOptions *options)
                header = priv->headers->pdata[i];
                
                if (priv->respect_content_length && !g_ascii_strcasecmp (header->name, "Content-Length")) {
-                       content_length = strtoul (header->value, &endptr, 10);
-                       if (endptr == header->value)
+                       inptr = header->raw_value;
+                       while (is_lwsp (*inptr))
+                               inptr++;
+                       
+                       content_length = strtoul (inptr, &endptr, 10);
+                       if (endptr == inptr)
                                content_length = ULONG_MAX;
                }
                
                if (g_ascii_strncasecmp (header->name, "Content-", 8) != 0) {
-                       _g_mime_object_append_header ((GMimeObject *) message, header->name, header->value,
-                                                     header->raw_name, header->raw_value, header->offset);
+                       _g_mime_object_append_header ((GMimeObject *) message, header->name, header->raw_name,
+                                                     header->raw_value, header->offset);
                }
        }
        
diff --git a/gmime/gmime-part.c b/gmime/gmime-part.c
index dcb220f..fa5a07e 100644
--- a/gmime/gmime-part.c
+++ b/gmime/gmime-part.c
@@ -188,7 +188,6 @@ process_header (GMimeObject *object, GMimeHeader *header)
        char encoding[32];
        guint i;
        
-       value = g_mime_header_get_value (header);
        name = g_mime_header_get_name (header);
        
        if (g_ascii_strncasecmp (name, "Content-", 8) != 0)
@@ -201,21 +200,24 @@ process_header (GMimeObject *object, GMimeHeader *header)
        
        switch (i) {
        case HEADER_CONTENT_TRANSFER_ENCODING:
+               value = g_mime_header_get_value (header);
                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 */
+               value = g_mime_header_get_value (header);
                g_free (mime_part->content_description);
-               mime_part->content_description = g_mime_strdup_trim (value);
+               mime_part->content_description = g_strdup (value);
                break;
        case HEADER_CONTENT_LOCATION:
+               value = g_mime_header_get_value (header);
                g_free (mime_part->content_location);
-               mime_part->content_location = g_mime_strdup_trim (value);
+               mime_part->content_location = g_strdup (value);
                break;
        case HEADER_CONTENT_MD5:
+               value = g_mime_header_get_value (header);
                g_free (mime_part->content_md5);
-               mime_part->content_md5 = g_mime_strdup_trim (value);
+               mime_part->content_md5 = g_strdup (value);
                break;
        default:
                return FALSE;
@@ -541,7 +543,7 @@ g_mime_part_set_content_description (GMimePart *mime_part, const char *descripti
        mime_part->content_description = g_strdup (description);
        
        _g_mime_object_block_header_list_changed (object);
-       g_mime_header_list_set (object->headers, "Content-Description", description);
+       g_mime_header_list_set (object->headers, "Content-Description", description, NULL);
        _g_mime_object_unblock_header_list_changed (object);
 }
 
@@ -654,7 +656,7 @@ g_mime_part_set_content_md5 (GMimePart *mime_part, const char *content_md5)
        mime_part->content_md5 = g_strdup (content_md5);
        
        _g_mime_object_block_header_list_changed (object);
-       g_mime_header_list_set (object->headers, "Content-Md5", content_md5);
+       g_mime_header_list_set (object->headers, "Content-Md5", content_md5, NULL);
        _g_mime_object_unblock_header_list_changed (object);
 }
 
@@ -753,7 +755,7 @@ g_mime_part_set_content_location (GMimePart *mime_part, const char *content_loca
        mime_part->content_location = g_strdup (content_location);
 
        _g_mime_object_block_header_list_changed (object);
-       g_mime_header_list_set (object->headers, "Content-Location", content_location);
+       g_mime_header_list_set (object->headers, "Content-Location", content_location, NULL);
        _g_mime_object_block_header_list_changed (object);
 }
 
@@ -795,7 +797,7 @@ g_mime_part_set_content_encoding (GMimePart *mime_part, GMimeContentEncoding enc
        mime_part->encoding = encoding;
        
        _g_mime_object_block_header_list_changed (object);
-       g_mime_header_list_set (object->headers, "Content-Transfer-Encoding", value);
+       g_mime_header_list_set (object->headers, "Content-Transfer-Encoding", value, NULL);
        _g_mime_object_block_header_list_changed (object);
 }
 
diff --git a/tests/test-headers.c b/tests/test-headers.c
index f21d18b..69c42f0 100644
--- a/tests/test-headers.c
+++ b/tests/test-headers.c
@@ -59,8 +59,8 @@ header_list_new (void)
        
        list = g_mime_header_list_new (g_mime_parser_options_get_default ());
        for (i = 1; i < G_N_ELEMENTS (initial); i++)
-               g_mime_header_list_append (list, initial[i].name, initial[i].value);
-       g_mime_header_list_prepend (list, initial[0].name, initial[0].value);
+               g_mime_header_list_append (list, initial[i].name, initial[i].value, NULL);
+       g_mime_header_list_prepend (list, initial[0].name, initial[0].value, NULL);
        
        return list;
 }
@@ -278,7 +278,7 @@ test_content_type_sync (void)
                
                /* let's try this in reverse... set the header value and make sure GMimeContentType gets 
updated */
                header = g_mime_header_list_get_header_at (headers, 0);
-               g_mime_header_set_value (header, "text/html; charset=utf-8");
+               g_mime_header_set_value (header, NULL, "text/html; charset=utf-8", NULL);
                type = g_mime_object_get_content_type (object);
                if (!g_mime_content_type_is_type (type, "text", "html"))
                        throw (exception_new ("GMimeContentType object was not updated"));
@@ -342,7 +342,7 @@ test_disposition_sync (void)
                
                /* let's try this in reverse... set the header value and make sure GMimeContentDisposition 
gets updated */
                header = g_mime_header_list_get_header_at (headers, 1);
-               g_mime_header_set_value (header, "attachment; filename=xyz");
+               g_mime_header_set_value (header, NULL, "attachment; filename=xyz", NULL);
                disposition = g_mime_object_get_content_disposition (object);
                if (!g_mime_content_disposition_is_attachment (disposition))
                        throw (exception_new ("GMimeContentDisposition object was not updated"));
diff --git a/tests/test-pgpmime.c b/tests/test-pgpmime.c
index 014668f..e2d210b 100644
--- a/tests/test-pgpmime.c
+++ b/tests/test-pgpmime.c
@@ -188,7 +188,7 @@ create_message (GMimeObject *body)
        g_object_unref (mailbox);
        
        g_mime_message_set_subject (message, "This is a test message", NULL);
-       g_mime_object_set_header ((GMimeObject *) message, "X-Mailer", "main.c");
+       g_mime_object_set_header ((GMimeObject *) message, "X-Mailer", "main.c", NULL);
        g_mime_message_set_mime_part (message, body);
        
        stream = g_mime_stream_mem_new ();
@@ -327,8 +327,8 @@ create_encrypted_message (GMimeCryptoContext *ctx, gboolean sign,
        g_object_unref (mailbox);
        
        g_mime_message_set_subject (message, "This is a test message", NULL);
-       g_mime_object_set_header ((GMimeObject *) message, "X-Mailer", "main.c");
-       g_mime_message_set_mime_part (message, GMIME_OBJECT (mpe));
+       g_mime_object_set_header ((GMimeObject *) message, "X-Mailer", "main.c", NULL);
+       g_mime_message_set_mime_part (message, (GMimeObject *) mpe);
        g_object_unref (mpe);
        
        stream = g_mime_stream_mem_new ();
diff --git a/tests/test-smime.c b/tests/test-smime.c
index d89c603..27df8b0 100644
--- a/tests/test-smime.c
+++ b/tests/test-smime.c
@@ -190,7 +190,7 @@ create_message (GMimeObject *body)
        g_object_unref (mailbox);
        
        g_mime_message_set_subject (message, "This is a test message", NULL);
-       g_mime_object_set_header ((GMimeObject *) message, "X-Mailer", "main.c");
+       g_mime_object_set_header ((GMimeObject *) message, "X-Mailer", "main.c", NULL);
        g_mime_message_set_mime_part (message, body);
        
        stream = g_mime_stream_mem_new ();


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