[gmime] Updated code to use the new GMimeParamList instead of a linked-list



commit 71c5b5f37989426f667fc1e37a0468f637c4334b
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Wed Mar 15 17:32:25 2017 -0400

    Updated code to use the new GMimeParamList instead of a linked-list

 examples/imap-example.c    |  118 +++--
 gmime/gmime-content-type.c |   76 +--
 gmime/gmime-content-type.h |    7 +-
 gmime/gmime-disposition.c  |   82 +--
 gmime/gmime-disposition.h  |    6 +-
 gmime/gmime-object.c       |   17 +-
 gmime/gmime-param.c        | 1394 ++++++++++++++++++++++----------------------
 gmime/gmime-param.h        |   71 ++-
 tests/test-headers.c       |   15 +-
 tests/test-mime.c          |   43 +-
 10 files changed, 913 insertions(+), 916 deletions(-)
---
diff --git a/examples/imap-example.c b/examples/imap-example.c
index 4859c39..ee867cf 100644
--- a/examples/imap-example.c
+++ b/examples/imap-example.c
@@ -77,23 +77,35 @@ escape_string (const char *string)
 static void
 write_part_bodystructure (GMimeObject *part, FILE *fp)
 {
+       GMimeContentType *content_type;
+       GMimeParamList *params;
+       const char *subtype;
        GMimeParam *param;
+       int i, n;
        
        fputc ('(', fp);
        
-       fprintf (fp, "\"%s\" ", part->content_type->type);
-       if (part->content_type->subtype)
-               fprintf (fp, "\"%s\" ", part->content_type->subtype);
+       content_type = g_mime_object_get_content_type (part);
+       
+       fprintf (fp, "\"%s\" ", g_mime_content_type_get_media_type (content_type));
+       
+       if ((subtype = g_mime_content_type_get_media_subtype (content_type)))
+               fprintf (fp, "\"%s\" ", subtype);
        else
                fputs ("\"\"", fp);
        
        /* Content-Type params */
-       if ((param = part->content_type->params)) {
+       params = g_mime_content_type_get_params (content_type);
+       if ((n = g_mime_param_list_length (params)) > 0) {
                fputc ('(', fp);
-               while (param) {
-                       fprintf (fp, "\"%s\" \"%s\"", param->name, param->value);
-                       if ((param = param->next))
+               for (i = 0; i < n; i++) {
+                       if (i > 0)
                                fputc (' ', fp);
+                       
+                       param = g_mime_param_list_get_parameter_at (params, i);
+                       fprintf (fp, "\"%s\" \"%s\"", g_mime_param_get_name (param),
+                                g_mime_param_get_value (param));
+                               
                }
                fputs (") ", fp);
        } else {
@@ -103,7 +115,6 @@ write_part_bodystructure (GMimeObject *part, FILE *fp)
        if (GMIME_IS_MULTIPART (part)) {
                GMimeMultipart *multipart = (GMimeMultipart *) part;
                GMimeObject *subpart;
-               int i, n;
                
                n = g_mime_multipart_get_count (multipart);
                for (i = 0; i < n; i++) {
@@ -192,14 +203,23 @@ write_part_bodystructure (GMimeObject *part, FILE *fp)
                /* print body */
                write_part_bodystructure ((GMimeObject *) message->mime_part, fp);
        } else if (GMIME_IS_PART (part)) {
-               if (GMIME_OBJECT (part)->disposition) {
-                       fprintf (fp, "\"%s\" ", GMIME_OBJECT (part)->disposition->disposition);
-                       if ((param = GMIME_OBJECT (part)->disposition->params)) {
+               GMimeContentDisposition *disposition;
+               
+               disposition = g_mime_object_get_content_disposition (part);
+               
+               if (disposition) {
+                       fprintf (fp, "\"%s\" ", g_mime_content_disposition_get_disposition (disposition));
+                       
+                       params = g_mime_content_disposition_get_params (disposition);
+                       if ((n = g_mime_param_list_length (params)) > 0) {
                                fputc ('(', fp);
-                               while (param) {
-                                       fprintf (fp, "\"%s\" \"%s\"", param->name, param->value);
-                                       if ((param = param->next))
+                               for (i = 0; i < n; i++) {
+                                       if (i > 0)
                                                fputc (' ', fp);
+                                       
+                                       param = g_mime_param_list_get_parameter_at (params, i);
+                                       fprintf (fp, "\"%s\" \"%s\"", g_mime_param_get_name (param),
+                                                g_mime_param_get_value (param));
                                }
                                fputs (") ", fp);
                        } else {
@@ -209,7 +229,7 @@ write_part_bodystructure (GMimeObject *part, FILE *fp)
                        fputs ("NIL NIL ", fp);
                }
                
-               switch (GMIME_PART (part)->encoding) {
+               switch (g_mime_part_get_content_encoding ((GMimePart *) part)) {
                case GMIME_CONTENT_ENCODING_7BIT:
                        fputs ("\"7bit\"", fp);
                        break;
@@ -351,11 +371,11 @@ struct _bodystruct {
        struct {
                char *type;
                char *subtype;
-               GMimeParam *params;
+               GMimeParamList *params;
        } content;
        struct {
                char *type;
-               GMimeParam *params;
+               GMimeParamList *params;
        } disposition;
        char *encoding;
        struct _envelope *envelope;
@@ -415,49 +435,53 @@ decode_qstring (unsigned char **in, unsigned char *inend)
        return qstring;
 }
 
-static GMimeParam *
-decode_param (unsigned char **in, unsigned char *inend)
+static gboolean
+decode_param (unsigned char **in, unsigned char *inend, char **name, char **value)
 {
        GMimeParam *param;
-       char *name, *val;
+       char *n, *v;
        
-       if (!(name = decode_qstring (in, inend)))
-               return NULL;
+       if (!(n = decode_qstring (in, inend)))
+               return FALSE;
        
-       g_assert ((val = decode_qstring (in, inend)));
+       if (!(v = decode_qstring (in, inend))) {
+               g_free (n);
+               return FALSE;
+       }
        
-       param = g_mime_param_new (name, val);
-       g_free (name);
-       g_free (val);
+       *name = n;
+       *value = v;
        
-       return param;
+       return TRUE;
 }
 
-static GMimeParam *
+static GMimeParamList *
 decode_params (unsigned char **in, unsigned char *inend)
 {
-       GMimeParam *params, *tail, *n;
+       GMimeParamList *params;
        unsigned char *inptr;
+       char *name, *value;
        
        inptr = *in;
-       params = NULL;
-       tail = (GMimeParam *) &params;
+       
+       params = g_mime_param_list_new ();
        
        while (inptr < inend && *inptr == ' ')
                inptr++;
        
        if (inptr == inend) {
                g_assert_not_reached ();
-               return NULL;
+               return params;
        }
        
        if (strncmp ((const char *) inptr, "NIL", 3) != 0) {
                g_assert (*inptr == '(');
                inptr++;
                
-               while ((n = decode_param (&inptr, inend)) != NULL) {
-                       tail->next = n;
-                       tail = n;
+               while (decode_param (&inptr, inend, &name, &value)) {
+                       g_mime_param_list_set_parameter (params, name, value);
+                       g_free (value);
+                       g_free (name);
                        
                        while (inptr < inend && *inptr == ' ')
                                inptr++;
@@ -597,7 +621,7 @@ static void
 bodystruct_dump (struct _bodystruct *part, int depth)
 {
        GMimeParam *param;
-       int i;
+       int i, n;
        
        for (i = 0; i < depth; i++)
                fputs ("  ", stderr);
@@ -606,10 +630,11 @@ bodystruct_dump (struct _bodystruct *part, int depth)
                 part->content.subtype);
        
        if (part->content.params) {
-               param = part->content.params;
-               while (param) {
-                       fprintf (stderr, "; %s=%s", param->name, param->value);
-                       param = param->next;
+               n = g_mime_param_list_length (part->content.params);
+               for (int i = 0; i < n; i++) {
+                       param = g_mime_param_list_get_parameter_at (part->content.params, i);
+                       fprintf (stderr, "; %s=%s", g_mime_param_get_name (param),
+                                g_mime_param_get_value (param));
                }
        }
        
@@ -662,10 +687,11 @@ bodystruct_dump (struct _bodystruct *part, int depth)
                                fputs ("  ", stderr);
                        fprintf (stderr, "Content-Disposition: %s", part->disposition.type);
                        if (part->disposition.params) {
-                               param = part->disposition.params;
-                               while (param) {
-                                       fprintf (stderr, "; %s=%s", param->name, param->value);
-                                       param = param->next;
+                               n = g_mime_param_list_length (part->disposition.params);
+                               for (i = 0; i < n; i++) {
+                                       param = g_mime_param_list_get_parameter_at (part->disposition.params, 
i);
+                                       fprintf (stderr, "; %s=%s", g_mime_param_get_name (param),
+                                                g_mime_param_get_value (param));
                                }
                        }
                        
@@ -691,11 +717,11 @@ bodystruct_free (struct _bodystruct *node)
                g_free (node->content.type);
                g_free (node->content.subtype);
                if (node->content.params)
-                       g_mime_param_free (node->content.params);
+                       g_mime_param_list_free (node->content.params);
                
                g_free (node->disposition.type);
                if (node->disposition.params)
-                       g_mime_param_free (node->disposition.params);
+                       g_mime_param_list_free (node->disposition.params);
                
                g_free (node->encoding);
                
diff --git a/gmime/gmime-content-type.c b/gmime/gmime-content-type.c
index b1cfb4f..09ea132 100644
--- a/gmime/gmime-content-type.c
+++ b/gmime/gmime-content-type.c
@@ -57,6 +57,8 @@ static void g_mime_content_type_class_init (GMimeContentTypeClass *klass);
 static void g_mime_content_type_init (GMimeContentType *content_type, GMimeContentTypeClass *klass);
 static void g_mime_content_type_finalize (GObject *object);
 
+static void param_list_changed (GMimeParamList *list, gpointer args, GMimeContentType *content_type);
+
 
 static GObjectClass *parent_class = NULL;
 
@@ -99,11 +101,12 @@ g_mime_content_type_class_init (GMimeContentTypeClass *klass)
 static void
 g_mime_content_type_init (GMimeContentType *content_type, GMimeContentTypeClass *klass)
 {
-       content_type->param_hash = g_hash_table_new (g_mime_strcase_hash, g_mime_strcase_equal);
        content_type->changed = g_mime_event_new ((GObject *) content_type);
-       content_type->params = NULL;
+       content_type->params = g_mime_param_list_new ();
        content_type->subtype = NULL;
        content_type->type = NULL;
+       
+       g_mime_event_add (content_type->params->changed, (GMimeEventCallback) param_list_changed, 
content_type);
 }
 
 static void
@@ -111,8 +114,7 @@ g_mime_content_type_finalize (GObject *object)
 {
        GMimeContentType *content_type = (GMimeContentType *) object;
        
-       g_hash_table_destroy (content_type->param_hash);
-       g_mime_param_free (content_type->params);
+       g_mime_param_list_free (content_type->params);
        g_mime_event_free (content_type->changed);
        g_free (content_type->subtype);
        g_free (content_type->type);
@@ -121,6 +123,13 @@ g_mime_content_type_finalize (GObject *object)
 }
 
 
+static void
+param_list_changed (GMimeParamList *list, gpointer args, GMimeContentType *content_type)
+{
+       g_mime_event_emit (content_type->changed, NULL);
+}
+
+
 /**
  * g_mime_content_type_new:
  * @type: the MIME type or %NULL for the default value
@@ -180,6 +189,7 @@ g_mime_content_type_parse (GMimeParserOptions *options, const char *str)
 {
        GMimeContentType *mime_type;
        const char *inptr = str;
+       GMimeParamList *params;
        char *type, *subtype;
        
        g_return_val_if_fail (str != NULL, NULL);
@@ -196,14 +206,10 @@ g_mime_content_type_parse (GMimeParserOptions *options, const char *str)
        while (*inptr && *inptr != ';')
                inptr++;
        
-       if (*inptr++ == ';' && *inptr) {
-               GMimeParam *param;
-               
-               param = mime_type->params = g_mime_param_parse (options, inptr);
-               while (param != NULL) {
-                       g_hash_table_insert (mime_type->param_hash, param->name, param);
-                       param = param->next;
-               }
+       if (*inptr++ == ';' && *inptr && (params = g_mime_param_list_parse (options, inptr))) {
+               g_mime_event_add (params->changed, (GMimeEventCallback) param_list_changed, mime_type);
+               g_mime_param_list_free (mime_type->params);
+               mime_type->params = params;
        }
        
        return mime_type;
@@ -351,32 +357,6 @@ g_mime_content_type_get_media_subtype (GMimeContentType *mime_type)
 
 
 /**
- * g_mime_content_type_set_params:
- * @mime_type: a #GMimeContentType object
- * @params: a list of #GMimeParam objects
- *
- * Sets the Content-Type's parameter list.
- **/
-void
-g_mime_content_type_set_params (GMimeContentType *mime_type, GMimeParam *params)
-{
-       g_return_if_fail (GMIME_IS_CONTENT_TYPE (mime_type));
-       
-       /* clear the current list/hash */
-       g_hash_table_remove_all (mime_type->param_hash);
-       g_mime_param_free (mime_type->params);
-       mime_type->params = params;
-       
-       while (params != NULL) {
-               g_hash_table_insert (mime_type->param_hash, params->name, params);
-               params = params->next;
-       }
-       
-       g_mime_event_emit (mime_type->changed, NULL);
-}
-
-
-/**
  * g_mime_content_type_get_params:
  * @mime_type: a #GMimeContentType object
  *
@@ -384,7 +364,7 @@ g_mime_content_type_set_params (GMimeContentType *mime_type, GMimeParam *params)
  *
  * Returns: the Content-Type's parameter list.
  **/
-const GMimeParam *
+GMimeParamList *
 g_mime_content_type_get_params (GMimeContentType *mime_type)
 {
        g_return_val_if_fail (GMIME_IS_CONTENT_TYPE (mime_type), NULL);
@@ -407,22 +387,9 @@ g_mime_content_type_get_params (GMimeContentType *mime_type)
 void
 g_mime_content_type_set_parameter (GMimeContentType *mime_type, const char *name, const char *value)
 {
-       GMimeParam *param = NULL;
-       
        g_return_if_fail (GMIME_IS_CONTENT_TYPE (mime_type));
-       g_return_if_fail (name != NULL);
-       g_return_if_fail (value != NULL);
        
-       if ((param = g_hash_table_lookup (mime_type->param_hash, name))) {
-               g_free (param->value);
-               param->value = g_strdup (value);
-       } else {
-               param = g_mime_param_new (name, value);
-               mime_type->params = g_mime_param_append_param (mime_type->params, param);
-               g_hash_table_insert (mime_type->param_hash, param->name, param);
-       }
-       
-       g_mime_event_emit (mime_type->changed, NULL);
+       g_mime_param_list_set_parameter (mime_type->params, name, value);
 }
 
 
@@ -443,9 +410,8 @@ g_mime_content_type_get_parameter (GMimeContentType *mime_type, const char *name
        GMimeParam *param;
        
        g_return_val_if_fail (GMIME_IS_CONTENT_TYPE (mime_type), NULL);
-       g_return_val_if_fail (name != NULL, NULL);
        
-       if (!(param = g_hash_table_lookup (mime_type->param_hash, name)))
+       if (!(param = g_mime_param_list_get_parameter (mime_type->params, name)))
                return NULL;
        
        return param->value;
diff --git a/gmime/gmime-content-type.h b/gmime/gmime-content-type.h
index 077dee4..eb6cb4c 100644
--- a/gmime/gmime-content-type.h
+++ b/gmime/gmime-content-type.h
@@ -52,10 +52,9 @@ struct _GMimeContentType {
        GObject parent_object;
        
        char *type, *subtype;
-       GMimeParam *params;
+       GMimeParamList *params;
        
        /* < private > */
-       GHashTable *param_hash;
        gpointer changed;
 };
 
@@ -66,7 +65,6 @@ struct _GMimeContentTypeClass {
 
 GType g_mime_content_type_get_type (void);
 
-
 GMimeContentType *g_mime_content_type_new (const char *type, const char *subtype);
 GMimeContentType *g_mime_content_type_parse (GMimeParserOptions *options, const char *str);
 
@@ -80,8 +78,7 @@ const char *g_mime_content_type_get_media_type (GMimeContentType *mime_type);
 void g_mime_content_type_set_media_subtype (GMimeContentType *mime_type, const char *subtype);
 const char *g_mime_content_type_get_media_subtype (GMimeContentType *mime_type);
 
-void g_mime_content_type_set_params (GMimeContentType *mime_type, GMimeParam *params);
-const GMimeParam *g_mime_content_type_get_params (GMimeContentType *mime_type);
+GMimeParamList *g_mime_content_type_get_params (GMimeContentType *mime_type);
 
 void g_mime_content_type_set_parameter (GMimeContentType *mime_type, const char *name, const char *value);
 const char *g_mime_content_type_get_parameter (GMimeContentType *mime_type, const char *name);
diff --git a/gmime/gmime-disposition.c b/gmime/gmime-disposition.c
index af388e0..db03d57 100644
--- a/gmime/gmime-disposition.c
+++ b/gmime/gmime-disposition.c
@@ -46,6 +46,8 @@ static void g_mime_content_disposition_class_init (GMimeContentDispositionClass
 static void g_mime_content_disposition_init (GMimeContentDisposition *disposition, 
GMimeContentDispositionClass *klass);
 static void g_mime_content_disposition_finalize (GObject *object);
 
+static void param_list_changed (GMimeParamList *list, gpointer args, GMimeContentDisposition *disposition);
+
 
 static GObjectClass *parent_class = NULL;
 
@@ -88,10 +90,11 @@ g_mime_content_disposition_class_init (GMimeContentDispositionClass *klass)
 static void
 g_mime_content_disposition_init (GMimeContentDisposition *disposition, GMimeContentDispositionClass *klass)
 {
-       disposition->param_hash = g_hash_table_new (g_mime_strcase_hash, g_mime_strcase_equal);
        disposition->changed = g_mime_event_new ((GObject *) disposition);
+       disposition->params = g_mime_param_list_new ();
        disposition->disposition = NULL;
-       disposition->params = NULL;
+       
+       g_mime_event_add (disposition->params->changed, (GMimeEventCallback) param_list_changed, disposition);
 }
 
 static void
@@ -99,8 +102,7 @@ g_mime_content_disposition_finalize (GObject *object)
 {
        GMimeContentDisposition *disposition = (GMimeContentDisposition *) object;
        
-       g_hash_table_destroy (disposition->param_hash);
-       g_mime_param_free (disposition->params);
+       g_mime_param_list_free (disposition->params);
        g_mime_event_free (disposition->changed);
        g_free (disposition->disposition);
        
@@ -108,6 +110,13 @@ g_mime_content_disposition_finalize (GObject *object)
 }
 
 
+static void
+param_list_changed (GMimeParamList *list, gpointer args, GMimeContentDisposition *disposition)
+{
+       g_mime_event_emit (disposition->changed, NULL);
+}
+
+
 /**
  * g_mime_content_disposition_new:
  *
@@ -141,7 +150,7 @@ g_mime_content_disposition_parse (GMimeParserOptions *options, const char *str)
 {
        GMimeContentDisposition *disposition;
        const char *inptr = str;
-       GMimeParam *param;
+       GMimeParamList *params;
        char *value;
        
        if (str == NULL)
@@ -159,13 +168,10 @@ g_mime_content_disposition_parse (GMimeParserOptions *options, const char *str)
        disposition->disposition = g_strstrip (value);
        
        /* parse the parameters, if any */
-       if (*inptr++ == ';' && *inptr) {
-               param = disposition->params = g_mime_param_parse (options, inptr);
-               
-               while (param) {
-                       g_hash_table_insert (disposition->param_hash, param->name, param);
-                       param = param->next;
-               }
+       if (*inptr++ == ';' && *inptr && (params = g_mime_param_list_parse (options, inptr))) {
+               g_mime_event_add (params->changed, (GMimeEventCallback) param_list_changed, disposition);
+               g_mime_param_list_free (disposition->params);
+               disposition->params = params;
        }
        
        return disposition;
@@ -217,40 +223,14 @@ g_mime_content_disposition_get_disposition (GMimeContentDisposition *disposition
 
 
 /**
- * g_mime_content_disposition_set_params:
- * @disposition: a #GMimeContentDisposition object
- * @params: a list of #GMimeParam objects
- *
- * Sets the Content-Disposition's parameter list.
- **/
-void
-g_mime_content_disposition_set_params (GMimeContentDisposition *disposition, GMimeParam *params)
-{
-       g_return_if_fail (GMIME_IS_CONTENT_DISPOSITION (disposition));
-       
-       /* destroy the current list/hash */
-       g_hash_table_remove_all (disposition->param_hash);
-       g_mime_param_free (disposition->params);
-       disposition->params = params;
-       
-       while (params != NULL) {
-               g_hash_table_insert (disposition->param_hash, params->name, params);
-               params = params->next;
-       }
-       
-       g_mime_event_emit (disposition->changed, NULL);
-}
-
-
-/**
  * g_mime_content_disposition_get_params:
  * @disposition: a #GMimeContentDisposition object
  *
  * Gets the Content-Disposition parameter list.
  *
- * Returns: the list of #GMimeParam's set on @disposition.
+ * Returns: the Content-Disposition's parameter list.
  **/
-const GMimeParam *
+GMimeParamList *
 g_mime_content_disposition_get_params (GMimeContentDisposition *disposition)
 {
        g_return_val_if_fail (GMIME_IS_CONTENT_DISPOSITION (disposition), NULL);
@@ -273,22 +253,9 @@ g_mime_content_disposition_get_params (GMimeContentDisposition *disposition)
 void
 g_mime_content_disposition_set_parameter (GMimeContentDisposition *disposition, const char *name, const char 
*value)
 {
-       GMimeParam *param = NULL;
-       
        g_return_if_fail (GMIME_IS_CONTENT_DISPOSITION (disposition));
-       g_return_if_fail (name != NULL);
-       g_return_if_fail (value != NULL);
-       
-       if ((param = g_hash_table_lookup (disposition->param_hash, name))) {
-               g_free (param->value);
-               param->value = g_strdup (value);
-       } else {
-               param = g_mime_param_new (name, value);
-               disposition->params = g_mime_param_append_param (disposition->params, param);
-               g_hash_table_insert (disposition->param_hash, param->name, param);
-       }
        
-       g_mime_event_emit (disposition->changed, NULL);
+       g_mime_param_list_set_parameter (disposition->params, name, value);
 }
 
 
@@ -309,9 +276,8 @@ g_mime_content_disposition_get_parameter (GMimeContentDisposition *disposition,
        GMimeParam *param;
        
        g_return_val_if_fail (GMIME_IS_CONTENT_DISPOSITION (disposition), NULL);
-       g_return_val_if_fail (name != NULL, NULL);
        
-       if (!(param = g_hash_table_lookup (disposition->param_hash, name)))
+       if (!(param = g_mime_param_list_get_parameter (disposition->params, name)))
                return NULL;
        
        return param->value;
@@ -350,8 +316,8 @@ g_mime_content_disposition_is_attachment (GMimeContentDisposition *disposition)
 char *
 g_mime_content_disposition_to_string (GMimeContentDisposition *disposition, gboolean fold)
 {
-       GString *string;
        char *header, *buf;
+       GString *string;
        
        g_return_val_if_fail (GMIME_IS_CONTENT_DISPOSITION (disposition), NULL);
        
@@ -359,7 +325,7 @@ g_mime_content_disposition_to_string (GMimeContentDisposition *disposition, gboo
        string = g_string_new ("Content-Disposition: ");
        
        g_string_append (string, disposition->disposition);
-       g_mime_param_write_to_string (disposition->params, fold, string);
+       g_mime_param_list_encode (disposition->params, fold, string);
        
        header = string->str;
        g_string_free (string, FALSE);
diff --git a/gmime/gmime-disposition.h b/gmime/gmime-disposition.h
index 9446c43..e5586b2 100644
--- a/gmime/gmime-disposition.h
+++ b/gmime/gmime-disposition.h
@@ -67,10 +67,9 @@ struct _GMimeContentDisposition {
        GObject parent_object;
        
        char *disposition;
-       GMimeParam *params;
+       GMimeParamList *params;
        
        /* < private > */
-       GHashTable *param_hash;
        gpointer changed;
 };
 
@@ -88,8 +87,7 @@ GMimeContentDisposition *g_mime_content_disposition_parse (GMimeParserOptions *o
 void g_mime_content_disposition_set_disposition (GMimeContentDisposition *disposition, const char *value);
 const char *g_mime_content_disposition_get_disposition (GMimeContentDisposition *disposition);
 
-void g_mime_content_disposition_set_params (GMimeContentDisposition *disposition, GMimeParam *params);
-const GMimeParam *g_mime_content_disposition_get_params (GMimeContentDisposition *disposition);
+GMimeParamList *g_mime_content_disposition_get_params (GMimeContentDisposition *disposition);
 
 void g_mime_content_disposition_set_parameter (GMimeContentDisposition *disposition,
                                               const char *name, const char *value);
diff --git a/gmime/gmime-object.c b/gmime/gmime-object.c
index caa1268..57e579c 100644
--- a/gmime/gmime-object.c
+++ b/gmime/gmime-object.c
@@ -322,7 +322,7 @@ write_content_type (GMimeParserOptions *options, GMimeStream *stream, const char
        g_string_append (out, val);
        g_free (val);
        
-       g_mime_param_write_to_string (content_type->params, TRUE, out);
+       g_mime_param_list_encode (content_type->params, TRUE, out);
        g_object_unref (content_type);
        
        nwritten = g_mime_stream_write (stream, out->str, out->len);
@@ -352,9 +352,8 @@ _g_mime_object_unblock_header_list_changed (GMimeObject *object)
 static void
 content_type_changed (GMimeContentType *content_type, gpointer args, GMimeObject *object)
 {
-       GMimeParam *params;
        GString *string;
-       char *type, *p;
+       char *type, *str;
        
        string = g_string_new ("Content-Type: ");
        
@@ -362,17 +361,15 @@ content_type_changed (GMimeContentType *content_type, gpointer args, GMimeObject
        g_string_append (string, type);
        g_free (type);
        
-       if ((params = content_type->params))
-               g_mime_param_write_to_string (params, FALSE, string);
+       g_mime_param_list_encode (content_type->params, FALSE, string);
        
-       p = string->str;
-       g_string_free (string, FALSE);
+       str = g_string_free (string, FALSE);
        
-       type = p + strlen ("Content-Type: ");
+       type = str + strlen ("Content-Type: ");
        _g_mime_object_block_header_list_changed (object);
        g_mime_header_list_set (object->headers, "Content-Type", type);
        _g_mime_object_unblock_header_list_changed (object);
-       g_free (p);
+       g_free (str);
 }
 
 static ssize_t
@@ -388,7 +385,7 @@ write_disposition (GMimeParserOptions *options, GMimeStream *stream, const char
        disposition = g_mime_content_disposition_parse (options, value);
        g_string_append (out, disposition->disposition);
        
-       g_mime_param_write_to_string (disposition->params, TRUE, out);
+       g_mime_param_list_encode (disposition->params, TRUE, out);
        g_object_unref (disposition);
        
        nwritten = g_mime_stream_write (stream, out->str, out->len);
diff --git a/gmime/gmime-param.c b/gmime/gmime-param.c
index c678eec..c0beaa4 100644
--- a/gmime/gmime-param.c
+++ b/gmime/gmime-param.c
@@ -31,6 +31,7 @@
 #include "gmime-param.h"
 #include "gmime-common.h"
 #include "gmime-events.h"
+#include "gmime-internal.h"
 #include "gmime-table-private.h"
 #include "gmime-parse-utils.h"
 #include "gmime-iconv-utils.h"
@@ -64,6 +65,24 @@ static unsigned char tohex[16] = {
 };
 
 
+static GMimeParam *
+g_mime_param_new_internal (void)
+{
+       GMimeParam *param;
+       
+       param = g_slice_new (GMimeParam);
+       
+       param->changed = g_mime_event_new (param);
+       param->method = GMIME_PARAM_ENCODING_METHOD_DEFAULT;
+       param->charset = NULL;
+       param->value = NULL;
+       param->name = NULL;
+       param->lang = NULL;
+       
+       return param;
+}
+
+
 /**
  * g_mime_param_new:
  * @name: parameter name
@@ -73,20 +92,671 @@ static unsigned char tohex[16] = {
  *
  * Returns: a new paramter structure.
  **/
-GMimeParam *
+static GMimeParam *
 g_mime_param_new (const char *name, const char *value)
 {
        GMimeParam *param;
        
-       param = g_new (GMimeParam, 1);
-       
-       param->next = NULL;
-       param->name = g_strdup (name);
+       param = g_mime_param_new_internal ();
        param->value = g_strdup (value);
+       param->name = g_strdup (name);
        
        return param;
 }
 
+
+/**
+ * g_mime_param_free:
+ * @param: a #GMimeParam
+ *
+ * Releases all memory used by this mime param back to the Operating
+ * System.
+ **/
+static void
+g_mime_param_free (GMimeParam *param)
+{
+       g_return_if_fail (param != NULL);
+       
+       g_mime_event_free (param->changed);
+       g_free (param->charset);
+       g_free (param->value);
+       g_free (param->name);
+       g_free (param->lang);
+       
+       g_slice_free (GMimeParam, param);
+}
+
+
+/**
+ * g_mime_param_get_name:
+ * @param: a #GMimeParam
+ *
+ * Gets the name of the parameter.
+ *
+ * Returns: the name of the parameter.
+ **/
+const char *
+g_mime_param_get_name (GMimeParam *param)
+{
+       g_return_val_if_fail (param != NULL, NULL);
+       
+       return param->name;
+}
+
+
+/**
+ * g_mime_param_get_value:
+ * @param: a #GMimeParam
+ *
+ * Gets the value of the parameter.
+ *
+ * Returns: the value of the parameter.
+ **/
+const char *
+g_mime_param_get_value (GMimeParam *param)
+{
+       g_return_val_if_fail (param != NULL, NULL);
+       
+       return param->value;
+}
+
+
+/**
+ * g_mime_param_set_value:
+ * @param: a #GMimeParam
+ * @value: the new parameter value
+ *
+ * Sets the parameter value to @value.
+ **/
+void
+g_mime_param_set_value (GMimeParam *param, const char *value)
+{
+       g_return_if_fail (param != NULL);
+       g_return_if_fail (value != NULL);
+       
+       g_free (param->value);
+       param->value = g_strdup (value);
+       
+       g_mime_event_emit (param->changed, NULL);
+}
+
+
+/**
+ * g_mime_param_get_charset:
+ * @param: a #GMimeParam
+ *
+ * Gets the charset used for encoding the parameter.
+ *
+ * Returns: the charset used for encoding the parameter.
+ **/
+const char *
+g_mime_param_get_charset (GMimeParam *param)
+{
+       g_return_val_if_fail (param != NULL, NULL);
+       
+       return param->charset;
+}
+
+
+/**
+ * g_mime_param_set_charset:
+ * @param: a #GMimeParam
+ * @charset: the charset or %NULL to use the default
+ *
+ * Sets the parameter charset used for encoding the value.
+ **/
+void
+g_mime_param_set_charset (GMimeParam *param, const char *charset)
+{
+       g_return_if_fail (param != NULL);
+       
+       g_free (param->charset);
+       param->charset = charset ? g_strdup (charset) : NULL;
+       
+       g_mime_event_emit (param->changed, NULL);
+}
+
+
+/**
+ * g_mime_param_get_lang:
+ * @param: a #GMimeParam
+ *
+ * Gets the language specifier used for encoding the parameter.
+ *
+ * Returns: the language specifier used for encoding the parameter.
+ **/
+const char *
+g_mime_param_get_lang (GMimeParam *param)
+{
+       g_return_val_if_fail (param != NULL, NULL);
+       
+       return param->lang;
+}
+
+
+/**
+ * g_mime_param_set_lang:
+ * @param: a #GMimeParam
+ * @lang: the language specifier
+ *
+ * Sets the parameter language specifier used for encoding the value.
+ **/
+void
+g_mime_param_set_lang (GMimeParam *param, const char *lang)
+{
+       g_return_if_fail (param != NULL);
+       
+       g_free (param->lang);
+       param->lang = lang ? g_strdup (lang) : NULL;
+       
+       g_mime_event_emit (param->changed, NULL);
+}
+
+
+/**
+ * g_mime_param_get_encoding_method:
+ * @param: a #GMimeParam
+ *
+ * Gets the encoding method used for encoding the parameter.
+ *
+ * Returns: the encoding method used for encoding the parameter.
+ **/
+GMimeParamEncodingMethod
+g_mime_param_get_encoding_method (GMimeParam *param)
+{
+       g_return_val_if_fail (param != NULL, GMIME_PARAM_ENCODING_METHOD_DEFAULT);
+       
+       return param->method;
+}
+
+
+/**
+ * g_mime_param_set_encoding_method:
+ * @param: a #GMimeParam
+ * @method: a #GMimeParamEncodingMethod
+ *
+ * Sets the encoding method used for encoding the value.
+ **/
+void
+g_mime_param_set_encoding_method (GMimeParam *param, GMimeParamEncodingMethod method)
+{
+       g_return_if_fail (param != NULL);
+       
+       param->method = method;
+       
+       g_mime_event_emit (param->changed, NULL);
+}
+
+
+static void
+param_changed (GMimeParam *param, gpointer args, GMimeParamList *list)
+{
+       g_mime_event_emit (list->changed, NULL);
+}
+
+
+/**
+ * g_mime_param_list_new:
+ *
+ * Creates a new Content-Type or Content-Disposition parameter list.
+ *
+ * Returns: a new #GMimeParamList.
+ **/
+GMimeParamList *
+g_mime_param_list_new (void)
+{
+       GMimeParamList *list;
+       
+       list = g_slice_new (GMimeParamList);
+       list->changed = g_mime_event_new (list);
+       list->params = g_ptr_array_new ();
+       
+       return list;
+}
+
+
+/**
+ * g_mime_param_list_free:
+ * @list: a #GMimeParamList
+ *
+ * Frees the #GMimeParamList.
+ **/
+void
+g_mime_param_list_free (GMimeParamList *list)
+{
+       guint i;
+       
+       g_return_if_fail (list != NULL);
+       
+       for (i = 0; i < list->params->len; i++)
+               g_mime_param_free (list->params->pdata[i]);
+       
+       g_ptr_array_free (list->params, TRUE);
+       g_mime_event_free (list->changed);
+       
+       g_slice_free (GMimeParamList, list);
+}
+
+
+/**
+ * g_mime_param_list_length:
+ * @list: a #GMimeParamList
+ *
+ * Gets the length of the list.
+ *
+ * Returns: the number of #GMimeParam items in the list.
+ **/
+int
+g_mime_param_list_length (GMimeParamList *list)
+{
+       g_return_val_if_fail (list != NULL, -1);
+       
+       return list->params->len;
+}
+
+
+/**
+ * g_mime_param_list_clear:
+ * @list: a #GMimeParamList
+ *
+ * Clears the list of parameters.
+ **/
+void
+g_mime_param_list_clear (GMimeParamList *list)
+{
+       guint i;
+       
+       g_return_if_fail (list != NULL);
+       
+       for (i = 0; i < list->params->len; i++)
+               g_mime_param_free (list->params->pdata[i]);
+       
+       g_ptr_array_set_size (list->params, 0);
+       
+       g_mime_event_emit (list->changed, NULL);
+}
+
+
+/**
+ * g_mime_param_list_add:
+ * @list: a #GMimeParamList
+ * @param: a #GMimeParam
+ *
+ * Adds a #GMimeParam to the #GMimeParamList.
+ *
+ * Returns: the index of the added #GMimeParam.
+ **/
+static void
+g_mime_param_list_add (GMimeParamList *list, GMimeParam *param)
+{
+       g_mime_event_add (param->changed, (GMimeEventCallback) param_changed, list);
+       g_ptr_array_add (list->params, param);
+}
+
+
+/**
+ * g_mime_param_list_set_parameter:
+ * @list: a #GMimeParamList
+ * @name: The name of the parameter
+ * @value: The parameter value
+ *
+ * Sets the specified parameter to @value.
+ **/
+void
+g_mime_param_list_set_parameter (GMimeParamList *list, const char *name, const char *value)
+{
+       GMimeParam *param;
+       guint i;
+       
+       g_return_if_fail (list != NULL);
+       g_return_if_fail (name != NULL);
+       g_return_if_fail (value != NULL);
+       
+       for (i = 0; i < list->params->len; i++) {
+               param = list->params->pdata[i];
+               
+               if (!g_ascii_strcasecmp (param->name, name)) {
+                       g_mime_param_set_value (param, value);
+                       return;
+               }
+       }
+       
+       param = g_mime_param_new (name, value);
+       g_mime_param_list_add (list, param);
+       
+       g_mime_event_emit (list->changed, NULL);
+}
+
+
+/**
+ * g_mime_param_list_get_parameter:
+ * @list: list: a #GMimeParamList
+ * @name: the name of the parameter
+ *
+ * Gets the #GMimeParam with the given @name.
+ *
+ * Returns: the requested #GMimeParam.
+ **/
+GMimeParam *
+g_mime_param_list_get_parameter (GMimeParamList *list, const char *name)
+{
+       GMimeParam *param;
+       guint i;
+       
+       g_return_val_if_fail (list != NULL, NULL);
+       g_return_val_if_fail (name != NULL, NULL);
+       
+       for (i = 0; i < list->params->len; i++) {
+               param = list->params->pdata[i];
+               
+               if (!g_ascii_strcasecmp (param->name, name))
+                       return param;
+       }
+       
+       return NULL;
+}
+
+
+/**
+ * g_mime_param_list_get_parameter_at:
+ * @list: a #GMimeParamList
+ * @index: the index of the requested parameter
+ *
+ * Gets the #GMimeParam at the specified @index.
+ *
+ * Returns: the #GMimeParam at the specified index.
+ **/
+GMimeParam *
+g_mime_param_list_get_parameter_at (GMimeParamList *list, int index)
+{
+       g_return_val_if_fail (list != NULL, NULL);
+       g_return_val_if_fail (index >= 0, NULL);
+       
+       if ((guint) index >= list->params->len)
+               return NULL;
+       
+       return list->params->pdata[index];
+}
+
+
+/**
+ * g_mime_param_list_remove:
+ * @list: a #GMimeParamList
+ * @name: the name of the parameter
+ *
+ * Removes a parameter from the #GMimeParamList.
+ *
+ * Returns: %TRUE if the specified parameter was removed or %FALSE otherwise.
+ **/
+gboolean
+g_mime_param_list_remove (GMimeParamList *list, const char *name)
+{
+       GMimeParam *param;
+       guint i;
+       
+       g_return_val_if_fail (list != NULL, FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+       
+       for (i = 0; i < list->params->len; i++) {
+               param = list->params->pdata[i];
+               
+               if (!g_ascii_strcasecmp (param->name, name)) {
+                       g_ptr_array_remove_index (list->params, i);
+                       g_mime_param_free (param);
+                       return TRUE;
+               }
+       }
+       
+       return FALSE;
+}
+
+
+/**
+ * g_mime_param_list_remove_at:
+ * @list: a #GMimeParamList
+ * @index: index of the param to remove
+ *
+ * Removes a #GMimeParam from the #GMimeParamList at the specified index.
+ *
+ * Returns: %TRUE if a #GMimeParam was removed or %FALSE otherwise.
+ **/
+gboolean
+g_mime_param_list_remove_at (GMimeParamList *list, int index)
+{
+       GMimeParam *param;
+       
+       g_return_val_if_fail (list != NULL, FALSE);
+       g_return_val_if_fail (index >= 0, FALSE);
+       
+       if ((guint) index >= list->params->len)
+               return FALSE;
+       
+       param = list->params->pdata[index];
+       g_ptr_array_remove_index (list->params, index);
+       g_mime_param_free (param);
+       
+       return TRUE;
+}
+
+
+/* FIXME: I wrote this in a quick & dirty fasion - it may not be 100% correct */
+static char *
+encode_param (GMimeParam *param, gboolean *encoded)
+{
+       register const unsigned char *inptr = (const unsigned char *) param->value;
+       const unsigned char *start = inptr;
+       const char *charset = NULL;
+       iconv_t cd = (iconv_t) -1;
+       char *outbuf = NULL;
+       unsigned char c;
+       char *outstr;
+       GString *str;
+       
+       *encoded = FALSE;
+       
+       while (*inptr && ((inptr - start) < GMIME_FOLD_LEN)) {
+               if (*inptr > 127)
+                       break;
+               inptr++;
+       }
+       
+       if (*inptr == '\0')
+               return g_strdup (param->value);
+       
+       if (!param->charset) {
+               if (*inptr > 127)
+                       charset = g_mime_charset_best (param->value, strlen (param->value));
+               
+               if (!charset)
+                       charset = "iso-8859-1";
+       } else {
+               charset = param->charset;
+       }
+       
+       if (g_ascii_strcasecmp (charset, "UTF-8") != 0)
+               cd = g_mime_iconv_open (charset, "UTF-8");
+       
+       if (cd != (iconv_t) -1) {
+               outbuf = g_mime_iconv_strdup (cd, param->value);
+               g_mime_iconv_close (cd);
+               if (outbuf == NULL) {
+                       charset = "UTF-8";
+                       inptr = start;
+               } else {
+                       inptr = (const unsigned char *) outbuf;
+               }
+       } else {
+               charset = "UTF-8";
+               inptr = start;
+       }
+       
+       /* FIXME: use rfc2047 encoding if requested... */
+       str = g_string_new (charset);
+       g_string_append_c (str, '\'');
+       if (param->lang)
+               g_string_append (str, param->lang);
+       g_string_append_c (str, '\'');
+       
+       while ((c = *inptr++)) {
+               if (!is_attrchar (c))
+                       g_string_append_printf (str, "%%%c%c", tohex[(c >> 4) & 0xf], tohex[c & 0xf]);
+               else
+                       g_string_append_c (str, c);
+       }
+       
+       g_free (outbuf);
+       
+       outstr = g_string_free (str, FALSE);
+       *encoded = TRUE;
+       
+       return outstr;
+}
+
+static void
+g_string_append_len_quoted (GString *str, const char *text, size_t len)
+{
+       register const char *inptr = text;
+       const char *inend = text + len;
+       
+       g_string_append_c (str, '"');
+       
+       while (inptr < inend) {
+               if ((*inptr == '"') || *inptr == '\\')
+                       g_string_append_c (str, '\\');
+               
+               g_string_append_c (str, *inptr);
+               
+               inptr++;
+       }
+       
+       g_string_append_c (str, '"');
+}
+
+
+/**
+ * g_mime_param_list_encode:
+ * @list: a #GMimeParamList
+ * @fold: %TRUE if the parameter list should be folded; otherwise, %FALSE
+ * @str: the output string buffer
+ *
+ * Encodes the parameter list into @str, folding lines if required.
+ **/
+void
+g_mime_param_list_encode (GMimeParamList *list, gboolean fold, GString *str)
+{
+       guint count, i;
+       int used;
+       
+       g_return_if_fail (list != NULL);
+       g_return_if_fail (str != NULL);
+       
+       count = list->params->len;
+       used = str->len;
+       
+       for (i = 0; i < count; i++) {
+               gboolean encoded = FALSE;
+               int here = str->len;
+               size_t nlen, vlen;
+               GMimeParam *param;
+               int quote = 0;
+               char *value;
+               
+               param = (GMimeParam *) list->params->pdata[i];
+               
+               if (!param->value)
+                       continue;
+               
+               if (!(value = encode_param (param, &encoded))) {
+                       w(g_warning ("appending parameter %s=%s violates rfc2184",
+                                    param->name, param->value));
+                       value = g_strdup (param->value);
+               }
+               
+               if (!encoded) {
+                       char *ch;
+                       
+                       for (ch = value; *ch; ch++) {
+                               if (!is_attrchar (*ch) || is_lwsp (*ch))
+                                       quote++;
+                       }
+               }
+               
+               nlen = strlen (param->name);
+               vlen = strlen (value);
+               
+               if (fold && (used + nlen + vlen + quote > GMIME_FOLD_LEN - 2)) {
+                       g_string_append (str, ";\n\t");
+                       here = str->len;
+                       used = 1;
+               } else {
+                       g_string_append (str, "; ");
+                       here = str->len;
+                       used += 2;
+               }
+               
+               if (nlen + vlen + quote > GMIME_FOLD_LEN - 2) {
+                       /* we need to do special rfc2184 parameter wrapping */
+                       size_t maxlen = GMIME_FOLD_LEN - (nlen + 6);
+                       char *inptr, *inend;
+                       int i = 0;
+                       
+                       inptr = value;
+                       inend = value + vlen;
+                       
+                       while (inptr < inend) {
+                               char *ptr = inptr + MIN ((size_t) (inend - inptr), maxlen);
+                               
+                               if (encoded && ptr < inend) {
+                                       /* be careful not to break an encoded char (ie %20) */
+                                       char *q = ptr;
+                                       int j = 2;
+                                       
+                                       for ( ; j > 0 && q > inptr && *q != '%'; j--, q--);
+                                       if (*q == '%')
+                                               ptr = q;
+                               }
+                               
+                               if (i != 0) {
+                                       if (fold)
+                                               g_string_append (str, ";\n\t");
+                                       else
+                                               g_string_append (str, "; ");
+                                       
+                                       here = str->len;
+                                       used = 1;
+                               }
+                               
+                               g_string_append_printf (str, "%s*%d%s=", param->name,
+                                                       i++, encoded ? "*" : "");
+                               
+                               if (encoded || !quote)
+                                       g_string_append_len (str, inptr, (size_t) (ptr - inptr));
+                               else
+                                       g_string_append_len_quoted (str, inptr, (size_t) (ptr - inptr));
+                               
+                               used += (str->len - here);
+                               
+                               inptr = ptr;
+                       }
+               } else {
+                       g_string_append_printf (str, "%s%s=", param->name, encoded ? "*" : "");
+                       
+                       if (encoded || !quote)
+                               g_string_append_len (str, value, vlen);
+                       else
+                               g_string_append_len_quoted (str, value, vlen);
+                       
+                       used += (str->len - here);
+               }
+               
+               g_free (value);
+       }
+       
+       if (fold)
+               g_string_append_c (str, '\n');
+}
+
+
 #define INT_OVERFLOW(x,d) (((x) > (INT_MAX / 10)) || ((x) == (INT_MAX / 10) && (d) > (INT_MAX % 10)))
 
 static int
@@ -239,16 +909,16 @@ decode_param_token (const char **in)
 }
 
 static gboolean
-decode_rfc2184_param (const char **in, char **paramp, int *part, gboolean *encoded)
+decode_rfc2184_param (const char **in, char **namep, int *part, gboolean *encoded)
 {
        gboolean is_rfc2184 = FALSE;
        const char *inptr = *in;
-       char *param;
+       char *name;
        
        *encoded = FALSE;
        *part = -1;
        
-       param = decode_param_token (&inptr);
+       name = decode_param_token (&inptr);
        
        skip_cfws (&inptr);
        
@@ -274,24 +944,23 @@ decode_rfc2184_param (const char **in, char **paramp, int *part, gboolean *encod
                }
        }
        
-       if (paramp)
-               *paramp = param;
+       *namep = name;
        
-       if (param)
+       if (name)
                *in = inptr;
        
        return is_rfc2184;
 }
 
 static gboolean
-decode_param (GMimeParserOptions *options, const char **in, char **paramp, char **valuep, int *id, gboolean 
*encoded)
+decode_param (GMimeParserOptions *options, const char **in, char **namep, char **valuep, int *id, gboolean 
*encoded)
 {
        gboolean is_rfc2184 = FALSE;
        const char *inptr = *in;
-       char *param, *value = NULL;
+       char *name, *value = NULL;
        char *val;
        
-       is_rfc2184 = decode_rfc2184_param (&inptr, &param, id, encoded);
+       is_rfc2184 = decode_rfc2184_param (&inptr, &name, id, encoded);
        
        if (*inptr == '=') {
                inptr++;
@@ -320,20 +989,20 @@ decode_param (GMimeParserOptions *options, const char **in, char **paramp, char
                                        value = val;
                                } else {
                                        d(g_warning ("Failed to convert %s param value (\"%s\") to UTF-8: %s",
-                                                    param, value, g_strerror (errno)));
+                                                    name, value, g_strerror (errno)));
                                }
                        }
                }
        }
        
-       if (param && value) {
-               *paramp = param;
+       if (name && value) {
                *valuep = value;
+               *namep = name;
                *in = inptr;
                return TRUE;
        } else {
-               g_free (param);
                g_free (value);
+               g_free (name);
                return FALSE;
        }
 }
@@ -520,30 +1189,28 @@ rfc2184_param_new (char *name, char *value, int id, gboolean encoded)
                g_free (value);
        }
        
-       rfc2184->param = g_new (GMimeParam, 1);
-       rfc2184->param->next = NULL;
+       rfc2184->param = g_mime_param_new_internal ();
        rfc2184->param->name = name;
-       rfc2184->param->value = NULL;
        
        return rfc2184;
 }
 
-static GMimeParam *
+static GMimeParamList *
 decode_param_list (GMimeParserOptions *options, const char *in)
 {
        struct _rfc2184_param *rfc2184, *list, *t;
-       GMimeParam *param, *params, *tail;
+       char *name, *value, *charset;
        struct _rfc2184_part *part;
        GHashTable *rfc2184_hash;
        const char *inptr = in;
-       char *name, *value;
+       GMimeParamList *params;
+       GMimeParam *param;
        gboolean encoded;
        GString *gvalue;
        guint i;
        int id;
        
-       params = NULL;
-       tail = (GMimeParam *) &params;
+       params = g_mime_param_list_new ();
        
        list = NULL;
        t = (struct _rfc2184_param *) &list;
@@ -571,16 +1238,13 @@ decode_param_list (GMimeParserOptions *options, const char *in)
                                t = rfc2184;
                                
                                g_hash_table_insert (rfc2184_hash, param->name, rfc2184);
-                               
-                               tail->next = param;
-                               tail = param;
+                               g_mime_param_list_add (params, param);
                        } else {
                                rfc2184_param_add_part (rfc2184, value, id, encoded);
                                g_free (name);
                        }
                } else {
-                       param = g_new (GMimeParam, 1);
-                       param->next = NULL;
+                       param = g_mime_param_new_internal ();
                        param->name = name;
                        
                        if (encoded) {
@@ -592,8 +1256,7 @@ decode_param_list (GMimeParserOptions *options, const char *in)
                                param->value = value;
                        }
                        
-                       tail->next = param;
-                       tail = param;
+                       g_mime_param_list_add (params, param);
                }
                
                skip_cfws (&inptr);
@@ -619,9 +1282,10 @@ decode_param_list (GMimeParserOptions *options, const char *in)
                g_ptr_array_free (rfc2184->parts, TRUE);
                
                param->value = charset_convert (rfc2184->charset, gvalue->str, gvalue->len);
-               g_string_free (gvalue, FALSE);
+               param->charset = rfc2184->charset ? g_strdup (rfc2184->charset) : NULL;
+               param->lang = rfc2184->lang;
                
-               g_free (rfc2184->lang);
+               g_string_free (gvalue, FALSE);
                g_free (rfc2184);
                rfc2184 = t;
        }
@@ -631,666 +1295,18 @@ decode_param_list (GMimeParserOptions *options, const char *in)
 
 
 /**
- * g_mime_param_parse:
+ * g_mime_param_list_parse:
  * @options: a #GMimeParserOptions
- * @str: input string
+ * @str: a string to parse
  *
- * Parses the input stringinto a parameter list.
+ * Parses the input string into a parameter list.
  *
- * Returns: a #GMimeParam linked list based on @text.
+ * Returns: a #GMimeParamList.
  **/
-GMimeParam *
-g_mime_param_parse (GMimeParserOptions *options, const char *str)
+GMimeParamList *
+g_mime_param_list_parse (GMimeParserOptions *options, const char *str)
 {
        g_return_val_if_fail (str != NULL, NULL);
        
        return decode_param_list (options, str);
 }
-
-
-/**
- * g_mime_param_free:
- * @param: a #GMimeParam
- *
- * Releases all memory used by this mime param back to the Operating
- * System.
- **/
-void
-g_mime_param_free (GMimeParam *param)
-{
-       GMimeParam *next;
-       
-       while (param) {
-               next = param->next;
-               g_free (param->name);
-               g_free (param->value);
-               g_free (param);
-               param = next;
-       }
-}
-
-
-/**
- * g_mime_param_next:
- * @param: a #GMimeParam node
- *
- * Gets the next #GMimeParam node in the list.
- *
- * Returns: the next #GMimeParam node in the list.
- **/
-const GMimeParam *
-g_mime_param_next (const GMimeParam *param)
-{
-       g_return_val_if_fail (param != NULL, NULL);
-       
-       return param->next;
-}
-
-
-/**
- * g_mime_param_get_name:
- * @param: a #GMimeParam
- *
- * Gets the name of the parameter.
- *
- * Returns: the name of the parameter.
- **/
-const char *
-g_mime_param_get_name (const GMimeParam *param)
-{
-       g_return_val_if_fail (param != NULL, NULL);
-       
-       return param->name;
-}
-
-
-/**
- * g_mime_param_get_value:
- * @param: a #GMimeParam
- *
- * Gets the value of the parameter.
- *
- * Returns: the value of the parameter.
- **/
-const char *
-g_mime_param_get_value (const GMimeParam *param)
-{
-       g_return_val_if_fail (param != NULL, NULL);
-       
-       return param->value;
-}
-
-
-/**
- * g_mime_param_append:
- * @params: param list
- * @name: new param name
- * @value: new param value
- *
- * Appends a new parameter with name @name and value @value to the
- * parameter list @params.
- *
- * Returns: a param list with the new param of name @name and value
- * @value appended to the list of params @params.
- **/
-GMimeParam *
-g_mime_param_append (GMimeParam *params, const char *name, const char *value)
-{
-       GMimeParam *param, *p;
-       
-       g_return_val_if_fail (name != NULL, params);
-       g_return_val_if_fail (value != NULL, params);
-       
-       param = g_mime_param_new (name, value);
-       if (params) {
-               p = params;
-               while (p->next)
-                       p = p->next;
-               p->next = param;
-       } else
-               params = param;
-       
-       return params;
-}
-
-
-/**
- * g_mime_param_append_param:
- * @params: param list
- * @param: param to append
- *
- * Appends @param to the param list @params.
- *
- * Returns: a param list with the new param @param appended to the list
- * of params @params.
- **/
-GMimeParam *
-g_mime_param_append_param (GMimeParam *params, GMimeParam *param)
-{
-       GMimeParam *p;
-       
-       g_return_val_if_fail (param != NULL, params);
-       
-       if (params) {
-               p = params;
-               while (p->next)
-                       p = p->next;
-               p->next = param;
-       } else
-               params = param;
-       
-       return params;
-}
-
-/* FIXME: I wrote this in a quick & dirty fasion - it may not be 100% correct */
-static char *
-encode_param (const char *in, gboolean *encoded)
-{
-       register const unsigned char *inptr = (const unsigned char *) in;
-       const unsigned char *instart = inptr;
-       iconv_t cd = (iconv_t) -1;
-       const char *charset = NULL;
-       char *outbuf = NULL;
-       unsigned char c;
-       char *outstr;
-       GString *out;
-       
-       *encoded = FALSE;
-       
-       while (*inptr && ((inptr - instart) < GMIME_FOLD_LEN)) {
-               if (*inptr > 127)
-                       break;
-               inptr++;
-       }
-       
-       if (*inptr == '\0')
-               return g_strdup (in);
-       
-       if (*inptr > 127)
-               charset = g_mime_charset_best (in, strlen (in));
-       
-       if (!charset)
-               charset = "iso-8859-1";
-       
-       if (g_ascii_strcasecmp (charset, "UTF-8") != 0)
-               cd = g_mime_iconv_open (charset, "UTF-8");
-       
-       if (cd != (iconv_t) -1) {
-               outbuf = g_mime_iconv_strdup (cd, in);
-               g_mime_iconv_close (cd);
-               if (outbuf == NULL) {
-                       charset = "UTF-8";
-                       inptr = instart;
-               } else {
-                       inptr = (const unsigned char *) outbuf;
-               }
-       } else {
-               charset = "UTF-8";
-               inptr = instart;
-       }
-       
-       /* FIXME: set the 'language' as well, assuming we can get that info...? */
-       out = g_string_new ("");
-       g_string_append_printf (out, "%s''", charset);
-       
-       while ((c = *inptr++)) {
-               if (!is_attrchar (c))
-                       g_string_append_printf (out, "%%%c%c", tohex[(c >> 4) & 0xf], tohex[c & 0xf]);
-               else
-                       g_string_append_c (out, c);
-       }
-       
-       g_free (outbuf);
-       
-       outstr = out->str;
-       g_string_free (out, FALSE);
-       *encoded = TRUE;
-       
-       return outstr;
-}
-
-static void
-g_string_append_len_quoted (GString *out, const char *in, size_t len)
-{
-       register const char *inptr;
-       const char *inend;
-       
-       g_string_append_c (out, '"');
-       
-       inptr = in;
-       inend = in + len;
-       
-       while (inptr < inend) {
-               if ((*inptr == '"') || *inptr == '\\')
-                       g_string_append_c (out, '\\');
-               
-               g_string_append_c (out, *inptr);
-               
-               inptr++;
-       }
-       
-       g_string_append_c (out, '"');
-}
-
-static void
-param_list_format (GString *out, const GMimeParam *param, gboolean fold)
-{
-       int used = out->len;
-       
-       while (param) {
-               gboolean encoded = FALSE;
-               int here = out->len;
-               size_t nlen, vlen;
-               int quote = 0;
-               char *value;
-               
-               if (!param->value) {
-                       param = param->next;
-                       continue;
-               }
-               
-               if (!(value = encode_param (param->value, &encoded))) {
-                       w(g_warning ("appending parameter %s=%s violates rfc2184",
-                                    param->name, param->value));
-                       value = g_strdup (param->value);
-               }
-               
-               if (!encoded) {
-                       char *ch;
-                       
-                       for (ch = value; *ch; ch++) {
-                               if (!is_attrchar (*ch) || is_lwsp (*ch))
-                                       quote++;
-                       }
-               }
-               
-               nlen = strlen (param->name);
-               vlen = strlen (value);
-               
-               if (fold && (used + nlen + vlen + quote > GMIME_FOLD_LEN - 2)) {
-                       g_string_append (out, ";\n\t");
-                       here = out->len;
-                       used = 1;
-               } else {
-                       g_string_append (out, "; ");
-                       here = out->len;
-                       used += 2;
-               }
-               
-               if (nlen + vlen + quote > GMIME_FOLD_LEN - 2) {
-                       /* we need to do special rfc2184 parameter wrapping */
-                       size_t maxlen = GMIME_FOLD_LEN - (nlen + 6);
-                       char *inptr, *inend;
-                       int i = 0;
-                       
-                       inptr = value;
-                       inend = value + vlen;
-                       
-                       while (inptr < inend) {
-                               char *ptr = inptr + MIN ((size_t) (inend - inptr), maxlen);
-                               
-                               if (encoded && ptr < inend) {
-                                       /* be careful not to break an encoded char (ie %20) */
-                                       char *q = ptr;
-                                       int j = 2;
-                                       
-                                       for ( ; j > 0 && q > inptr && *q != '%'; j--, q--);
-                                       if (*q == '%')
-                                               ptr = q;
-                               }
-                               
-                               if (i != 0) {
-                                       if (fold)
-                                               g_string_append (out, ";\n\t");
-                                       else
-                                               g_string_append (out, "; ");
-                                       
-                                       here = out->len;
-                                       used = 1;
-                               }
-                               
-                               g_string_append_printf (out, "%s*%d%s=", param->name,
-                                                       i++, encoded ? "*" : "");
-                               
-                               if (encoded || !quote)
-                                       g_string_append_len (out, inptr, (size_t) (ptr - inptr));
-                               else
-                                       g_string_append_len_quoted (out, inptr, (size_t) (ptr - inptr));
-                               
-                               used += (out->len - here);
-                               
-                               inptr = ptr;
-                       }
-               } else {
-                       g_string_append_printf (out, "%s%s=", param->name, encoded ? "*" : "");
-                       
-                       if (encoded || !quote)
-                               g_string_append_len (out, value, vlen);
-                       else
-                               g_string_append_len_quoted (out, value, vlen);
-                       
-                       used += (out->len - here);
-               }
-               
-               g_free (value);
-               
-               param = param->next;
-       }
-       
-       if (fold)
-               g_string_append_c (out, '\n');
-}
-
-
-/**
- * g_mime_param_write_to_string:
- * @param: MIME Param list
- * @fold: specifies whether or not to fold headers
- * @str: output string
- *
- * Assumes the output string contains only the Content-* header and
- * it's immediate value.
- *
- * Writes the params out to the string @string.
- **/
-void
-g_mime_param_write_to_string (const GMimeParam *param, gboolean fold, GString *str)
-{
-       g_return_if_fail (str != NULL);
-       
-       param_list_format (str, param, fold);
-}
-
-
-/**
- * g_mime_param_list_new:
- *
- * Creates a new Content-Type or Content-Disposition parameter list.
- *
- * Returns: a new #GMimeParamList.
- **/
-GMimeParamList *
-g_mime_param_list_new (void)
-{
-       GMimeParamList *list;
-       
-       list = g_slice_new (GMimeParamList);
-       list->hash = g_hash_table_new_full (g_mime_strcase_hash, g_mime_strcase_equal, NULL, NULL);
-       list->changed = g_mime_event_new (list);
-       list->params = g_ptr_array_new ();
-       
-       return list;
-}
-
-
-/**
- * g_mime_param_list_free:
- * @list: a #GMimeParamList
- *
- * Frees the #GMimeParamList.
- **/
-void
-g_mime_param_list_free (GMimeParamList *list)
-{
-       guint i;
-       
-       g_return_if_fail (list != NULL);
-       
-       for (i = 0; i < list->params->len; i++)
-               g_mime_param_free (list->params->pdata[i]);
-       
-       g_ptr_array_free (list->params, TRUE);
-       g_hash_table_destroy (list->hash);
-       g_mime_event_free (list->changed);
-       
-       g_slice_free (GMimeParamList, list);
-}
-
-
-/**
- * g_mime_param_list_length:
- * @list: a #GMimeParamList
- *
- * Gets the length of the list.
- *
- * Returns: the number of #GMimeParam items in the list.
- **/
-int
-g_mime_param_list_length (GMimeParamList *list)
-{
-       g_return_val_if_fail (list != NULL, -1);
-       
-       return list->params->len;
-}
-
-
-/**
- * g_mime_param_list_clear:
- * @list: a #GMimeParamList
- *
- * Clears the list of parameters.
- **/
-void
-g_mime_param_list_clear (GMimeParamList *list)
-{
-       guint i;
-       
-       g_return_if_fail (list != NULL);
-       
-       for (i = 0; i < list->params->len; i++)
-               g_mime_param_free (list->params->pdata[i]);
-       
-       g_ptr_array_set_size (list->params, 0);
-}
-
-
-/**
- * g_mime_param_list_add:
- * @list: a #GMimeParamList
- * @param: a #GMimeParam
- *
- * Adds a #GMimeParam to the #GMimeParamList.
- *
- * Returns: the index of the added #GMimeParam.
- **/
-int
-g_mime_param_list_add (GMimeParamList *list, GMimeParam *param)
-{
-       int index;
-       
-       g_return_val_if_fail (param != NULL, -1);
-       g_return_val_if_fail (list != NULL, -1);
-       
-       index = list->params->len;
-       g_ptr_array_add (list->params, param);
-       
-       return index;
-}
-
-
-/**
- * g_mime_param_list_insert:
- * @list: a #GMimeParamList
- * @index: index to insert at
- * @param: a #GMimeParam
- *
- * Inserts a #GMimeParam into the #GMimeParamList at the specified index.
- **/
-void
-g_mime_param_list_insert (GMimeParamList *list, int index, GMimeParam *param)
-{
-       char *dest, *src;
-       size_t n;
-
-       g_return_if_fail (param != NULL);
-       g_return_if_fail (list != NULL);
-       g_return_if_fail (index >= 0);
-
-       if ((guint) index < list->params->len) {
-               g_ptr_array_set_size (list->params, list->params->len + 1);
-               
-               dest = ((char *) list->params->pdata) + (sizeof (void *) * (index + 1));
-               src = ((char *) list->params->pdata) + (sizeof (void *) * index);
-               n = list->params->len - index - 1;
-               
-               g_memmove (dest, src, (sizeof (void *) * n));
-               list->params->pdata[index] = param;
-       } else {
-               /* the easy case */
-               g_ptr_array_add (list->params, param);
-       }
-}
-
-
-/**
- * g_mime_param_list_remove:
- * @list: a #GMimeParamList
- * @param: a #GMimeParam
- *
- * Removes a #GMimeParam from the #GMimeParamList.
- *
- * Returns: %TRUE if the specified #GMimeParam was removed or %FALSE otherwise.
- **/
-gboolean
-g_mime_param_list_remove (GMimeParamList *list, GMimeParam *param)
-{
-       int index;
-       
-       g_return_val_if_fail (param != NULL, FALSE);
-       g_return_val_if_fail (list != NULL, FALSE);
-       
-       if ((index = g_mime_param_list_index_of (list, param)) == -1)
-               return FALSE;
-       
-       return g_mime_param_list_remove_at (list, index);
-}
-
-
-/**
- * g_mime_param_list_remove_at:
- * @list: a #GMimeParamList
- * @index: index of the param to remove
- *
- * Removes a #GMimeParam from the #GMimeParamList at the specified index.
- *
- * Returns: %TRUE if a #GMimeParam was removed or %FALSE otherwise.
- **/
-gboolean
-g_mime_param_list_remove_at (GMimeParamList *list, int index)
-{
-       GMimeParam *param;
-       
-       g_return_val_if_fail (list != NULL, FALSE);
-       g_return_val_if_fail (index >= 0, FALSE);
-       
-       if ((guint) index >= list->params->len)
-               return FALSE;
-       
-       param = list->params->pdata[index];
-       g_ptr_array_remove_index (list->params, index);
-       g_mime_param_free (param);
-       
-       return TRUE;
-}
-
-
-/**
- * g_mime_param_list_contains:
- * @list: a #GMimeParamList
- * @param: a #GMimeParam
- *
- * Checks whether or not the specified #GMimeParam is contained within
- * the #GMimeParamList.
- *
- * Returns: %TRUE if the specified #GMimeParam is contained within the
- * specified #GMimeParamList or %FALSE otherwise.
- **/
-gboolean
-g_mime_param_list_contains (GMimeParamList *list, GMimeParam *param)
-{
-       return g_mime_param_list_index_of (list, param) != -1;
-}
-
-
-/**
- * g_mime_param_list_index_of:
- * @list: a #GMimeParamList
- * @param: a #GMimeParam
- *
- * Gets the index of the specified #GMimeParam inside the
- * #GMimeParamList.
- *
- * Returns: the index of the requested #GMimeParam within the
- * #GMimeParamList or %-1 if it is not contained within the
- * #GMimeParamList.
- **/
-int
-g_mime_param_list_index_of (GMimeParamList *list, GMimeParam *param)
-{
-       guint i;
-       
-       g_return_val_if_fail (param != NULL, -1);
-       g_return_val_if_fail (list != NULL, -1);
-       
-       for (i = 0; i < list->params->len; i++) {
-               if (list->params->pdata[i] == param)
-                       return i;
-       }
-       
-       return -1;
-}
-
-
-/**
- * g_mime_param_list_get_param:
- * @list: a #GMimeParamList
- * @index: index of #GMimeParam to get
- *
- * Gets the #GMimeParam at the specified index.
- *
- * Returns: the #GMimeParam at the specified index or %NULL if the index is out of range.
- **/
-GMimeParam *
-g_mime_param_list_get_param (GMimeParamList *list, int index)
-{
-       g_return_val_if_fail (list != NULL, NULL);
-       g_return_val_if_fail (index >= 0, NULL);
-       
-       if ((guint) index >= list->params->len)
-               return NULL;
-       
-       return list->params->pdata[index];
-}
-
-
-/**
- * g_mime_param_list_set_param:
- * @list: a #GMimeParamList
- * @index: index of #GMimeParam to set
- * @param: a #GMimeParam
- *
- * Sets the #GMimeParam at the specified index to @param.
- **/
-void
-g_mime_param_list_set_param (GMimeParamList *list, int index, GMimeParam *param)
-{
-       GMimeParam *old;
-       
-       g_return_if_fail (param != NULL);
-       g_return_if_fail (list != NULL);
-       g_return_if_fail (index >= 0);
-       
-       if ((guint) index > list->params->len)
-               return;
-       
-       if ((guint) index == list->params->len) {
-               g_mime_param_list_add (list, param);
-               return;
-       }
-       
-       if ((old = list->params->pdata[index]) == param)
-               return;
-       
-       list->params->pdata[index] = param;
-       g_mime_param_free (old);
-}
diff --git a/gmime/gmime-param.h b/gmime/gmime-param.h
index cb6f6ce..9e47f09 100644
--- a/gmime/gmime-param.h
+++ b/gmime/gmime-param.h
@@ -32,32 +32,56 @@ typedef struct _GMimeParamList GMimeParamList;
 
 
 /**
+ * GMimeParamEncodingMethod:
+ * @GMIME_PARAM_ENCODING_METHOD_DEFAULT: Use the default encoding method set on the #GMimeFormatOptions.
+ * @GMIME_PARAM_ENCODING_METHOD_RFC2231: Use the encoding method described in rfc2231.
+ * @GMIME_PARAM_ENCODING_METHOD_RFC2047: Use the encoding method described in rfc2047.
+ *
+ * The MIME specifications specify that the proper method for encoding Content-Type and
+ * Content-Disposition parameter values is the method described in
+ * <a href="https://tools.ietf.org/html/rfc2231";>rfc2231</a>. However, it is common for
+ * some older email clients to improperly encode using the method described in
+ * <a href="https://tools.ietf.org/html/rfc2047";>rfc2047</a> instead.
+ **/
+typedef enum {
+       GMIME_PARAM_ENCODING_METHOD_DEFAULT = 0,
+       GMIME_PARAM_ENCODING_METHOD_RFC2231 = 1,
+       GMIME_PARAM_ENCODING_METHOD_RFC2047 = 2
+} GMimeParamEncodingMethod;
+
+
+/**
  * GMimeParam:
- * @next: Pointer to the next param.
- * @name: Parameter name.
- * @value: Parameter value.
+ * @method: The encoding method used for the parameter value.
+ * @charset: The charset to use when encoding the parameter value.
+ * @lang: the language specifier to use when encoding the value.
+ * @name: The parameter name.
+ * @value: The parameter value.
  *
- * A parameter name/value pair as used for some Content header fields.
+ * A parameter name/value pair as used in the Content-Type and Content-Disposition headers.
  **/
 struct _GMimeParam {
-       GMimeParam *next;
-       char *name;
-       char *value;
+       GMimeParamEncodingMethod method;
+       char *charset, *lang;
+       char *name, *value;
+       
+       /* < private > */
+       gpointer changed;
 };
 
-GMimeParam *g_mime_param_new (const char *name, const char *value);
-GMimeParam *g_mime_param_parse (GMimeParserOptions *options, const char *str);
-void g_mime_param_free (GMimeParam *param);
+const char *g_mime_param_get_name (GMimeParam *param);
 
-const GMimeParam *g_mime_param_next (const GMimeParam *param);
+const char *g_mime_param_get_value (GMimeParam *param);
+void g_mime_param_set_value (GMimeParam *param, const char *value);
 
-GMimeParam *g_mime_param_append (GMimeParam *params, const char *name, const char *value);
-GMimeParam *g_mime_param_append_param (GMimeParam *params, GMimeParam *param);
+const char *g_mime_param_get_charset (GMimeParam *param);
+void g_mime_param_set_charset (GMimeParam *param, const char *charset);
 
-const char *g_mime_param_get_name (const GMimeParam *param);
-const char *g_mime_param_get_value (const GMimeParam *param);
+const char *g_mime_param_get_lang (GMimeParam *param);
+void g_mime_param_set_lang (GMimeParam *param, const char *lang);
 
-void g_mime_param_write_to_string (const GMimeParam *param, gboolean fold, GString *str);
+GMimeParamEncodingMethod g_mime_param_get_encoding_method (GMimeParam *param);
+void g_mime_param_set_encoding_method (GMimeParam *param, GMimeParamEncodingMethod method);
 
 
 /**
@@ -73,22 +97,21 @@ struct _GMimeParamList {
 };
 
 GMimeParamList *g_mime_param_list_new (void);
+GMimeParamList *g_mime_param_list_parse (GMimeParserOptions *options, const char *str);
 void g_mime_param_list_free (GMimeParamList *list);
 
 int g_mime_param_list_length (GMimeParamList *list);
 
 void g_mime_param_list_clear (GMimeParamList *list);
 
-int g_mime_param_list_add (GMimeParamList *list, GMimeParam *param);
-void g_mime_param_list_insert (GMimeParamList *list, int index, GMimeParam *param);
-gboolean g_mime_param_list_remove (GMimeParamList *list, GMimeParam *param);
-gboolean g_mime_param_list_remove_at (GMimeParamList *list, int index);
+void g_mime_param_list_set_parameter (GMimeParamList *list, const char *name, const char *value);
+GMimeParam *g_mime_param_list_get_parameter (GMimeParamList *list, const char *name);
+GMimeParam *g_mime_param_list_get_parameter_at (GMimeParamList *list, int index);
 
-gboolean g_mime_param_list_contains (GMimeParamList *list, GMimeParam *param);
-int g_mime_param_list_index_of (GMimeParamList *list, GMimeParam *param);
+gboolean g_mime_param_list_remove (GMimeParamList *list, const char *name);
+gboolean g_mime_param_list_remove_at (GMimeParamList *list, int index);
 
-GMimeParam *g_mime_param_list_get_param (GMimeParamList *list, int index);
-void g_mime_param_list_set_param (GMimeParamList *list, int index, GMimeParam *param);
+void g_mime_param_list_encode (GMimeParamList *list, gboolean fold, GString *str);
 
 G_END_DECLS
 
diff --git a/tests/test-headers.c b/tests/test-headers.c
index 9ae9f63..7dbb9fb 100644
--- a/tests/test-headers.c
+++ b/tests/test-headers.c
@@ -224,6 +224,7 @@ test_header_sync (void)
        InternetAddress *addr, *ia;
        GMimeHeaderList *headers;
        GMimeContentType *type;
+       GMimeParamList *params;
        GMimeMessage *message;
        GMimeObject *object;
        GMimeHeader *header;
@@ -232,7 +233,7 @@ test_header_sync (void)
        
        part = g_mime_part_new_with_type ("application", "octet-stream");
        object = (GMimeObject *) part;
-
+       
        headers = g_mime_object_get_header_list (object);
        
        testsuite_check ("content-type synchronization");
@@ -267,10 +268,11 @@ test_header_sync (void)
                if (strcmp ("text/plain; format=flowed", value) != 0)
                        throw (exception_new ("content-type header had unexpected value after setting a 
param"));
                
-               /* now change the content-type's parameters by setting a param list */
-               g_mime_content_type_set_params (type, NULL);
+               /* now change the content-type's parameters by clearing the params */
+               params = g_mime_content_type_get_params (type);
+               g_mime_param_list_clear (params);
                if (!(value = g_mime_object_get_header (object, "Content-Type")))
-                       throw (exception_new ("content-type header was unexpectedly null after setting 
params"));
+                       throw (exception_new ("content-type header was unexpectedly null after clearing 
params"));
                if (strcmp ("text/plain", value) != 0)
                        throw (exception_new ("content-type header had unexpected value after setting 
params"));
                
@@ -313,8 +315,9 @@ test_header_sync (void)
                if (strcmp ("inline; filename=hello.txt", value) != 0)
                        throw (exception_new ("content-disposition header had unexpected value after setting 
a param"));
                
-               /* now change the content-disposition's parameters by setting a param list */
-               g_mime_content_disposition_set_params (disposition, NULL);
+               /* now change the content-disposition's parameters by clearing the params */
+               params = g_mime_content_disposition_get_params (disposition);
+               g_mime_param_list_clear (params);
                if (!(value = g_mime_object_get_header (object, "Content-Disposition")))
                        throw (exception_new ("content-disposition header was unexpectedly null after setting 
params"));
                if (strcmp ("inline", value) != 0)
diff --git a/tests/test-mime.c b/tests/test-mime.c
index 4ddbac2..089fe25 100644
--- a/tests/test-mime.c
+++ b/tests/test-mime.c
@@ -526,9 +526,11 @@ test_header_folding (GMimeParserOptions *options)
 
 static struct {
        const char *input;
+       const char *charset;
        const char *encoded;
 } rfc2184[] = {
        { "this is a really really long filename that should force gmime to rfc2184 encode it - yay!.html",
+         "iso-8859-1",
          "Content-Disposition: attachment;\n\t"
          "filename*0*=iso-8859-1''this%20is%20a%20really%20really%20long%20filename%20;\n\t"
          "filename*1*=that%20should%20force%20gmime%20to%20rfc2184%20encode%20it%20-;\n\t"
@@ -538,51 +540,54 @@ static struct {
 static void
 test_rfc2184 (GMimeParserOptions *options)
 {
-       GMimeParam param, *params;
+       GMimeParamList *params;
+       GMimeParam *param;
        const char *value;
        GString *str;
+       int count;
        size_t n;
        guint i;
        
-       param.next = NULL;
-       param.name = "filename";
-       
-       str = g_string_new ("Content-Disposition: attachment");
-       n = str->len;
-       
        for (i = 0; i < G_N_ELEMENTS (rfc2184); i++) {
-               params = NULL;
+               params = g_mime_param_list_new ();
+               g_mime_param_list_set_parameter (params, "filename", rfc2184[i].input);
                
-               param.value = (char *) rfc2184[i].input;
+               str = g_string_new ("Content-Disposition: attachment");
+               n = str->len;
                
                testsuite_check ("rfc2184[%u]", i);
                try {
-                       g_mime_param_write_to_string (&param, TRUE, str);
+                       g_mime_param_list_encode (params, TRUE, str);
                        if (strcmp (rfc2184[i].encoded, str->str) != 0)
                                throw (exception_new ("encoded param does not match: %s", str->str));
                        
-                       if (!(params = g_mime_param_parse (options, str->str + n + 2)))
+                       g_mime_param_list_free (params);
+                       
+                       if (!(params = g_mime_param_list_parse (options, str->str + n + 2)))
                                throw (exception_new ("could not parse encoded param list"));
                        
-                       if (params->next != NULL)
-                               throw (exception_new ("parsed more than a single param?"));
+                       if ((count = g_mime_param_list_length (params)) != 1)
+                               throw (exception_new ("expected only 1 param, but parsed %d", count));
                        
-                       value = g_mime_param_get_value (params);
-                       if (strcmp (rfc2184[i].input, value) != 0)
+                       if (!(param = g_mime_param_list_get_parameter (params, "filename")))
+                               throw (exception_new ("failed to get filename param"));
+                       
+                       if (strcmp (rfc2184[i].input, param->value) != 0)
                                throw (exception_new ("parsed param value does not match"));
                        
+                       if (strcmp (rfc2184[i].charset, param->charset) != 0)
+                               throw (exception_new ("parsed charset does not match"));
+                       
                        testsuite_check_passed ();
                } catch (ex) {
                        testsuite_check_failed ("rfc2184[%u]: %s", i, ex->message);
                } finally;
                
                if (params != NULL)
-                       g_mime_param_free (params);
+                       g_mime_param_list_free (params);
                
-               g_string_truncate (str, n);
+               g_string_free (str, TRUE);
        }
-       
-       g_string_free (str, TRUE);
 }
 
 


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