[gmime] Replaced GMimeHeaderIter with an indexed API



commit a7d9687d85c27bfed11616a599a5e89e1e06107b
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Tue Jan 31 13:48:03 2017 -0500

    Replaced GMimeHeaderIter with an indexed API

 TODO                          |    4 +
 gmime.spec.in                 |    2 +-
 gmime/Makefile.am             |   40 ++--
 gmime/gmime-header.c          |  696 ++++++++++++-----------------------------
 gmime/gmime-header.h          |   90 +-----
 gmime/gmime-message-partial.c |   30 +-
 gmime/gmime-message.c         |   70 ++---
 tests/test-headers.c          |  282 +++--------------
 8 files changed, 333 insertions(+), 881 deletions(-)
---
diff --git a/TODO b/TODO
index e14f763..b79c13f 100644
--- a/TODO
+++ b/TODO
@@ -9,6 +9,10 @@ GMime 2.8 / 3.0 Planning:
 - Drop the use of GMimeHeaderList's stream cache and instead solve
   this problem by using a per-header cache of the original raw value.
 
+- Kill off GMimeHeaderIter - that API sucks. Let's provide an
+  index-based accessor for particular GMimeHeaders in GMimeHeaderList.
+  Something like g_mime_header_list_get_header_at(int index).
+
 - Fix g_mime_message_[g,s]set_sender() to take/return an
   InternetAddressList to be more consistent with the recipient
   functions as well as being less error-prone.
diff --git a/gmime.spec.in b/gmime.spec.in
index 8f2bb69..614297d 100644
--- a/gmime.spec.in
+++ b/gmime.spec.in
@@ -80,7 +80,7 @@ rm -rf $RPM_BUILD_ROOT
 %{prefix}/lib/*.sh
 %{prefix}/lib/libgmime*
 %{prefix}/lib/pkgconfig/*
-%{prefix}/include/gmime-2.6/gmime/*.h
+%{prefix}/include/gmime-3.0/gmime/*.h
 %if %{enable_gtk_doc}
 %{_datadir}/gtk-doc/html/*/*
 %endif
diff --git a/gmime/Makefile.am b/gmime/Makefile.am
index 6808cc5..b4433f4 100644
--- a/gmime/Makefile.am
+++ b/gmime/Makefile.am
@@ -17,9 +17,9 @@ noinst_PROGRAMS = gen-table charset-map
 
 EXTRA_DIST = gmime-version.h.in gmime-version.h
 
-lib_LTLIBRARIES = libgmime-2.6.la
+lib_LTLIBRARIES = libgmime-3.0.la
 
-libgmime_2_6_la_SOURCES =              \
+libgmime_3_0_la_SOURCES =              \
        gmime.c                         \
        gmime-certificate.c             \
        gmime-charset.c                 \
@@ -156,8 +156,8 @@ install-libtool-import-lib:
 uninstall-libtool-import-lib:
 endif
 
-libgmime_2_6_la_LIBADD = $(top_builddir)/util/libutil.la $(GLIB_LIBS)
-libgmime_2_6_la_LDFLAGS = \
+libgmime_3_0_la_LIBADD = $(top_builddir)/util/libutil.la $(GLIB_LIBS)
+libgmime_3_0_la_LDFLAGS = \
        -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
        -export-dynamic $(no_undefined)
 
@@ -179,18 +179,18 @@ INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir)
 INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
 
 if HAVE_INTROSPECTION
-GMime-2.6.gir: libgmime-2.6.la
-GMime_2_6_gir_INCLUDES = GObject-2.0 Gio-2.0
-GMime_2_6_gir_CFLAGS = $(AM_CPPFLAGS)
-GMime_2_6_gir_LIBS = libgmime-2.6.la
-GMime_2_6_gir_FILES = $(gmimeinclude_HEADERS) $(libgmime_2_6_la_SOURCES)
-GMime_2_6_gir_EXPORT_PACKAGES = gmime-2.6
-GMime_2_6_gir_SCANNERFLAGS = \
+GMime-3.0.gir: libgmime-3.0.la
+GMime_3_0_gir_INCLUDES = GObject-2.0 Gio-2.0
+GMime_3_0_gir_CFLAGS = $(AM_CPPFLAGS)
+GMime_3_0_gir_LIBS = libgmime-3.0.la
+GMime_3_0_gir_FILES = $(gmimeinclude_HEADERS) $(libgmime_3_0_la_SOURCES)
+GMime_3_0_gir_EXPORT_PACKAGES = gmime-3.0
+GMime_3_0_gir_SCANNERFLAGS = \
        --c-include="gmime/gmime.h" \
        --accept-unprefixed \
        --symbol-prefix "gmime_" \
        --symbol-prefix "g_mime_"
-INTROSPECTION_GIRS += GMime-2.6.gir
+INTROSPECTION_GIRS += GMime-3.0.gir
 
 girdir = $(datadir)/gir-1.0
 gir_DATA = $(INTROSPECTION_GIRS)
@@ -204,21 +204,21 @@ endif
 if ENABLE_VAPIGEN
 -include $(VAPIGEN_MAKEFILE)
 
-gmime-2.6.vapi: GMime-2.6.gir GMime-2.6.metadata
+gmime-3.0.vapi: GMime-3.0.gir GMime-3.0.metadata
 
-VAPIGEN_VAPIS = gmime-2.6.vapi
-gmime_2_6_vapi_DEPS = gio-2.0
-gmime_2_6_vapi_METADATADIRS = $(srcdir)
-gmime_2_6_vapi_FILES = GMime-2.6.gir
+VAPIGEN_VAPIS = gmime-3.0.vapi
+gmime_3_0_vapi_DEPS = gio-2.0
+gmime_3_0_vapi_METADATADIRS = $(srcdir)
+gmime_3_0_vapi_FILES = GMime-3.0.gir
 
-gmime-2.6.deps:
-       $(AM_V_GEN) for pkg in $(gmime_2_6_vapi_DEPS); do \
+gmime-3.0.deps:
+       $(AM_V_GEN) for pkg in $(gmime_3_0_vapi_DEPS); do \
                echo $$pkg >> $@; \
        done
 
 vapidir = $(datadir)/vala/vapi
 vapi_DATA = $(VAPIGEN_VAPIS) $(VAPIGEN_VAPIS:.vapi=.deps)
 
-EXTRA_DIST += GMime-2.6.metadata
+EXTRA_DIST += GMime-3.0.metadata
 CLEANFILES += $(vapi_DATA)
 endif
diff --git a/gmime/gmime-header.c b/gmime/gmime-header.c
index ba9eddc..4413fe2 100644
--- a/gmime/gmime-header.c
+++ b/gmime/gmime-header.c
@@ -46,8 +46,7 @@
  **/
 
 struct _GMimeHeader {
-       GMimeHeader *next;
-       GMimeHeader *prev;
+       GMimeHeaderList *list;
        gint64 offset;
        char *name;
        char *value;
@@ -55,12 +54,10 @@ struct _GMimeHeader {
 };
 
 struct _GMimeHeaderList {
-       GMimeStream *stream;
        GHashTable *writers;
        GMimeEvent *changed;
        GHashTable *hash;
-       guint32 version;
-       List list;
+       GPtrArray *list;
 };
 
 
@@ -76,17 +73,16 @@ struct _GMimeHeaderList {
  * Returns: a new #GMimeHeader with the specified values.
  **/
 static GMimeHeader *
-g_mime_header_new (const char *name, const char *value, const char *raw_value, gint64 offset)
+g_mime_header_new (GMimeHeaderList *headers, const char *name, const char *value, const char *raw_value, 
gint64 offset)
 {
        GMimeHeader *header;
        
        header = g_slice_new (GMimeHeader);
+       header->list = headers;
        header->name = g_strdup (name);
        header->value = g_strdup (value);
        header->raw_value = raw_value ? g_strdup (raw_value) : NULL;
        header->offset = offset;
-       header->next = NULL;
-       header->prev = NULL;
        
        return header;
 }
@@ -110,421 +106,105 @@ g_mime_header_free (GMimeHeader *header)
 
 
 /**
- * g_mime_header_iter_new:
- *
- * Dynamically allocates a #GMimeHeaderIter on the heap. This is
- * intended for use in language bindings but may also be useful in
- * applications as well. You must free this iter with
- * g_mime_header_iter_free().
- *
- * Returns: a newly-allocated #GMimeHeaderIter.
- **/
-GMimeHeaderIter *
-g_mime_header_iter_new (void)
-{
-       GMimeHeaderIter *iter;
-       
-       iter = g_slice_new (GMimeHeaderIter);
-       iter->hdrlist = NULL;
-       iter->cursor = NULL;
-       iter->version = 0;
-       
-       return iter;
-}
-
-
-/**
- * g_mime_header_iter_copy:
- * @iter: a #GMimeHeaderIter
- *
- * Creates a dynamically allocated header iterator as a copy of
- * @iter. You must free this iter with g_mime_header_iter_free().
- *
- * Returns: a newly-allocated copy of @iter.
- **/
-GMimeHeaderIter *
-g_mime_header_iter_copy (GMimeHeaderIter *iter)
-{
-       GMimeHeaderIter *copy;
-       
-       g_return_val_if_fail (iter != NULL, NULL);
-       
-       copy = g_mime_header_iter_new ();
-       memcpy (copy, iter, sizeof (GMimeHeaderIter));
-       
-       return copy;
-}
-
-
-/**
- * g_mime_header_iter_copy_to:
- * @src: a #GMimeHeaderIter
- * @dest: a #GMimeHeaderIter
- *
- * Copies @src to @dest.
- **/
-void
-g_mime_header_iter_copy_to (GMimeHeaderIter *src, GMimeHeaderIter *dest)
-{
-       g_return_if_fail (dest != NULL);
-       g_return_if_fail (src != NULL);
-       
-       memcpy (dest, src, sizeof (GMimeHeaderIter));
-}
-
-
-/**
- * g_mime_header_iter_free:
- * @iter: a #GMimeHeaderIter
- *
- * Frees a dynamically-allocated #GMimeHeaderIter as created by
- * g_mime_header_iter_new() or g_mime_header_iter_copy().
- **/
-void
-g_mime_header_iter_free (GMimeHeaderIter *iter)
-{
-       g_return_if_fail (iter != NULL);
-       
-       g_slice_free (GMimeHeaderIter, iter);
-}
-
-
-/**
- * g_mime_header_iter_equal:
- * @iter1: a #GMimeHeaderIter
- * @iter2: a #GMimeHeaderIter
- *
- * Check that @iter1 and @iter2 reference the same header.
- *
- * Returns: %TRUE if @iter1 and @iter2 refer to the same header or
- * %FALSE otherwise.
- **/
-gboolean
-g_mime_header_iter_equal (GMimeHeaderIter *iter1, GMimeHeaderIter *iter2)
-{
-       g_return_val_if_fail (iter1 != NULL, FALSE);
-       g_return_val_if_fail (iter2 != NULL, FALSE);
-       
-       return iter1->hdrlist == iter2->hdrlist &&
-               iter1->version == iter2->version &&
-               iter1->cursor == iter2->cursor;
-}
-
-
-/**
- * g_mime_header_iter_is_valid:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_get_name:
+ * @header: a #GMimeHeader
  *
- * Checks if a #GMimeHeaderIter is valid. An iterator may become
- * invalid if the #GMimeHeaderList that the iterator refers to
- * changes.
+ * Gets the header's name.
  *
- * Returns: %TRUE if @iter is still valid or %FALSE otherwise.
+ * Returns: the header name or %NULL if invalid.
  **/
-gboolean
-g_mime_header_iter_is_valid (GMimeHeaderIter *iter)
+const char *
+g_mime_header_get_name (GMimeHeader *header)
 {
-       g_return_val_if_fail (iter != NULL, FALSE);
-       
-       if (!iter->hdrlist || iter->version != iter->hdrlist->version)
-               return FALSE;
-       
-       if (!iter->cursor || !iter->cursor->next)
-               return FALSE;
+       g_return_val_if_fail (header != NULL, NULL);
        
-       return TRUE;
+       return header->name;
 }
 
 
 /**
- * g_mime_header_iter_first:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_get_value:
+ * @header: a #GMimeHeader
  *
- * Updates @iter to point to the first header.
+ * Gets the header's value.
  *
- * Returns: %TRUE on success or %FALSE otherwise.
- **/
-gboolean
-g_mime_header_iter_first (GMimeHeaderIter *iter)
-{
-       GMimeHeader *first;
-       
-       g_return_val_if_fail (iter != NULL, FALSE);
-       
-       /* make sure we can actually do as requested */
-       if (!iter->hdrlist || list_is_empty (&iter->hdrlist->list))
-               return FALSE;
-       
-       first = (GMimeHeader *) iter->hdrlist->list.head;
-       
-       iter->version = iter->hdrlist->version;
-       iter->cursor = first;
-       
-       return TRUE;
-}
-
-
-/**
- * g_mime_header_iter_last:
- * @iter: a #GMimeHeaderIter
- *
- * Updates @iter to point to the last header.
+ * Returns: the header's raw, unprocessed value or %NULL if invalid.
  *
- * Returns: %TRUE on success or %FALSE otherwise.
+ * Note: The returned value should be decoded with a function such as
+ * g_mime_utils_header_decode_text() before displaying to the user.
  **/
-gboolean
-g_mime_header_iter_last (GMimeHeaderIter *iter)
+const char *
+g_mime_header_get_value (GMimeHeader *header)
 {
-       GMimeHeader *last;
-       
-       g_return_val_if_fail (iter != NULL, FALSE);
+       g_return_val_if_fail (header != NULL, NULL);
        
-       /* make sure we can actually do as requested */
-       if (!iter->hdrlist || list_is_empty (&iter->hdrlist->list))
-               return FALSE;
-       
-       last = (GMimeHeader *) iter->hdrlist->list.tailpred;
-       
-       iter->version = iter->hdrlist->version;
-       iter->cursor = last;
-       
-       return TRUE;
+       return header->value;
 }
 
 
 /**
- * g_mime_header_iter_next:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_set_value:
+ * @header: a #GMimeHeader
+ * @value: the new header value
  *
- * Advances to the next header.
+ * Sets the header's value.
  *
- * Returns: %TRUE on success or %FALSE otherwise.
+ * Note: @value should be encoded with a function such as
+ * g_mime_utils_header_encode_text().
  **/
-gboolean
-g_mime_header_iter_next (GMimeHeaderIter *iter)
+void
+g_mime_header_set_value (GMimeHeader *header, const char *value)
 {
-       GMimeHeader *next;
-       
-       g_return_val_if_fail (iter != NULL, FALSE);
-       
-       /* make sure current cursor is valid */
-       if (!g_mime_header_iter_is_valid (iter))
-               return FALSE;
+       g_return_if_fail (header != NULL);
+       g_return_if_fail (value != NULL);
        
-       /* make sure next item is valid */
-       next = iter->cursor->next;
-       if (!next->next)
-               return FALSE;
-       
-       iter->cursor = next;
+       g_free (header->raw_value);
+       g_free (header->value);
        
-       return TRUE;
+       header->value = g_strdup (value);
 }
 
 
 /**
- * g_mime_header_iter_prev:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_get_raw_value:
+ * @header: a #GMimeHeader
  *
- * Advances to the previous header.
+ * Gets the header's raw (folded) value.
  *
- * Returns: %TRUE on success or %FALSE otherwise.
+ * Returns: the header value or %NULL if invalid.
  **/
-gboolean
-g_mime_header_iter_prev (GMimeHeaderIter *iter)
+const char *
+_g_mime_header_get_raw_value (GMimeHeader *header)
 {
-       GMimeHeader *prev;
-       
-       g_return_val_if_fail (iter != NULL, FALSE);
+       g_return_val_if_fail (header != NULL, NULL);
        
-       /* make sure current cursor is valid */
-       if (!g_mime_header_iter_is_valid (iter))
-               return FALSE;
-       
-       /* make sure prev item is valid */
-       prev = iter->cursor->prev;
-       if (!prev || !prev->prev)
-               return FALSE;
-       
-       iter->cursor = prev;
-       
-       return TRUE;
+       return header->raw_value;
 }
 
 
 /**
- * g_mime_header_iter_get_offset:
- * @iter: a #GMimeHeaderIter
+ * g_mime_header_get_offset:
+ * @header: a #GMimeHeader
  *
- * Gets the current header's file/stream offset.
+ * Gets the header's stream offset if known.
  *
- * Returns: the file/stream offset or %-1 if unknown or invalid.
+ * Returns: the header offset or %-1 if unknown.
  **/
 gint64
-g_mime_header_iter_get_offset (GMimeHeaderIter *iter)
+g_mime_header_get_offset (GMimeHeader *header)
 {
-       g_return_val_if_fail (iter != NULL, -1);
+       g_return_val_if_fail (header != NULL, -1);
        
-       if (!g_mime_header_iter_is_valid (iter))
-               return -1;
-       
-       return iter->cursor->offset;
+       return header->offset;
 }
 
 
 void
-_g_mime_header_iter_set_offset (GMimeHeaderIter *iter, gint64 offset)
-{
-       iter->cursor->offset = offset;
-}
-
-
-/**
- * g_mime_header_iter_get_name:
- * @iter: a #GMimeHeaderIter
- *
- * Gets the current header's name.
- *
- * Returns: the header name or %NULL if invalid.
- **/
-const char *
-g_mime_header_iter_get_name (GMimeHeaderIter *iter)
-{
-       g_return_val_if_fail (iter != NULL, NULL);
-       
-       if (!g_mime_header_iter_is_valid (iter))
-               return NULL;
-       
-       return iter->cursor->name;
-}
-
-
-/**
- * g_mime_header_iter_set_value:
- * @iter: a #GMimeHeaderIter
- * @value: new header value
- *
- * Sets the current header's value to the new value.
- *
- * Returns: %TRUE if the value was set or %FALSE otherwise (indicates
- * invalid iter).
- *
- * Note: @value should be encoded with a function such as
- * g_mime_utils_header_encode_text().
- **/
-gboolean
-g_mime_header_iter_set_value (GMimeHeaderIter *iter, const char *value)
+_g_mime_header_set_offset (GMimeHeader *header, gint64 offset)
 {
-       g_return_val_if_fail (iter != NULL, FALSE);
-       
-       if (!g_mime_header_iter_is_valid (iter))
-               return FALSE;
-       
-       g_free (iter->cursor->value);
-       iter->cursor->value = g_strdup (value);
-       
-       g_free (iter->cursor->raw_value);
-       iter->cursor->raw_value = NULL;
-       
-       return TRUE;
-}
-
-
-/**
- * g_mime_header_iter_get_value:
- * @iter: a #GMimeHeaderIter
- *
- * Gets the current header's value.
- *
- * Returns: the header's raw, unprocessed value or %NULL if invalid.
- *
- * 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_header_iter_get_value (GMimeHeaderIter *iter)
-{
-       g_return_val_if_fail (iter != NULL, NULL);
-       
-       if (!g_mime_header_iter_is_valid (iter))
-               return NULL;
-       
-       return iter->cursor->value;
-}
-
-
-const char *
-_g_mime_header_iter_get_raw_value (GMimeHeaderIter *iter)
-{
-       g_return_val_if_fail (iter != NULL, NULL);
-       
-       if (!g_mime_header_iter_is_valid (iter))
-               return NULL;
-       
-       return iter->cursor->raw_value;
-}
-
-
-/**
- * g_mime_header_iter_remove:
- * @iter: a #GMimeHeaderIter
- *
- * Removes the current header and advances to the next header.
- *
- * Note: If you remove the last header in the list, then @iter will
- * become invalid regardless of whether or not other headers remain.
- *
- * Returns: %TRUE on success or %FALSE otherwise.
- **/
-gboolean
-g_mime_header_iter_remove (GMimeHeaderIter *iter)
-{
-       GMimeHeader *cursor, *header, *next;
-       GMimeHeaderList *hdrlist;
-       
-       g_return_val_if_fail (iter != NULL, FALSE);
-       
-       if (!g_mime_header_iter_is_valid (iter))
-               return FALSE;
-       
-       /* save iter state */
-       hdrlist = iter->hdrlist;
-       cursor = iter->cursor;
-       next = cursor->next;
-       
-       if (!(header = g_hash_table_lookup (hdrlist->hash, cursor->name)))
-               return FALSE;
-       
-       if (cursor == header) {
-               /* update the header lookup table */
-               GMimeHeader *node = next;
-               
-               g_hash_table_remove (hdrlist->hash, cursor->name);
-               
-               while (node->next) {
-                       if (!g_ascii_strcasecmp (node->name, cursor->name)) {
-                               /* enter this node into the lookup table */
-                               g_hash_table_insert (hdrlist->hash, node->name, node);
-                               break;
-                       }
-                       
-                       node = node->next;
-               }
-       }
-       
-       /* remove/free the header */
-       list_unlink ((ListNode *) cursor);
-       g_mime_header_free (cursor);
-       hdrlist->version++;
-       
-       /* update iter state */
-       iter->version = hdrlist->version;
-       iter->cursor = next;
-       
-       return TRUE;
+       header->offset = offset;
 }
 
-
 static ssize_t
 default_writer (GMimeStream *stream, const char *name, const char *value)
 {
@@ -539,13 +219,25 @@ default_writer (GMimeStream *stream, const char *name, const char *value)
 }
 
 
-static ssize_t
-g_mime_header_write_to_stream (GHashTable *writers, GMimeHeader *header, GMimeStream *stream)
+/**
+ * g_mime_header_write_to_stream:
+ * @header: a #GMimeHeader
+ * @stream: a #GMimeStream
+ *
+ * Write the header to the specified stream.
+ *
+ * Returns: the number of bytes written, or %-1 on fail.
+ **/
+ssize_t
+g_mime_header_write_to_stream (GMimeHeader *header, GMimeStream *stream)
 {
        ssize_t nwritten, total = 0;
        GMimeHeaderWriter writer;
        char *val;
        
+       g_return_val_if_fail (header != NULL, -1);
+       g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
+       
        if (header->raw_value) {
                val = g_mime_utils_header_printf ("%s:%s", header->name, header->raw_value);
                nwritten = g_mime_stream_write_string (stream, val);
@@ -556,7 +248,7 @@ g_mime_header_write_to_stream (GHashTable *writers, GMimeHeader *header, GMimeSt
                
                total += nwritten;
        } else if (header->value) {
-               if (!(writer = g_hash_table_lookup (writers, header->name)))
+               if (!(writer = g_hash_table_lookup (header->list->writers, header->name)))
                        writer = default_writer;
                
                if ((nwritten = writer (stream, header->name, header->value)) == -1)
@@ -570,27 +262,6 @@ g_mime_header_write_to_stream (GHashTable *writers, GMimeHeader *header, GMimeSt
 
 
 /**
- * g_mime_header_iter_write_to_stream:
- * @iter: a #GMimeHeaderIter
- * @stream: a #GMimeStream
- *
- * Write the header to a stream.
- *
- * Returns: the number of bytes written or %-1 on fail.
- **/
-ssize_t
-g_mime_header_iter_write_to_stream (GMimeHeaderIter *iter, GMimeStream *stream)
-{
-       g_return_val_if_fail (iter != NULL, -1);
-       
-       if (!g_mime_header_iter_is_valid (iter))
-               return -1;
-       
-       return g_mime_header_write_to_stream (iter->hdrlist->writers, iter->cursor, stream);
-}
-
-
-/**
  * g_mime_header_list_new:
  *
  * Creates a new #GMimeHeaderList object.
@@ -608,9 +279,8 @@ g_mime_header_list_new (void)
                                                  g_free, NULL);
        headers->hash = g_hash_table_new (g_mime_strcase_hash,
                                          g_mime_strcase_equal);
-       list_init (&headers->list);
        headers->changed = g_mime_event_new (headers);
-       headers->version = 0;
+       headers->list = g_ptr_array_new ();
        
        return headers;
 }
@@ -625,17 +295,15 @@ g_mime_header_list_new (void)
 void
 g_mime_header_list_destroy (GMimeHeaderList *headers)
 {
-       GMimeHeader *header, *next;
+       guint i;
        
        if (!headers)
                return;
        
-       header = (GMimeHeader *) headers->list.head;
-       while (header->next) {
-               next = header->next;
-               g_mime_header_free (header);
-               header = next;
-       }
+       for (i = 0; i < headers->list->len; i++)
+               g_mime_header_free (headers->list->pdata[i]);
+       
+       g_ptr_array_free (headers->list, TRUE);
        
        g_hash_table_destroy (headers->writers);
        g_hash_table_destroy (headers->hash);
@@ -655,19 +323,33 @@ g_mime_header_list_destroy (GMimeHeaderList *headers)
 void
 g_mime_header_list_clear (GMimeHeaderList *headers)
 {
-       GMimeHeader *header, *next;
+       guint i;
        
        g_return_if_fail (headers != NULL);
        
-       header = (GMimeHeader *) headers->list.head;
-       while (header->next) {
-               next = header->next;
-               g_mime_header_free (header);
-               header = next;
-       }
+       for (i = 0; i < headers->list->len; i++)
+               g_mime_header_free (headers->list->pdata[i]);
        
        g_hash_table_remove_all (headers->hash);
-       list_init (&headers->list);
+       
+       g_ptr_array_set_size (headers->list, 0);
+}
+
+
+/**
+ * g_mime_header_list_get_count:
+ * @headers: a #GMimeHeaderList
+ *
+ * Gets the number of headers contained within the header list.
+ *
+ * Returns: the number of headers in the header list.
+ **/
+int
+g_mime_header_list_get_count (GMimeHeaderList *headers)
+{
+       g_return_val_if_fail (headers != NULL, -1);
+       
+       return headers->list->len;
 }
 
 
@@ -710,11 +392,25 @@ _g_mime_header_list_has_raw_value (const GMimeHeaderList *headers, const char *n
 void
 _g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value, const char 
*raw_value, gint64 offset)
 {
+       unsigned char *dest, *src;
        GMimeHeader *header;
+       guint n;
        
-       header = g_mime_header_new (name, value, raw_value, offset);
-       list_prepend (&headers->list, (ListNode *) header);
+       header = g_mime_header_new (headers, name, value, raw_value, offset);
        g_hash_table_replace (headers->hash, header->name, header);
+       
+       if (headers->list->len > 0) {
+               g_ptr_array_set_size (headers->list, headers->list->len + 1);
+               
+               dest = ((unsigned char *) headers->list->pdata) + sizeof (void *);
+               src = (unsigned char *) headers->list->pdata;
+               n = headers->list->len - 1;
+               
+               g_memmove (dest, src, (sizeof (void *) * n));
+               headers->list->pdata[0] = header;
+       } else {
+               g_ptr_array_add (headers->list, header);
+       }
 }
 
 
@@ -746,8 +442,8 @@ _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const ch
 {
        GMimeHeader *header;
        
-       header = g_mime_header_new (name, value, raw_value, offset);
-       list_append (&headers->list, (ListNode *) header);
+       header = g_mime_header_new (headers, name, value, raw_value, offset);
+       g_ptr_array_add (headers->list, header);
        
        if (!g_hash_table_lookup (headers->hash, name))
                g_hash_table_insert (headers->hash, header->name, header);
@@ -807,34 +503,32 @@ g_mime_header_list_get (const GMimeHeaderList *headers, const char *name)
 void
 _g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value, const char 
*raw_value, gint64 offset)
 {
-       GMimeHeader *header, *next;
+       GMimeHeader *header, *hdr;
+       guint i;
        
        if ((header = g_hash_table_lookup (headers->hash, name))) {
-               g_free (header->value);
-               header->value = g_strdup (value);
-               
                g_free (header->raw_value);
                header->raw_value = raw_value ? g_strdup (raw_value) : NULL;
                
+               g_free (header->value);
+               header->value = g_strdup (value);
+               
                header->offset = offset;
                
-               header = header->next;
-               while (header->next) {
-                       next = header->next;
+               for (i = headers->list->len - 1; i > 0; i--) {
+                       hdr = (GMimeHeader *) headers->list->pdata[i];
                        
-                       if (!g_ascii_strcasecmp (header->name, name)) {
-                               /* remove/free the header */
-                               list_unlink ((ListNode *) header);
-                               g_mime_header_free (header);
-                               headers->version++;
-                       }
+                       if (hdr == header)
+                               break;
+                       
+                       if (g_ascii_strcasecmp (header->name, hdr->name) != 0)
+                               continue;
                        
-                       header = next;
+                       g_ptr_array_remove_index (headers->list, i);
+                       g_mime_header_free (hdr);
                }
        } else {
-               header = g_mime_header_new (name, value, raw_value, offset);
-               list_append (&headers->list, (ListNode *) header);
-               g_hash_table_insert (headers->hash, header->name, header);
+               _g_mime_header_list_append (headers, name, value, raw_value, offset);
        }
 }
 
@@ -868,11 +562,33 @@ g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *
 
 
 /**
+ * g_mime_header_list_get_header:
+ * @headers: a #GMimeHeaderList
+ * @index: the 0-based index of the header
+ *
+ * Gets the header at the specified @index within the list.
+ *
+ * Returns: (transfer none): the header at position @index.
+ **/
+GMimeHeader *
+g_mime_header_list_get_header (GMimeHeaderList *headers, int index)
+{
+       g_return_val_if_fail (headers != NULL, NULL);
+       g_return_val_if_fail (index >= 0, NULL);
+       
+       if ((guint) index >= headers->list->len)
+               return NULL;
+       
+       return (GMimeHeader *) headers->list->pdata[index];
+}
+
+
+/**
  * g_mime_header_list_remove:
  * @headers: a #GMimeHeaderList
  * @name: header name
  *
- * Remove the specified header.
+ * Remove the first instance of the specified header.
  *
  * Returns: %TRUE if the header was successfully removed or %FALSE if
  * the specified header could not be found.
@@ -881,6 +597,7 @@ gboolean
 g_mime_header_list_remove (GMimeHeaderList *headers, const char *name)
 {
        GMimeHeader *header, *node;
+       guint i;
        
        g_return_val_if_fail (headers != NULL, FALSE);
        g_return_val_if_fail (name != NULL, FALSE);
@@ -888,80 +605,71 @@ g_mime_header_list_remove (GMimeHeaderList *headers, const char *name)
        if (!(header = g_hash_table_lookup (headers->hash, name)))
                return FALSE;
        
+       /* get the index of the header */
+       for (i = 0; i < headers->list->len; i++) {
+               if (headers->list->pdata[i] == header)
+                       break;
+       }
+       
+       g_ptr_array_remove_index (headers->list, i);
+       g_hash_table_remove (headers->hash, name);
+       g_mime_header_free (header);
+       
        /* look for another header with the same name... */
-       node = header->next;
-       while (node->next) {
-               if (!g_ascii_strcasecmp (node->name, name)) {
+       while (i < headers->list->len) {
+               header = (GMimeHeader *) headers->list->pdata[i];
+               
+               if (!g_ascii_strcasecmp (header->name, name)) {
                        /* enter this node into the lookup table */
-                       g_hash_table_replace (headers->hash, node->name, node);
+                       g_hash_table_insert (headers->hash, header->name, header);
                        break;
                }
                
-               node = node->next;
+               i++;
        }
        
-       /* invalidate all our outstanding iterators matching @header */
-       headers->version++;
-       
-       /* remove/free the header */
-       list_unlink ((ListNode *) header);
-       g_mime_header_free (header);
-       
        return TRUE;
 }
 
 
 /**
- * g_mime_header_list_get_iter:
+ * g_mime_header_list_remove_at:
  * @headers: a #GMimeHeaderList
- * @iter: (out): a #GMimeHeaderIter
- *
- * Initializes an iterator for traversing @headers.
+ * @index: the 0-based index of the header to remove
  *
- * Returns: a %TRUE if successful or %FALSE if there are no headers to
- * traverse.
+ * Removes the header at the specified @index from @headers.
  **/
-gboolean
-g_mime_header_list_get_iter (GMimeHeaderList *headers, GMimeHeaderIter *iter)
-{
-       GMimeHeader *cursor;
-       
-       g_return_val_if_fail (headers != NULL, FALSE);
-       
-       cursor = (GMimeHeader *) headers->list.head;
-       if (!cursor->next)
-               return FALSE;
-       
-       iter->version = headers->version;
-       iter->hdrlist = headers;
-       iter->cursor = cursor;
-       
-       return TRUE;
-}
-
-
-/**
- * g_mime_header_list_foreach:
- * @headers: A #GMimeHeaderList
- * @func: (scope call): function to be called for each header.
- * @user_data: User data to be passed to the func.
- *
- * Calls @func for each header name/value pair.
- */
 void
-g_mime_header_list_foreach (const GMimeHeaderList *headers, GMimeHeaderForeachFunc func, gpointer user_data)
+g_mime_header_list_remove_at (GMimeHeaderList *headers, int index)
 {
-       const GMimeHeader *header;
+       GMimeHeader *header, *hdr;
+       guint i;
        
        g_return_if_fail (headers != NULL);
-       g_return_if_fail (func != NULL);
+       g_return_if_fail (index >= 0);
        
-       header = (const GMimeHeader *) headers->list.head;
+       if ((guint) index >= headers->list->len)
+               return;
        
-       while (header->next) {
-               func (header->name, header->value, user_data);
-               header = header->next;
+       header = (GMimeHeader *) headers->list->pdata[index];
+       g_ptr_array_remove_index (headers->list, index);
+       
+       /* if this is the first instance of a header with this name, then we'll
+        * need to update the hash table to point to the next instance... */
+       if ((hdr = g_hash_table_lookup (headers->hash, header->name)) == header) {
+               g_hash_table_remove (headers->hash, header->name);
+               
+               for (i = (guint) index; i < headers->list->len; i++) {
+                       hdr = (GMimeHeader *) headers->list->pdata[i];
+                       
+                       if (!g_ascii_strcasecmp (header->name, hdr->name)) {
+                               g_hash_table_insert (headers->hash, hdr->name, hdr);
+                               break;
+                       }
+               }
        }
+       
+       g_mime_header_free (header);
 }
 
 
@@ -978,23 +686,19 @@ ssize_t
 g_mime_header_list_write_to_stream (const GMimeHeaderList *headers, GMimeStream *stream)
 {
        ssize_t nwritten, total = 0;
-       GHashTable *writers;
        GMimeHeader *header;
-       char *val;
+       guint i;
        
        g_return_val_if_fail (headers != NULL, -1);
        g_return_val_if_fail (stream != NULL, -1);
        
-       header = (GMimeHeader *) headers->list.head;
-       writers = headers->writers;
-       
-       while (header->next) {
-               if ((nwritten = g_mime_header_write_to_stream (writers, header, stream)) == -1)
+       for (i = 0; i < headers->list->len; i++) {
+               header = (GMimeHeader *) headers->list->pdata[i];
+               
+               if ((nwritten = g_mime_header_write_to_stream (header, stream)) == -1)
                        return -1;
                
                total += nwritten;
-               
-               header = header->next;
        }
        
        return total;
diff --git a/gmime/gmime-header.h b/gmime/gmime-header.h
index ce1ff8d..f088ef9 100644
--- a/gmime/gmime-header.h
+++ b/gmime/gmime-header.h
@@ -27,18 +27,19 @@
 
 G_BEGIN_DECLS
 
-typedef struct _GMimeHeader GMimeHeader;
-
 
 /**
- * GMimeHeaderForeachFunc:
+ * GMimeHeaderWriter:
+ * @stream: The output stream.
  * @name: The field name.
  * @value: The field value.
- * @user_data: The user-supplied callback data.
  *
- * Function signature for the callback to g_mime_header_list_foreach().
+ * Function signature for the callback to
+ * g_mime_header_list_register_writer().
+ *
+ * Returns: the number of bytes written or %-1 on error.
  **/
-typedef void (* GMimeHeaderForeachFunc) (const char *name, const char *value, gpointer user_data);
+typedef ssize_t (* GMimeHeaderWriter) (GMimeStream *stream, const char *name, const char *value);
 
 
 /**
@@ -48,92 +49,37 @@ typedef void (* GMimeHeaderForeachFunc) (const char *name, const char *value, gp
  **/
 typedef struct _GMimeHeader GMimeHeader;
 
+const char *g_mime_header_get_name (GMimeHeader *header);
 
-/**
- * GMimeHeaderList:
- *
- * A message or mime-part header.
- **/
-typedef struct _GMimeHeaderList GMimeHeaderList;
-
-
-/**
- * GMimeHeaderIter:
- * @hdrlist: a #GMimeHeaderList
- * @cursor: a #GMimeHeader
- * @version: the version of @hdrlist when initialized
- *
- * A message or mime-part header iterator. All members should be
- * considered private.
- **/
-typedef struct _GMimeHeaderIter GMimeHeaderIter;
-
-struct _GMimeHeaderIter {
-       GMimeHeaderList *hdrlist;
-       GMimeHeader *cursor;
-       guint32 version;
-};
-
-
-GMimeHeaderIter *g_mime_header_iter_new (void);
-void g_mime_header_iter_free (GMimeHeaderIter *iter);
+const char *g_mime_header_get_value (GMimeHeader *header);
+void g_mime_header_set_value (GMimeHeader *header, const char *value);
 
-GMimeHeaderIter *g_mime_header_iter_copy (GMimeHeaderIter *iter);
-void g_mime_header_iter_copy_to (GMimeHeaderIter *src, GMimeHeaderIter *dest);
+gint64 g_mime_header_get_offset (GMimeHeader *header);
 
-gboolean g_mime_header_iter_equal (GMimeHeaderIter *iter1, GMimeHeaderIter *iter2);
-
-gboolean g_mime_header_iter_is_valid (GMimeHeaderIter *iter);
-
-gboolean g_mime_header_iter_first (GMimeHeaderIter *iter);
-gboolean g_mime_header_iter_last (GMimeHeaderIter *iter);
-
-gboolean g_mime_header_iter_next (GMimeHeaderIter *iter);
-gboolean g_mime_header_iter_prev (GMimeHeaderIter *iter);
-
-const char *g_mime_header_iter_get_name (GMimeHeaderIter *iter);
-
-gboolean g_mime_header_iter_set_value (GMimeHeaderIter *iter, const char *value);
-const char *g_mime_header_iter_get_value (GMimeHeaderIter *iter);
-
-gint64 g_mime_header_iter_get_offset (GMimeHeaderIter *iter);
-
-gboolean g_mime_header_iter_remove (GMimeHeaderIter *iter);
-
-ssize_t g_mime_header_iter_write_to_stream (GMimeHeaderIter *iter, GMimeStream *stream);
+ssize_t g_mime_header_write_to_stream (GMimeHeader *header, GMimeStream *stream);
 
 
 /**
- * GMimeHeaderWriter:
- * @stream: The output stream.
- * @name: The field name.
- * @value: The field value.
- *
- * Function signature for the callback to
- * g_mime_header_list_register_writer().
+ * GMimeHeaderList:
  *
- * Returns: the number of bytes written or %-1 on error.
+ * A list of message or mime-part headers.
  **/
-typedef ssize_t (* GMimeHeaderWriter) (GMimeStream *stream, const char *name, const char *value);
+typedef struct _GMimeHeaderList GMimeHeaderList;
 
 GMimeHeaderList *g_mime_header_list_new (void);
 
 void g_mime_header_list_destroy (GMimeHeaderList *headers);
 
-void g_mime_header_list_set_stream (GMimeHeaderList *headers, GMimeStream *stream);
-GMimeStream *g_mime_header_list_get_stream (GMimeHeaderList *headers);
-
 void g_mime_header_list_clear (GMimeHeaderList *headers);
+int g_mime_header_list_get_count (GMimeHeaderList *headers);
 gboolean g_mime_header_list_contains (const 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);
 const char *g_mime_header_list_get (const GMimeHeaderList *headers, const char *name);
+GMimeHeader *g_mime_header_list_get_header (GMimeHeaderList *headers, int index);
 gboolean g_mime_header_list_remove (GMimeHeaderList *headers, const char *name);
-
-gboolean g_mime_header_list_get_iter (GMimeHeaderList *headers, GMimeHeaderIter *iter);
-
-void g_mime_header_list_foreach (const GMimeHeaderList *headers, GMimeHeaderForeachFunc func, gpointer 
user_data);
+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 (const GMimeHeaderList *headers, GMimeStream *stream);
diff --git a/gmime/gmime-message-partial.c b/gmime/gmime-message-partial.c
index 098a8cf..32dbf02 100644
--- a/gmime/gmime-message-partial.c
+++ b/gmime/gmime-message-partial.c
@@ -41,7 +41,7 @@
  * A #GMimeMessagePartial represents the message/partial MIME part.
  **/
 
-extern const char *_g_mime_header_iter_get_raw_value (GMimeHeaderIter *iter);
+extern const char *_g_mime_header_get_raw_value (GMimeHeader *header);
 
 extern void _g_mime_object_append_header (GMimeObject *object, const char *header, const char *value, const 
char *raw_value, gint64 offset);
 
@@ -377,24 +377,26 @@ static GMimeMessage *
 message_partial_message_new (GMimeMessage *base)
 {
        const char *name, *value, *raw_value;
+       GMimeHeaderList *headers;
        GMimeMessage *message;
-       GMimeHeaderList *list;
-       GMimeHeaderIter iter;
+       GMimeHeader *header;
        gint64 offset;
+       int count, i;
        
        message = g_mime_message_new (FALSE);
        
-       list = ((GMimeObject *) base)->headers;
+       headers = ((GMimeObject *) base)->headers;
        
-       if (g_mime_header_list_get_iter (list, &iter)) {
-               do {
-                       name = g_mime_header_iter_get_name (&iter);
-                       value = g_mime_header_iter_get_value (&iter);
-                       raw_value = _g_mime_header_iter_get_raw_value (&iter);
-                       offset = g_mime_header_iter_get_offset (&iter);
-                       
-                       _g_mime_object_append_header ((GMimeObject *) message, name, value, raw_value, 
offset);
-               } while (g_mime_header_iter_next (&iter));
+       count = g_mime_header_list_get_count (headers);
+       
+       for (i = 0; i < count; i++) {
+               header = g_mime_header_list_get_header (headers, i);
+               raw_value = _g_mime_header_get_raw_value (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_value, offset);
        }
        
        return message;
diff --git a/gmime/gmime-message.c b/gmime/gmime-message.c
index cec1fbe..3544d2a 100644
--- a/gmime/gmime-message.c
+++ b/gmime/gmime-message.c
@@ -53,7 +53,7 @@ extern void _g_mime_object_prepend_header (GMimeObject *object, const char *head
 extern void _g_mime_object_append_header (GMimeObject *object, const char *header, const char *value, const 
char *raw_value, gint64 offset);
 extern void _g_mime_object_set_header (GMimeObject *object, const char *header, const char *value, const 
char *raw_value, gint64 offset);
 
-extern void _g_mime_header_iter_set_offset (GMimeHeaderIter *iter, gint64 offset);
+extern void _g_mime_header_set_offset (GMimeHeader *header, gint64 offset);
 
 extern void _g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value, 
const char *raw_value, gint64 offset);
 extern void _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value, const 
char *raw_value, gint64 offset);
@@ -978,57 +978,56 @@ write_headers_to_stream (GMimeObject *object, GMimeStream *stream)
        GMimeMessage *message = (GMimeMessage *) object;
        GMimeObject *mime_part = message->mime_part;
        ssize_t nwritten, total = 0;
-       GMimeHeaderIter mesg, body;
        
-       if (!g_mime_header_list_get_iter (object->headers, &mesg))
-               return -1;
-       
-       if (message->mime_part && g_mime_header_list_get_iter (mime_part->headers, &body)) {
-               while (g_mime_header_iter_is_valid (&mesg) && g_mime_header_iter_is_valid (&body)) {
-                       gint64 mesg_offset, body_offset;
-                       
-                       if ((body_offset = g_mime_header_iter_get_offset (&body)) < 0)
+       if (mime_part != NULL) {
+               int body_count = g_mime_header_list_get_count (mime_part->headers);
+               int count = g_mime_header_list_get_count (object->headers);
+               GMimeHeader *header, *body_header;
+               gint64 body_offset, offset;
+               int body_index = 0;
+               int index = 0;
+               
+               while (index < count && body_index < body_count) {
+                       body_header = g_mime_header_list_get_header (mime_part->headers, body_index);
+                       if ((body_offset = g_mime_header_get_offset (body_header)) < 0)
                                break;
                        
-                       mesg_offset = g_mime_header_iter_get_offset (&mesg);
+                       header = g_mime_header_list_get_header (object->headers, index);
+                       offset = g_mime_header_get_offset (header);
                        
-                       if (mesg_offset >= 0 && mesg_offset < body_offset) {
-                               if ((nwritten = g_mime_header_iter_write_to_stream (&mesg, stream)) == -1)
+                       if (offset >= 0 && offset < body_offset) {
+                               if ((nwritten = g_mime_header_write_to_stream (header, stream)) == -1)
                                        return -1;
                                
                                total += nwritten;
-                               
-                               if (!g_mime_header_iter_next (&mesg))
-                                       break;
+                               index++;
                        } else {
-                               if ((nwritten = g_mime_header_iter_write_to_stream (&body, stream)) == -1)
+                               if ((nwritten = g_mime_header_write_to_stream (body_header, stream)) == -1)
                                        return -1;
                                
                                total += nwritten;
-                               
-                               if (!g_mime_header_iter_next (&body))
-                                       break;
+                               body_index++;
                        }
                }
                
-               while (g_mime_header_iter_is_valid (&mesg)) {
-                       if ((nwritten = g_mime_header_iter_write_to_stream (&mesg, stream)) == -1)
+               while (index < count) {
+                       header = g_mime_header_list_get_header (object->headers, index);
+                       
+                       if ((nwritten = g_mime_header_write_to_stream (header, stream)) == -1)
                                return -1;
                        
                        total += nwritten;
-                       
-                       if (!g_mime_header_iter_next (&mesg))
-                               break;
+                       index++;
                }
                
-               while (g_mime_header_iter_is_valid (&body)) {
-                       if ((nwritten = g_mime_header_iter_write_to_stream (&body, stream)) == -1)
+               while (body_index < body_count) {
+                       header = g_mime_header_list_get_header (mime_part->headers, body_index);
+                       
+                       if ((nwritten = g_mime_header_write_to_stream (header, stream)) == -1)
                                return -1;
                        
                        total += nwritten;
-                       
-                       if (!g_mime_header_iter_next (&body))
-                               break;
+                       body_index++;
                }
                
                return total;
@@ -1562,8 +1561,6 @@ g_mime_message_get_mime_part (GMimeMessage *message)
 void
 g_mime_message_set_mime_part (GMimeMessage *message, GMimeObject *mime_part)
 {
-       GMimeHeaderIter iter;
-       
        g_return_if_fail (mime_part == NULL || GMIME_IS_OBJECT (mime_part));
        g_return_if_fail (GMIME_IS_MESSAGE (message));
        
@@ -1575,14 +1572,15 @@ g_mime_message_set_mime_part (GMimeMessage *message, GMimeObject *mime_part)
        
        if (mime_part) {
                GMimeHeaderList *headers = ((GMimeObject *) message)->headers;
+               GMimeHeader *header;
+               int i;
                
                if (!g_mime_header_list_contains (headers, "MIME-Version"))
                        g_mime_header_list_append (headers, "MIME-Version", "1.0");
                
-               if (g_mime_header_list_get_iter (mime_part->headers, &iter)) {
-                       do {
-                               _g_mime_header_iter_set_offset (&iter, -1);
-                       } while (g_mime_header_iter_next (&iter));
+               for (i = 0; i < g_mime_header_list_get_count (mime_part->headers); i++) {
+                       header = g_mime_header_list_get_header (mime_part->headers, i);
+                       _g_mime_header_set_offset (header, -1);
                }
                
                g_object_ref (mime_part);
diff --git a/tests/test-headers.c b/tests/test-headers.c
index b311d0d..4736359 100644
--- a/tests/test-headers.c
+++ b/tests/test-headers.c
@@ -65,211 +65,80 @@ header_list_new (void)
 }
 
 static void
-test_iter_forward_back (void)
+test_indexing (void)
 {
        const char *name, *value;
        GMimeHeaderList *list;
-       GMimeHeaderIter iter;
-       guint i;
+       GMimeHeader *header;
+       int index, count;
        
        list = header_list_new ();
        
-       /* make sure initial iter is valid */
-       testsuite_check ("initial iter");
-       try {
-               if (!g_mime_header_list_get_iter (list, &iter))
-                       throw (exception_new ("get_iter() failed"));
-               
-               if (!g_mime_header_iter_is_valid (&iter))
-                       throw (exception_new ("invalid iter"));
-               
-               name = g_mime_header_iter_get_name (&iter);
-               value = g_mime_header_iter_get_value (&iter);
-               
-               if (strcmp (initial[0].name, name) != 0 || strcmp (initial[0].value, value) != 0)
-                       throw (exception_new ("resulted in unexpected header"));
-               testsuite_check_passed ();
-       } catch (ex) {
-               testsuite_check_failed ("initial iter: %s", ex->message);
-       } finally;
+       count = g_mime_header_list_get_count (list);
        
-       /* make sure iter->next works as expected */
-       for (i = 1; i < G_N_ELEMENTS (initial); i++) {
-               testsuite_check ("next iter[%u]", i);
+       /* make sure indexing works as expected */
+       for (index = 0; index < G_N_ELEMENTS (initial); index++) {
+               testsuite_check ("headers[%d]", index);
                try {
-                       if (!g_mime_header_iter_next (&iter))
-                               throw (exception_new ("failed to advance"));
-                       
-                       if (!g_mime_header_iter_is_valid (&iter))
-                               throw (exception_new ("advanced but is invalid"));
+                       if (!(header = g_mime_header_list_get_header (list, index)))
+                               throw (exception_new ("failed to get header at index"));
                        
-                       name = g_mime_header_iter_get_name (&iter);
-                       value = g_mime_header_iter_get_value (&iter);
+                       name = g_mime_header_get_name (header);
+                       value = g_mime_header_get_value (header);
                        
-                       if (strcmp (initial[i].name, name) != 0 ||
-                           strcmp (initial[i].value, value) != 0)
+                       if (strcmp (initial[index].name, name) != 0 ||
+                           strcmp (initial[index].value, value) != 0)
                                throw (exception_new ("resulted in unexpected header"));
                        testsuite_check_passed ();
                } catch (ex) {
-                       testsuite_check_failed ("next iter[%u]: %s", i, ex->message);
+                       testsuite_check_failed ("next iter[%d]: %s", index, ex->message);
                } finally;
        }
        
        /* make sure trying to advance past the last header fails */
-       testsuite_check ("iter->next past end of headers");
+       testsuite_check ("indexing past end of headers");
        try {
-               if (g_mime_header_iter_next (&iter))
+               if (g_mime_header_list_get_header (list, index) != NULL)
                        throw (exception_new ("should not have worked"));
                testsuite_check_passed ();
        } catch (ex) {
-               testsuite_check_failed ("iter->next past end of headers: %s", ex->message);
-       } finally;
-       
-       /* make sure iter->prev works as expected */
-       i--;
-       while (i > 0) {
-               testsuite_check ("prev iter[%u]", i);
-               try {
-                       if (!g_mime_header_iter_prev (&iter))
-                               throw (exception_new ("failed to advance"));
-                       
-                       if (!g_mime_header_iter_is_valid (&iter))
-                               throw (exception_new ("advanced but is invalid"));
-                       
-                       name = g_mime_header_iter_get_name (&iter);
-                       value = g_mime_header_iter_get_value (&iter);
-                       
-                       if (strcmp (initial[i - 1].name, name) != 0 ||
-                           strcmp (initial[i - 1].value, value) != 0)
-                               throw (exception_new ("resulted in unexpected header"));
-                       testsuite_check_passed ();
-               } catch (ex) {
-                       testsuite_check_failed ("prev iter[%u]: %s", i, ex->message);
-               } finally;
-               
-               i--;
-       }
-       
-       /* make sure trying to advance prev of the first header fails */
-       testsuite_check ("iter->prev past beginning of headers");
-       try {
-               if (g_mime_header_iter_prev (&iter))
-                       throw (exception_new ("should not have worked"));
-               testsuite_check_passed ();
-       } catch (ex) {
-               testsuite_check_failed ("iter->prev past beginning of headers: %s", ex->message);
-       } finally;
-       
-       g_mime_header_list_destroy (list);
-}
-
-static void
-test_iter_remove_all (void)
-{
-       GMimeHeaderList *list;
-       GMimeHeaderIter iter;
-       guint i = 0;
-       
-       list = header_list_new ();
-       
-       g_mime_header_list_get_iter (list, &iter);
-       
-       testsuite_check ("removing all headers");
-       try {
-               while (g_mime_header_iter_remove (&iter))
-                       i++;
-               
-               if (i != G_N_ELEMENTS (initial))
-                       throw (exception_new ("only removed %u of %u", i, G_N_ELEMENTS (initial)));
-               
-               if (g_mime_header_iter_is_valid (&iter))
-                       throw (exception_new ("expected invalid iter"));
-               
-               testsuite_check_passed ();
-       } catch (ex) {
-               testsuite_check_failed ("removing all headers: %s", ex->message);
-       } finally;
-       
-       g_mime_header_list_get_iter (list, &iter);
-       
-       testsuite_check ("empty list iter");
-       try {
-               if (g_mime_header_iter_is_valid (&iter))
-                       throw (exception_new ("expected invalid iter"));
-               
-               testsuite_check_passed ();
-       } catch (ex) {
-               testsuite_check_failed ("empty list iter: %s", ex->message);
+               testsuite_check_failed ("indexing past end of headers: %s", ex->message);
        } finally;
        
        g_mime_header_list_destroy (list);
 }
 
 static void
-test_iter_remove (void)
+test_remove_at (void)
 {
-       GMimeHeaderIter iter, iter1, iter2, iter3;
        const char *name, *value;
        GMimeHeaderList *list;
+       GMimeHeader *header;
+       int count;
        guint i;
        
        list = header_list_new ();
        
-       g_mime_header_list_get_iter (list, &iter1);
-       
-       testsuite_check ("iter copying");
-       try {
-               /* make iter2 point to the second header */
-               g_mime_header_iter_copy_to (&iter1, &iter2);
-               if (!g_mime_header_iter_next (&iter2))
-                       throw (exception_new ("iter2->next failed"));
-               
-               name = g_mime_header_iter_get_name (&iter2);
-               value = g_mime_header_iter_get_value (&iter2);
-               
-               if (strcmp (initial[1].name, name) != 0 ||
-                   strcmp (initial[1].value, value) != 0)
-                       throw (exception_new ("iter2 resulted in unexpected header"));
-               
-               /* make iter3 point to the third header */
-               g_mime_header_iter_copy_to (&iter2, &iter3);
-               if (!g_mime_header_iter_next (&iter3))
-                       throw (exception_new ("iter3->next failed"));
-               
-               name = g_mime_header_iter_get_name (&iter3);
-               value = g_mime_header_iter_get_value (&iter3);
-               
-               if (strcmp (initial[2].name, name) != 0 ||
-                   strcmp (initial[2].value, value) != 0)
-                       throw (exception_new ("iter3 resulted in unexpected header"));
-               
-               testsuite_check_passed ();
-       } catch (ex) {
-               testsuite_check_failed ("iter copying: %s", ex->message);
-       } finally;
-       
        testsuite_check ("remove first header");
        try {
                /* remove the first header */
-               g_mime_header_iter_copy_to (&iter1, &iter);
-               if (!g_mime_header_iter_remove (&iter))
-                       throw (exception_new ("iter::remove() failed"));
+               g_mime_header_list_remove_at (list, 0);
                
-               /* make sure iter now points to the 2nd header */
-               name = g_mime_header_iter_get_name (&iter);
-               value = g_mime_header_iter_get_value (&iter);
+               /* make sure the first header is now the same as the second original header */
+               header = g_mime_header_list_get_header (list, 0);
+               name = g_mime_header_get_name (header);
+               value = g_mime_header_get_value (header);
                
                if (strcmp (initial[1].name, name) != 0 ||
                    strcmp (initial[1].value, value) != 0)
-                       throw (exception_new ("iter doesn't point to 2nd header as expected"));
+                       throw (exception_new ("expected second Received header"));
                
-               /* make sure that the other iters have been invalidated */
-               if (g_mime_header_iter_is_valid (&iter1))
-                       throw (exception_new ("iter::remove() iter1::isvalid() incorrect"));
-               if (g_mime_header_iter_is_valid (&iter2))
-                       throw (exception_new ("iter::remove() iter2::isvalid() incorrect"));
-               if (g_mime_header_iter_is_valid (&iter3))
-                       throw (exception_new ("iter::remove() iter3::isvalid() incorrect"));
+               /* make sure that the internal hash table was properly updated */
+               if (!(value = g_mime_header_list_get (list, "Received")))
+                       throw (exception_new ("lookup of Received header failed"));
+               
+               if (strcmp (initial[1].value, value) != 0)
+                       throw (exception_new ("expected second Received header value"));
                
                testsuite_check_passed ();
        } catch (ex) {
@@ -279,84 +148,17 @@ test_iter_remove (void)
        testsuite_check ("remove last header");
        try {
                /* remove the last header */
-               g_mime_header_iter_last (&iter);
-               
-               if (!g_mime_header_iter_remove (&iter))
-                       throw (exception_new ("iter::remove() failed"));
+               count = g_mime_header_list_get_count (list);
+               g_mime_header_list_remove_at (list, count - 1);
                
-               /* iter should be invalid now because it couldn't advance to a header beyond the last */
-               if (g_mime_header_iter_is_valid (&iter))
-                       throw (exception_new ("iter::remove() iter is valid when it shouldn't be"));
+               if ((value = g_mime_header_list_get (list, "Message-Id")) != NULL)
+                       throw (exception_new ("lookup of Message-Id should have failed"));
                
                testsuite_check_passed ();
        } catch (ex) {
                testsuite_check_failed ("remove last header: %s", ex->message);
        } finally;
        
-       testsuite_check ("remove middle header");
-       try {
-               g_mime_header_list_get_iter (list, &iter);
-               
-               /* advance to a header in the middle somewhere... */
-               g_mime_header_iter_next (&iter);
-               g_mime_header_iter_next (&iter);
-               
-               /* we should now be pointing to the 3rd header (4th from the initial headers) */
-               name = g_mime_header_iter_get_name (&iter);
-               value = g_mime_header_iter_get_value (&iter);
-               
-               if (strcmp (initial[3].name, name) != 0 ||
-                   strcmp (initial[3].value, value) != 0)
-                       throw (exception_new ("iter doesn't point to 3rd header as expected"));
-               
-               /* remove it */
-               if (!g_mime_header_iter_remove (&iter))
-                       throw (exception_new ("iter::remove() failed"));
-               
-               /* make sure the iter is still valid */
-               if (!g_mime_header_iter_is_valid (&iter))
-                       throw (exception_new ("iter::remove() iter isn't valid when it should be"));
-               
-               /* make sure iter now points to the 4th header */
-               name = g_mime_header_iter_get_name (&iter);
-               value = g_mime_header_iter_get_value (&iter);
-               
-               if (strcmp (initial[4].name, name) != 0 ||
-                   strcmp (initial[4].value, value) != 0)
-                       throw (exception_new ("iter doesn't point to 4th header as expected"));
-               
-               testsuite_check_passed ();
-       } catch (ex) {
-               testsuite_check_failed ("remove first header: %s", ex->message);
-       } finally;
-       
-       testsuite_check ("resulting lists match");
-       try {
-               g_mime_header_list_get_iter (list, &iter);
-               i = 1;
-               
-               do {
-                       name = g_mime_header_iter_get_name (&iter);
-                       value = g_mime_header_iter_get_value (&iter);
-                       
-                       if (i == 3)
-                               i++;
-                       
-                       if (strcmp (initial[i].name, name) != 0 ||
-                           strcmp (initial[i].value, value) != 0)
-                               throw (exception_new ("iter vs array mismatch @ index %u", i));
-                       
-                       i++;
-               } while (g_mime_header_iter_next (&iter));
-               
-               if (++i != G_N_ELEMENTS (initial))
-                       throw (exception_new ("iter didn't have as many headers as expected"));
-               
-               testsuite_check_passed ();
-       } catch (ex) {
-               testsuite_check_failed ("resulting lists match: %s", ex->message);
-       } finally;
-       
        g_mime_header_list_destroy (list);
 }
 
@@ -539,16 +341,12 @@ int main (int argc, char **argv)
        
        testsuite_init (argc, argv);
        
-       testsuite_start ("iterating forward and backward");
-       test_iter_forward_back ();
-       testsuite_end ();
-       
-       testsuite_start ("removing all headers");
-       test_iter_remove_all ();
+       testsuite_start ("indexing");
+       test_indexing ();
        testsuite_end ();
        
-       testsuite_start ("removing individual headers");
-       test_iter_remove ();
+       testsuite_start ("removing at an index");
+       test_remove_at ();
        testsuite_end ();
        
        testsuite_start ("header synchronization");


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