[evolution] Convert EMailPart to a GObject.



commit f9ffe647231a7ba2bd5347d92d560b6a57fee786
Author: Matthew Barnes <mbarnes redhat com>
Date:   Wed May 15 09:17:58 2013 -0400

    Convert EMailPart to a GObject.
    
    EMailPart is reference-counted, subclassed, and allows a custom
    finalize function.  There's no excuse for it not to use GObject.

 composer/e-msg-composer.c                          |    2 +-
 em-format/Makefile.am                              |    5 +
 em-format/e-mail-formatter-attachment-bar.c        |    3 +-
 em-format/e-mail-formatter-attachment.c            |   13 +-
 em-format/e-mail-formatter-message-rfc822.c        |   12 +-
 em-format/e-mail-formatter-print-headers.c         |    2 +-
 em-format/e-mail-formatter-print.c                 |    2 +-
 em-format/e-mail-formatter-quote-attachment.c      |    2 +-
 em-format/e-mail-formatter-quote-message-rfc822.c  |    4 +-
 em-format/e-mail-formatter-quote.c                 |    2 +-
 em-format/e-mail-formatter.c                       |    2 +-
 em-format/e-mail-parser-attachment-bar.c           |   21 +-
 em-format/e-mail-parser-headers.c                  |   36 +--
 em-format/e-mail-parser-image.c                    |   25 +-
 em-format/e-mail-parser-text-enriched.c            |   25 +-
 em-format/e-mail-parser.c                          |   38 +-
 em-format/e-mail-part-attachment-bar.c             |   89 ++++
 em-format/e-mail-part-attachment-bar.h             |   47 ++-
 em-format/e-mail-part-attachment.c                 |  147 +++++++-
 em-format/e-mail-part-attachment.h                 |   40 ++-
 em-format/e-mail-part-headers.c                    |   95 +++++
 em-format/e-mail-part-headers.h                    |   68 ++++
 em-format/e-mail-part-image.c                      |  100 +++++
 em-format/e-mail-part-image.h                      |   65 +++
 em-format/e-mail-part-list.c                       |   10 +-
 em-format/e-mail-part.c                            |  422 +++++++++++++------
 em-format/e-mail-part.h                            |   59 ++--
 mail/e-mail-display.c                              |    8 +-
 mail/e-mail-reader-utils.c                         |    2 +-
 mail/e-mail-request.c                              |    2 +-
 mail/em-utils.c                                    |    2 +-
 modules/audio-inline/Makefile.am                   |    1 +
 modules/audio-inline/e-mail-formatter-audio.c      |    3 +-
 modules/audio-inline/e-mail-parser-audio.c         |   38 +--
 modules/audio-inline/e-mail-part-audio.c           |  142 +++++++
 modules/audio-inline/e-mail-part-audio.h           |   33 ++-
 .../audio-inline/evolution-module-audio-inline.c   |    2 +
 modules/itip-formatter/Makefile.am                 |    1 +
 modules/itip-formatter/e-mail-parser-itip.c        |  108 +-----
 modules/itip-formatter/e-mail-part-itip.c          |  171 ++++++++
 modules/itip-formatter/e-mail-part-itip.h          |   34 ++-
 .../evolution-module-itip-formatter.c              |    2 +
 .../e-mail-display-popup-prefer-plain.c            |    2 +-
 modules/vcard-inline/Makefile.am                   |    1 +
 modules/vcard-inline/e-mail-parser-vcard.c         |  235 +-----------
 modules/vcard-inline/e-mail-part-vcard.c           |  353 ++++++++++++++++
 modules/vcard-inline/e-mail-part-vcard.h           |   33 ++-
 .../vcard-inline/evolution-module-vcard-inline.c   |    2 +
 48 files changed, 1810 insertions(+), 701 deletions(-)
---
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 2dc6ac7..bad162a 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -216,7 +216,7 @@ emcu_part_to_html (EMsgComposer *composer,
        while (!g_queue_is_empty (&queue)) {
                EMailPart *mail_part = g_queue_pop_head (&queue);
                e_mail_part_list_add_part (part_list, mail_part);
-               e_mail_part_unref (mail_part);
+               g_object_unref (mail_part);
        }
        g_string_free (part_id, TRUE);
        g_object_unref (parser);
diff --git a/em-format/Makefile.am b/em-format/Makefile.am
index f26a004..d3861a6 100644
--- a/em-format/Makefile.am
+++ b/em-format/Makefile.am
@@ -15,6 +15,8 @@ emformatinclude_HEADERS =                             \
        e-mail-part.h                                   \
        e-mail-part-attachment.h                        \
        e-mail-part-attachment-bar.h                    \
+       e-mail-part-headers.h                           \
+       e-mail-part-image.h                             \
        e-mail-part-list.h                              \
        e-mail-part-utils.h                             \
        e-mail-stripsig-filter.h
@@ -89,6 +91,9 @@ libemformat_la_SOURCES =                              \
        e-mail-parser-text-plain.c                      \
        e-mail-part.c                                   \
        e-mail-part-attachment.c                        \
+       e-mail-part-attachment-bar.c                    \
+       e-mail-part-headers.c                           \
+       e-mail-part-image.c                             \
        e-mail-part-list.c                              \
        e-mail-part-utils.c                             \
        e-mail-stripsig-filter.c                        \
diff --git a/em-format/e-mail-formatter-attachment-bar.c b/em-format/e-mail-formatter-attachment-bar.c
index b18ce06..89378b8 100644
--- a/em-format/e-mail-formatter-attachment-bar.c
+++ b/em-format/e-mail-formatter-attachment-bar.c
@@ -80,7 +80,8 @@ emfe_attachment_bar_get_widget (EMailFormatterExtension *extension,
 
        g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT_BAR (part), NULL);
 
-       store = E_MAIL_PART_ATTACHMENT_BAR (part)->store;
+       store = e_mail_part_attachment_bar_get_store (
+               E_MAIL_PART_ATTACHMENT_BAR (part));
 
        widget = e_attachment_bar_new (store);
        g_object_set_data (G_OBJECT (store), "attachment-bar", widget);
diff --git a/em-format/e-mail-formatter-attachment.c b/em-format/e-mail-formatter-attachment.c
index 7718090..0a100e0 100644
--- a/em-format/e-mail-formatter-attachment.c
+++ b/em-format/e-mail-formatter-attachment.c
@@ -100,10 +100,11 @@ find_attachment_store (EMailPartList *part_list,
        g_free (tmp);
 
        if (part != NULL)
-               store = E_MAIL_PART_ATTACHMENT_BAR (part)->store;
+               store = e_mail_part_attachment_bar_get_store (
+                       E_MAIL_PART_ATTACHMENT_BAR (part));
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 
        return store;
 }
@@ -297,10 +298,8 @@ emfe_attachment_format (EMailFormatterExtension *extension,
                                empa->attachment_view_part_id);
 
                        /* Avoid recursion. */
-                       if (attachment_view_part == part) {
-                               e_mail_part_unref (attachment_view_part);
-                               attachment_view_part = NULL;
-                       }
+                       if (attachment_view_part == part)
+                               g_clear_object (&attachment_view_part);
 
                        if (attachment_view_part != NULL) {
                                ok = e_mail_formatter_format_as (
@@ -308,7 +307,7 @@ emfe_attachment_format (EMailFormatterExtension *extension,
                                        attachment_view_part,
                                        content_stream, NULL,
                                        cancellable);
-                               e_mail_part_unref (attachment_view_part);
+                               g_object_unref (attachment_view_part);
                        }
 
                } else {
diff --git a/em-format/e-mail-formatter-message-rfc822.c b/em-format/e-mail-formatter-message-rfc822.c
index 01b67c6..0477e61 100644
--- a/em-format/e-mail-formatter-message-rfc822.c
+++ b/em-format/e-mail-formatter-message-rfc822.c
@@ -77,7 +77,7 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension,
 
                /* Discard the first EMailPart. */
                if (!g_queue_is_empty (&queue))
-                       e_mail_part_unref (g_queue_pop_head (&queue));
+                       g_object_unref (g_queue_pop_head (&queue));
 
                head = g_queue_peek_head_link (&queue);
 
@@ -119,7 +119,7 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension,
                g_free (end);
 
                while (!g_queue_is_empty (&queue))
-                       e_mail_part_unref (g_queue_pop_head (&queue));
+                       g_object_unref (g_queue_pop_head (&queue));
 
                context->mode = E_MAIL_FORMATTER_MODE_RAW;
 
@@ -136,14 +136,14 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension,
 
                /* Discard the first EMailPart. */
                if (!g_queue_is_empty (&queue))
-                       e_mail_part_unref (g_queue_pop_head (&queue));
+                       g_object_unref (g_queue_pop_head (&queue));
 
                if (g_queue_is_empty (&queue))
                        return FALSE;
 
                part = g_queue_pop_head (&queue);
                end = g_strconcat (part_id, ".end", NULL);
-               e_mail_part_unref (part);
+               g_object_unref (part);
 
                head = g_queue_peek_head_link (&queue);
 
@@ -187,7 +187,7 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension,
                g_free (end);
 
                while (!g_queue_is_empty (&queue))
-                       e_mail_part_unref (g_queue_pop_head (&queue));
+                       g_object_unref (g_queue_pop_head (&queue));
 
        } else {
                EMailPart *p;
@@ -240,7 +240,7 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension,
                g_free (str);
                g_free (uri);
 
-               e_mail_part_unref (p);
+               g_object_unref (p);
        }
 
        return TRUE;
diff --git a/em-format/e-mail-formatter-print-headers.c b/em-format/e-mail-formatter-print-headers.c
index 6e4826d..39b6878 100644
--- a/em-format/e-mail-formatter-print-headers.c
+++ b/em-format/e-mail-formatter-print-headers.c
@@ -211,7 +211,7 @@ emfpe_headers_format (EMailFormatterExtension *extension,
        }
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 
        g_string_append (str, "</table>");
 
diff --git a/em-format/e-mail-formatter-print.c b/em-format/e-mail-formatter-print.c
index a855ebc..0728cb6 100644
--- a/em-format/e-mail-formatter-print.c
+++ b/em-format/e-mail-formatter-print.c
@@ -171,7 +171,7 @@ mail_formatter_print_run (EMailFormatter *formatter,
        }
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 
        /* This consumes the attachments queue. */
        if (!g_queue_is_empty (&attachments))
diff --git a/em-format/e-mail-formatter-quote-attachment.c b/em-format/e-mail-formatter-quote-attachment.c
index e098a02..1a6b194 100644
--- a/em-format/e-mail-formatter-quote-attachment.c
+++ b/em-format/e-mail-formatter-quote-attachment.c
@@ -107,7 +107,7 @@ emfqe_attachment_format (EMailFormatterExtension *extension,
                "<DATA class=\"ClueFlow\" clear=\"orig\">-->",
                cancellable, NULL);
 
-       e_mail_part_unref (attachment_view_part);
+       g_object_unref (attachment_view_part);
 
        return TRUE;
 }
diff --git a/em-format/e-mail-formatter-quote-message-rfc822.c 
b/em-format/e-mail-formatter-quote-message-rfc822.c
index ae1d3a4..15a9056 100644
--- a/em-format/e-mail-formatter-quote-message-rfc822.c
+++ b/em-format/e-mail-formatter-quote-message-rfc822.c
@@ -76,7 +76,7 @@ emfqe_message_rfc822_format (EMailFormatterExtension *extension,
                return FALSE;
 
        /* Discard the first EMailPart. */
-       e_mail_part_unref (g_queue_pop_head (&queue));
+       g_object_unref (g_queue_pop_head (&queue));
 
        head = g_queue_peek_head (&queue);
 
@@ -133,7 +133,7 @@ emfqe_message_rfc822_format (EMailFormatterExtension *extension,
        g_free (end);
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 
        camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
 
diff --git a/em-format/e-mail-formatter-quote.c b/em-format/e-mail-formatter-quote.c
index 52d76ec..99c4de9 100644
--- a/em-format/e-mail-formatter-quote.c
+++ b/em-format/e-mail-formatter-quote.c
@@ -130,7 +130,7 @@ mail_formatter_quote_run (EMailFormatter *formatter,
        }
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 
        if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) {
                camel_stream_write_string (
diff --git a/em-format/e-mail-formatter.c b/em-format/e-mail-formatter.c
index 5b00753..acb5c65 100644
--- a/em-format/e-mail-formatter.c
+++ b/em-format/e-mail-formatter.c
@@ -479,7 +479,7 @@ mail_formatter_run (EMailFormatter *formatter,
        }
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 
        camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
 }
diff --git a/em-format/e-mail-parser-attachment-bar.c b/em-format/e-mail-parser-attachment-bar.c
index 1ceebe5..0632211 100644
--- a/em-format/e-mail-parser-attachment-bar.c
+++ b/em-format/e-mail-parser-attachment-bar.c
@@ -28,16 +28,6 @@
 
 #include "e-mail-parser-extension.h"
 
-static void
-mail_part_attachment_bar_free (EMailPart *part)
-{
-       EMailPartAttachmentBar *empab = (EMailPartAttachmentBar *) part;
-
-       g_clear_object (&empab->store);
-}
-
-/******************************************************************************/
-
 typedef EMailParserExtension EMailParserAttachmentBar;
 typedef EMailParserExtensionClass EMailParserAttachmentBarClass;
 
@@ -61,19 +51,16 @@ empe_attachment_bar_parse (EMailParserExtension *extension,
                            GCancellable *cancellable,
                            GQueue *out_mail_parts)
 {
-       EMailPartAttachmentBar *empab;
+       EMailPart *mail_part;
        gint len;
 
        len = part_id->len;
        g_string_append (part_id, ".attachment-bar");
-       empab = (EMailPartAttachmentBar *) e_mail_part_subclass_new (
-               part, part_id->str, sizeof (EMailPartAttachmentBar),
-               (GFreeFunc) mail_part_attachment_bar_free);
-       empab->parent.mime_type = g_strdup (parser_mime_types[0]);
-       empab->store = E_ATTACHMENT_STORE (e_attachment_store_new ());
+       mail_part = e_mail_part_attachment_bar_new (part, part_id->str);
+       e_mail_part_set_mime_type (mail_part, parser_mime_types[0]);
        g_string_truncate (part_id, len);
 
-       g_queue_push_tail (out_mail_parts, empab);
+       g_queue_push_tail (out_mail_parts, mail_part);
 
        return TRUE;
 }
diff --git a/em-format/e-mail-parser-headers.c b/em-format/e-mail-parser-headers.c
index 900b64c..76cad8b 100644
--- a/em-format/e-mail-parser-headers.c
+++ b/em-format/e-mail-parser-headers.c
@@ -27,6 +27,7 @@
 #include <libemail-engine/e-mail-utils.h>
 
 #include "e-mail-parser-extension.h"
+#include "e-mail-part-headers.h"
 
 typedef EMailParserExtension EMailParserHeaders;
 typedef EMailParserExtensionClass EMailParserHeadersClass;
@@ -39,35 +40,10 @@ G_DEFINE_TYPE (
        E_TYPE_MAIL_PARSER_EXTENSION)
 
 static const gchar *parser_mime_types[] = {
-       "application/vnd.evolution.headers",
+       E_MAIL_PART_HEADERS_MIME_TYPE,
        NULL
 };
 
-static void
-empe_headers_bind_dom (EMailPart *part,
-                       WebKitDOMElement *element)
-{
-       WebKitDOMDocument *document;
-       WebKitDOMElement *photo;
-       gchar *addr, *uri;
-
-       document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
-       photo = webkit_dom_document_get_element_by_id (document, "__evo-contact-photo");
-
-       /* Contact photos disabled, the <img> tag is not there */
-       if (!photo)
-               return;
-
-       addr = webkit_dom_element_get_attribute (photo, "data-mailaddr");
-       uri = g_strdup_printf ("mail://contact-photo?mailaddr=%s", addr);
-
-       webkit_dom_html_image_element_set_src (
-               WEBKIT_DOM_HTML_IMAGE_ELEMENT (photo), uri);
-
-       g_free (addr);
-       g_free (uri);
-}
-
 static gboolean
 empe_headers_parse (EMailParserExtension *extension,
                     EMailParser *parser,
@@ -82,13 +58,11 @@ empe_headers_parse (EMailParserExtension *extension,
        len = part_id->len;
        g_string_append (part_id, ".headers");
 
-       mail_part = e_mail_part_new (part, part_id->str);
-       mail_part->mime_type = g_strdup ("application/vnd.evolution.headers");
-       mail_part->bind_func = empe_headers_bind_dom;
-       g_string_truncate (part_id, len);
-
+       mail_part = e_mail_part_headers_new (part, part_id->str);
        g_queue_push_tail (out_mail_parts, mail_part);
 
+       g_string_truncate (part_id, len);
+
        return TRUE;
 }
 
diff --git a/em-format/e-mail-parser-image.c b/em-format/e-mail-parser-image.c
index 4fc57de..807e724 100644
--- a/em-format/e-mail-parser-image.c
+++ b/em-format/e-mail-parser-image.c
@@ -25,6 +25,7 @@
 #include <e-util/e-util.h>
 
 #include "e-mail-parser-extension.h"
+#include "e-mail-part-image.h"
 #include "e-mail-part-utils.h"
 
 typedef EMailParserExtension EMailParserImage;
@@ -58,12 +59,6 @@ static const gchar *parser_mime_types[] = {
 };
 
 static gboolean
-is_attachment (const gchar *disposition)
-{
-       return disposition && g_ascii_strcasecmp (disposition, "attachment") == 0;
-}
-
-static gboolean
 empe_image_parse (EMailParserExtension *extension,
                   EMailParser *parser,
                   CamelMimePart *part,
@@ -73,28 +68,12 @@ empe_image_parse (EMailParserExtension *extension,
 {
        GQueue work_queue = G_QUEUE_INIT;
        EMailPart *mail_part;
-       const gchar *tmp;
-       gchar *cid;
        gint len;
-       CamelContentType *ct;
-
-       tmp = camel_mime_part_get_content_id (part);
-       if (tmp) {
-               cid = g_strdup_printf ("cid:%s", tmp);
-       } else {
-               cid = NULL;
-       }
 
        len = part_id->len;
        g_string_append (part_id, ".image");
 
-       ct = camel_mime_part_get_content_type (part);
-
-       mail_part = e_mail_part_new (part, part_id->str);
-       mail_part->is_attachment = TRUE;
-       mail_part->cid = cid;
-       mail_part->mime_type = ct ? camel_content_type_simple (ct) : g_strdup ("image/*");
-       mail_part->is_hidden = cid != NULL && !is_attachment (camel_mime_part_get_disposition (part));
+       mail_part = e_mail_part_image_new (part, part_id->str);
 
        g_string_truncate (part_id, len);
 
diff --git a/em-format/e-mail-parser-text-enriched.c b/em-format/e-mail-parser-text-enriched.c
index f2b26c2..f938471 100644
--- a/em-format/e-mail-parser-text-enriched.c
+++ b/em-format/e-mail-parser-text-enriched.c
@@ -53,22 +53,33 @@ empe_text_enriched_parse (EMailParserExtension *extension,
 {
        GQueue work_queue = G_QUEUE_INIT;
        EMailPart *mail_part;
-       const gchar *tmp;
+       const gchar *cid;
        gint len;
        CamelContentType *ct;
 
        len = part_id->len;
        g_string_append (part_id, ".text_enriched");
 
+       mail_part = e_mail_part_new (part, part_id->str);
+
        ct = camel_mime_part_get_content_type (part);
+       if (ct != NULL) {
+               gchar *mime_type;
 
-       mail_part = e_mail_part_new (part, part_id->str);
-       mail_part->mime_type = ct ? camel_content_type_simple (ct) : g_strdup ("text/enriched");
-       tmp = camel_mime_part_get_content_id (part);
-       if (!tmp) {
-               mail_part->cid = NULL;
+               mime_type = camel_content_type_simple (ct);
+               e_mail_part_set_mime_type (mail_part, mime_type);
+               g_free (mime_type);
        } else {
-               mail_part->cid = g_strdup_printf ("cid:%s", tmp);
+               e_mail_part_set_mime_type (mail_part, "text/enriched");
+       }
+
+       cid = camel_mime_part_get_content_id (part);
+       if (cid != NULL) {
+               gchar *cid_uri;
+
+               cid_uri = g_strdup_printf ("cid:%s", cid);
+               e_mail_part_set_cid (mail_part, cid_uri);
+               g_free (cid_uri);
        }
 
        g_string_truncate (part_id, len);
diff --git a/em-format/e-mail-parser.c b/em-format/e-mail-parser.c
index 75ec0e5..929662f 100644
--- a/em-format/e-mail-parser.c
+++ b/em-format/e-mail-parser.c
@@ -111,7 +111,7 @@ mail_parser_run (EMailParser *parser,
 
        mail_part = e_mail_part_new (CAMEL_MIME_PART (message), ".message");
        e_mail_part_list_add_part (part_list, mail_part);
-       e_mail_part_unref (mail_part);
+       g_object_unref (mail_part);
 
        for (iter = parsers->head; iter; iter = iter->next) {
                EMailParserExtension *extension;
@@ -136,7 +136,7 @@ mail_parser_run (EMailParser *parser,
        while (!g_queue_is_empty (&mail_part_queue)) {
                mail_part = g_queue_pop_head (&mail_part_queue);
                e_mail_part_list_add_part (part_list, mail_part);
-               e_mail_part_unref (mail_part);
+               g_object_unref (mail_part);
        }
 
        g_string_free (part_id, TRUE);
@@ -369,7 +369,7 @@ e_mail_parser_parse_sync (EMailParser *parser,
                                part->is_hidden ? 1 : 0,
                                e_mail_part_get_is_attachment (part) ? 1 : 0);
 
-                       e_mail_part_unref (part);
+                       g_object_unref (part);
                }
 
                camel_debug_end ();
@@ -473,7 +473,7 @@ e_mail_parser_parse_finish (EMailParser *parser,
                                part->is_hidden ? 1 : 0,
                                e_mail_part_get_is_attachment (part) ? 1 : 0);
 
-                       e_mail_part_unref (part);
+                       g_object_unref (part);
                }
 
                camel_debug_end ();
@@ -644,8 +644,9 @@ e_mail_parser_wrap_as_attachment (EMailParser *parser,
                                   GQueue *parts_queue)
 {
        EMailPartAttachment *empa;
+       EAttachment *attachment;
        EMailPart *first_part;
-       const gchar *snoop_mime_type, *cid;
+       const gchar *snoop_mime_type;
        GQueue *extensions;
        CamelContentType *ct;
        gchar *mime_type;
@@ -691,30 +692,23 @@ e_mail_parser_wrap_as_attachment (EMailParser *parser,
        part_id_len = part_id->len;
        g_string_append (part_id, ".attachment");
 
-       empa = (EMailPartAttachment *) e_mail_part_subclass_new (
-               part, part_id->str, sizeof (EMailPartAttachment),
-               (GFreeFunc) e_mail_part_attachment_free);
-       empa->parent.mime_type = g_strdup ("application/vnd.evolution.attachment");
-       empa->parent.is_attachment = TRUE;
+       empa = e_mail_part_attachment_new (part, part_id->str);
        empa->shown = extensions && (!g_queue_is_empty (extensions) &&
                e_mail_part_is_inline (part, extensions));
        empa->snoop_mime_type = snoop_mime_type;
-       empa->attachment = e_attachment_new ();
 
        first_part = g_queue_peek_head (parts_queue);
        if (first_part != NULL) {
-               empa->attachment_view_part_id = g_strdup (first_part->id);
+               const gchar *id = e_mail_part_get_id (first_part);
+               empa->attachment_view_part_id = g_strdup (id);
                first_part->is_hidden = TRUE;
        }
 
-       cid = camel_mime_part_get_content_id (part);
-       if (cid)
-               empa->parent.cid = g_strdup_printf ("cid:%s", cid);
+       attachment = e_mail_part_attachment_ref_attachment (empa);
 
-       e_attachment_set_mime_part (empa->attachment, part);
-       e_attachment_set_shown (empa->attachment, empa->shown);
+       e_attachment_set_shown (attachment, empa->shown);
        e_attachment_set_can_show (
-               empa->attachment,
+               attachment,
                extensions && !g_queue_is_empty (extensions));
 
        /* Try to guess size of the attachments */
@@ -734,13 +728,13 @@ e_mail_parser_wrap_as_attachment (EMailParser *parser,
        g_idle_add_full (
                G_PRIORITY_HIGH_IDLE,
                (GSourceFunc) load_attachment_idle,
-               g_object_ref (empa->attachment),
+               g_object_ref (attachment),
                NULL);
 
        if (size != 0) {
                GFileInfo *fileinfo;
 
-               fileinfo = e_attachment_get_file_info (empa->attachment);
+               fileinfo = e_attachment_get_file_info (attachment);
 
                if (!fileinfo) {
                        fileinfo = g_file_info_new ();
@@ -751,11 +745,13 @@ e_mail_parser_wrap_as_attachment (EMailParser *parser,
                }
 
                g_file_info_set_size (fileinfo, size);
-               e_attachment_set_file_info (empa->attachment, fileinfo);
+               e_attachment_set_file_info (attachment, fileinfo);
 
                g_object_unref (fileinfo);
        }
 
+       g_object_unref (attachment);
+
        g_string_truncate (part_id, part_id_len);
 
        /* Push to head, not tail. */
diff --git a/em-format/e-mail-part-attachment-bar.c b/em-format/e-mail-part-attachment-bar.c
new file mode 100644
index 0000000..5cebd9b
--- /dev/null
+++ b/em-format/e-mail-part-attachment-bar.c
@@ -0,0 +1,89 @@
+/*
+ * e-mail-part-attachment-bar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-attachment-bar.h"
+
+#define E_MAIL_PART_ATTACHMENT_BAR_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_MAIL_PART_ATTACHMENT_BAR, EMailPartAttachmentBarPrivate))
+
+struct _EMailPartAttachmentBarPrivate {
+       EAttachmentStore *store;
+};
+
+G_DEFINE_TYPE (
+       EMailPartAttachmentBar,
+       e_mail_part_attachment_bar,
+       E_TYPE_MAIL_PART)
+
+static void
+mail_part_attachment_bar_dispose (GObject *object)
+{
+       EMailPartAttachmentBarPrivate *priv;
+
+       priv = E_MAIL_PART_ATTACHMENT_BAR_GET_PRIVATE (object);
+
+       g_clear_object (&priv->store);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_mail_part_attachment_bar_parent_class)->
+               dispose (object);
+}
+
+static void
+e_mail_part_attachment_bar_class_init (EMailPartAttachmentBarClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (
+               class, sizeof (EMailPartAttachmentBarPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = mail_part_attachment_bar_dispose;
+}
+
+static void
+e_mail_part_attachment_bar_init (EMailPartAttachmentBar *part)
+{
+       GtkTreeModel *tree_model;
+
+       part->priv = E_MAIL_PART_ATTACHMENT_BAR_GET_PRIVATE (part);
+
+       tree_model = e_attachment_store_new ();
+       part->priv->store = E_ATTACHMENT_STORE (tree_model);
+}
+
+EMailPart *
+e_mail_part_attachment_bar_new (CamelMimePart *mime_part,
+                                const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+
+       return g_object_new (
+               E_TYPE_MAIL_PART_ATTACHMENT_BAR,
+               "id", id, "mime-part", mime_part, NULL);
+}
+
+EAttachmentStore *
+e_mail_part_attachment_bar_get_store (EMailPartAttachmentBar *part)
+{
+       g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT_BAR (part), NULL);
+
+       return part->priv->store;
+}
+
diff --git a/em-format/e-mail-part-attachment-bar.h b/em-format/e-mail-part-attachment-bar.h
index 38e644f..ca9f931 100644
--- a/em-format/e-mail-part-attachment-bar.h
+++ b/em-format/e-mail-part-attachment-bar.h
@@ -21,18 +21,51 @@
 
 #include <em-format/e-mail-part.h>
 
-#define E_MAIL_PART_ATTACHMENT_BAR(part) \
-       ((EMailPartAttachmentBar *) part)
-#define E_IS_MAIL_PART_ATTACHMENT_BAR(part) \
-       (E_MAIL_PART_IS (part, EMailPartAttachmentBar))
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_ATTACHMENT_BAR \
+       (e_mail_part_attachment_bar_get_type ())
+#define E_MAIL_PART_ATTACHMENT_BAR(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART_ATTACHMENT_BAR, EMailPartAttachmentBar))
+#define E_MAIL_PART_ATTACHMENT_BAR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART_ATTACHMENT_BAR, EMailPartAttachmentBarClass))
+#define E_IS_MAIL_PART_ATTACHMENT_BAR(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_PART_ATTACHMENT_BAR))
+#define E_IS_MAIL_PART_ATTACHMENT_BAR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_PART_ATTACHMENT_BAR))
+#define E_MAIL_PART_ATTACHMENT_BAR_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART_ATTACHMENT_BAR, EMailPartAttachmentBarClass))
 
 #define E_MAIL_PART_ATTACHMENT_BAR_MIME_TYPE \
        "application/vnd.evolution.widget.attachment-bar"
 
-typedef struct _EMailPartAttachmentBar {
+G_BEGIN_DECLS
+
+typedef struct _EMailPartAttachmentBar EMailPartAttachmentBar;
+typedef struct _EMailPartAttachmentBarClass EMailPartAttachmentBarClass;
+typedef struct _EMailPartAttachmentBarPrivate EMailPartAttachmentBarPrivate;
+
+struct _EMailPartAttachmentBar {
        EMailPart parent;
+       EMailPartAttachmentBarPrivate *priv;
+};
+
+struct _EMailPartAttachmentBarClass {
+       EMailPartClass parent_class;
+};
+
+GType          e_mail_part_attachment_bar_get_type
+                                               (void) G_GNUC_CONST;
+EMailPart *    e_mail_part_attachment_bar_new  (CamelMimePart *mime_part,
+                                                const gchar *id);
+EAttachmentStore *
+               e_mail_part_attachment_bar_get_store
+                                               (EMailPartAttachmentBar *part);
 
-       EAttachmentStore *store;
-} EMailPartAttachmentBar;
+G_END_DECLS
 
 #endif /* E_MAIL_PART_ATTACHMENT_BAR_H */
diff --git a/em-format/e-mail-part-attachment.c b/em-format/e-mail-part-attachment.c
index ef19a81..df81357 100644
--- a/em-format/e-mail-part-attachment.c
+++ b/em-format/e-mail-part-attachment.c
@@ -18,22 +18,153 @@
 
 #include "e-mail-part-attachment.h"
 
-void
-e_mail_part_attachment_free (EMailPartAttachment *empa)
+#define E_MAIL_PART_ATTACHMENT_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_MAIL_PART_ATTACHMENT, EMailPartAttachmentPrivate))
+
+struct _EMailPartAttachmentPrivate {
+       EAttachment *attachment;
+};
+
+enum {
+       PROP_0,
+       PROP_ATTACHMENT
+};
+
+G_DEFINE_TYPE (
+       EMailPartAttachment,
+       e_mail_part_attachment,
+       E_TYPE_MAIL_PART)
+
+static void
+mail_part_attachment_get_property (GObject *object,
+                                   guint property_id,
+                                   GValue *value,
+                                   GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_ATTACHMENT:
+                       g_value_take_object (
+                               value,
+                               e_mail_part_attachment_ref_attachment (
+                               E_MAIL_PART_ATTACHMENT (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_attachment_dispose (GObject *object)
+{
+       EMailPartAttachmentPrivate *priv;
+
+       priv = E_MAIL_PART_ATTACHMENT_GET_PRIVATE (object);
+
+       g_clear_object (&priv->attachment);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_mail_part_attachment_parent_class)->
+               dispose (object);
+}
+
+static void
+mail_part_attachment_finalize (GObject *object)
+{
+       EMailPartAttachment *part = E_MAIL_PART_ATTACHMENT (object);
+
+       g_free (part->attachment_view_part_id);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_mail_part_attachment_parent_class)->
+               finalize (object);
+}
+
+static void
+mail_part_attachment_constructed (GObject *object)
 {
-       g_clear_object (&empa->attachment);
+       EMailPartAttachmentPrivate *priv;
+       CamelMimePart *mime_part;
+       EAttachment *attachment;
+       EMailPart *part;
+       const gchar *cid;
 
-       if (empa->attachment_view_part_id) {
-               g_free (empa->attachment_view_part_id);
-               empa->attachment_view_part_id = NULL;
+       part = E_MAIL_PART (object);
+       priv = E_MAIL_PART_ATTACHMENT_GET_PRIVATE (object);
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_mail_part_attachment_parent_class)->
+               constructed (object);
+
+       e_mail_part_set_mime_type (part, E_MAIL_PART_ATTACHMENT_MIME_TYPE);
+       e_mail_part_set_is_attachment (part, TRUE);
+
+       mime_part = e_mail_part_ref_mime_part (part);
+
+       cid = camel_mime_part_get_content_id (mime_part);
+       if (cid != NULL) {
+               gchar *cid_uri;
+
+               cid_uri = g_strconcat ("cid:", cid, NULL);
+               e_mail_part_set_cid (part, cid_uri);
+               g_free (cid_uri);
        }
+
+       attachment = e_attachment_new ();
+       e_attachment_set_mime_part (attachment, mime_part);
+       priv->attachment = g_object_ref (attachment);
+       g_object_unref (attachment);
+
+       g_object_unref (mime_part);
+}
+
+static void
+e_mail_part_attachment_class_init (EMailPartAttachmentClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (EMailPartAttachmentPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->get_property = mail_part_attachment_get_property;
+       object_class->dispose = mail_part_attachment_dispose;
+       object_class->finalize = mail_part_attachment_finalize;
+       object_class->constructed = mail_part_attachment_constructed;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_ATTACHMENT,
+               g_param_spec_object (
+                       "attachment",
+                       "Attachment",
+                       "The attachment object",
+                       E_TYPE_ATTACHMENT,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_mail_part_attachment_init (EMailPartAttachment *part)
+{
+       part->priv = E_MAIL_PART_ATTACHMENT_GET_PRIVATE (part);
+}
+
+EMailPartAttachment *
+e_mail_part_attachment_new (CamelMimePart *mime_part,
+                            const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+
+       return g_object_new (
+               E_TYPE_MAIL_PART_ATTACHMENT,
+               "id", id, "mime-part", mime_part, NULL);
 }
 
 EAttachment *
 e_mail_part_attachment_ref_attachment (EMailPartAttachment *part)
 {
-       g_return_val_if_fail (part != NULL, NULL);
+       g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT (part), NULL);
 
-       return g_object_ref (part->attachment);
+       return g_object_ref (part->priv->attachment);
 }
 
diff --git a/em-format/e-mail-part-attachment.h b/em-format/e-mail-part-attachment.h
index 24f0cf2..5c9fd61 100644
--- a/em-format/e-mail-part-attachment.h
+++ b/em-format/e-mail-part-attachment.h
@@ -21,28 +21,52 @@
 
 #include <em-format/e-mail-part.h>
 
-#define E_MAIL_PART_ATTACHMENT(part) \
-       ((EMailPartAttachment *) part)
-#define E_IS_MAIL_PART_ATTACHMENT(part) \
-       (E_MAIL_PART_IS (part, EMailPartAttachment))
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_ATTACHMENT \
+       (e_mail_part_attachment_get_type ())
+#define E_MAIL_PART_ATTACHMENT(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART_ATTACHMENT, EMailPartAttachment))
+#define E_MAIL_PART_ATTACHMENT_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART_ATTACHMENT, EMailPartAttachmentClass))
+#define E_IS_MAIL_PART_ATTACHMENT(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_PART_ATTACHMENT))
+#define E_IS_MAIL_PART_ATTACHMENT_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_PART_ATTACHMENT))
+#define E_MAIL_PART_ATTACHMENT_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART_ATTACHMENT, EMailPartAttachmentClass))
 
 #define E_MAIL_PART_ATTACHMENT_MIME_TYPE \
        "application/vnd.evolution.attachment"
 
 G_BEGIN_DECLS
 
-typedef struct _EMailPartAttachment {
+typedef struct _EMailPartAttachment EMailPartAttachment;
+typedef struct _EMailPartAttachmentClass EMailPartAttachmentClass;
+typedef struct _EMailPartAttachmentPrivate EMailPartAttachmentPrivate;
+
+struct _EMailPartAttachment {
        EMailPart parent;
+       EMailPartAttachmentPrivate *priv;
 
-       EAttachment *attachment;
        gchar *attachment_view_part_id;
 
        gboolean shown;
        const gchar *snoop_mime_type;
+};
 
-} EMailPartAttachment;
+struct _EMailPartAttachmentClass {
+       EMailPartClass parent_class;
+};
 
-void           e_mail_part_attachment_free     (EMailPartAttachment *empa);
+GType          e_mail_part_attachment_get_type (void) G_GNUC_CONST;
+EMailPartAttachment *
+               e_mail_part_attachment_new      (CamelMimePart *mime_part,
+                                                const gchar *id);
 EAttachment *  e_mail_part_attachment_ref_attachment
                                                (EMailPartAttachment *part);
 
diff --git a/em-format/e-mail-part-headers.c b/em-format/e-mail-part-headers.c
new file mode 100644
index 0000000..d1398f9
--- /dev/null
+++ b/em-format/e-mail-part-headers.c
@@ -0,0 +1,95 @@
+/*
+ * e-mail-part-headers.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-headers.h"
+
+G_DEFINE_TYPE (
+       EMailPartHeaders,
+       e_mail_part_headers,
+       E_TYPE_MAIL_PART)
+
+static void
+mail_part_headers_constructed (GObject *object)
+{
+       EMailPart *part;
+
+       part = E_MAIL_PART (object);
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_mail_part_headers_parent_class)->
+               constructed (object);
+
+       e_mail_part_set_mime_type (part, E_MAIL_PART_HEADERS_MIME_TYPE);
+}
+
+static void
+mail_part_headers_bind_dom_element (EMailPart *part,
+                                    WebKitDOMElement *element)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *photo;
+       gchar *addr, *uri;
+
+       document = webkit_dom_node_get_owner_document (
+               WEBKIT_DOM_NODE (element));
+       photo = webkit_dom_document_get_element_by_id (
+               document, "__evo-contact-photo");
+
+       /* Contact photos disabled, the <img> tag is not there. */
+       if (photo == NULL)
+               return;
+
+       addr = webkit_dom_element_get_attribute (photo, "data-mailaddr");
+       uri = g_strdup_printf ("mail://contact-photo?mailaddr=%s", addr);
+
+       webkit_dom_html_image_element_set_src (
+               WEBKIT_DOM_HTML_IMAGE_ELEMENT (photo), uri);
+
+       g_free (addr);
+       g_free (uri);
+}
+
+static void
+e_mail_part_headers_class_init (EMailPartHeadersClass *class)
+{
+       GObjectClass *object_class;
+       EMailPartClass *mail_part_class;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->constructed = mail_part_headers_constructed;
+
+       mail_part_class = E_MAIL_PART_CLASS (class);
+       mail_part_class->bind_dom_element = mail_part_headers_bind_dom_element;
+}
+
+static void
+e_mail_part_headers_init (EMailPartHeaders *part)
+{
+}
+
+EMailPart *
+e_mail_part_headers_new (CamelMimePart *mime_part,
+                         const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+
+       return g_object_new (
+               E_TYPE_MAIL_PART_HEADERS,
+               "id", id, "mime-part", mime_part, NULL);
+}
+
diff --git a/em-format/e-mail-part-headers.h b/em-format/e-mail-part-headers.h
new file mode 100644
index 0000000..fb0e0eb
--- /dev/null
+++ b/em-format/e-mail-part-headers.h
@@ -0,0 +1,68 @@
+/*
+ * e-mail-part-headers.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_HEADERS_H
+#define E_MAIL_PART_HEADERS_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_HEADERS \
+       (e_mail_part_headers_get_type ())
+#define E_MAIL_PART_HEADERS(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART_HEADERS, EMailPartHeaders))
+#define E_MAIL_PART_HEADERS_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART_HEADERS, EMailPartHeadersClass))
+#define E_IS_MAIL_PART_HEADERS(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((cls), E_TYPE_MAIL_PART_HEADERS))
+#define E_IS_MAIL_PART_HEADERS_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((obj), E_TYPE_MAIL_PART_HEADERS))
+#define E_MAIL_PART_HEADERS_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART_HEADERS, EMailPartHeadersClass))
+
+#define E_MAIL_PART_HEADERS_MIME_TYPE \
+       "application/vnd.evolution.headers"
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartHeaders EMailPartHeaders;
+typedef struct _EMailPartHeadersClass EMailPartHeadersClass;
+typedef struct _EMailPartHeadersPrivate EMailPartHeadersPrivate;
+
+struct _EMailPartHeaders {
+       EMailPart parent;
+       EMailPartHeadersPrivate *priv;
+};
+
+struct _EMailPartHeadersClass {
+       EMailPartClass parent_class;
+};
+
+GType          e_mail_part_headers_get_type    (void) G_GNUC_CONST;
+EMailPart *    e_mail_part_headers_new         (CamelMimePart *mime_part,
+                                                const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_HEADERS_H */
+
diff --git a/em-format/e-mail-part-image.c b/em-format/e-mail-part-image.c
new file mode 100644
index 0000000..2a70fe9
--- /dev/null
+++ b/em-format/e-mail-part-image.c
@@ -0,0 +1,100 @@
+/*
+ * e-mail-part-image.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-image.h"
+
+G_DEFINE_TYPE (
+       EMailPartImage,
+       e_mail_part_image,
+       E_TYPE_MAIL_PART)
+
+static void
+mail_part_image_constructed (GObject *object)
+{
+       EMailPart *part;
+       CamelMimePart *mime_part;
+       CamelContentType *content_type;
+       const gchar *content_id;
+       const gchar *disposition;
+
+       part = E_MAIL_PART (object);
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_mail_part_image_parent_class)->constructed (object);
+
+       e_mail_part_set_is_attachment (part, TRUE);
+
+       mime_part = e_mail_part_ref_mime_part (part);
+
+       content_id = camel_mime_part_get_content_id (mime_part);
+       content_type = camel_mime_part_get_content_type (mime_part);
+       disposition = camel_mime_part_get_disposition (mime_part);
+
+       if (content_id != NULL) {
+               gchar *cid;
+
+               cid = g_strconcat ("cid:", content_id, NULL);
+               e_mail_part_set_cid (part, cid);
+               g_free (cid);
+       }
+
+       if (content_type != NULL) {
+               gchar *mime_type;
+
+               mime_type = camel_content_type_simple (content_type);
+               e_mail_part_set_mime_type (part, mime_type);
+               g_free (mime_type);
+       } else {
+               e_mail_part_set_mime_type (part, "image/*");
+       }
+
+       if (disposition == NULL)
+               disposition = "inline";
+
+       part->is_hidden =
+               (content_id != NULL) &&
+               (g_ascii_strcasecmp (disposition, "attachment") != 0);
+
+       g_object_unref (mime_part);
+}
+
+static void
+e_mail_part_image_class_init (EMailPartImageClass *class)
+{
+       GObjectClass *object_class;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->constructed = mail_part_image_constructed;
+}
+
+static void
+e_mail_part_image_init (EMailPartImage *part)
+{
+}
+
+EMailPart *
+e_mail_part_image_new (CamelMimePart *mime_part,
+                       const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+
+       return g_object_new (
+               E_TYPE_MAIL_PART_IMAGE,
+               "id", id, "mime-part", mime_part, NULL);
+}
+
diff --git a/em-format/e-mail-part-image.h b/em-format/e-mail-part-image.h
new file mode 100644
index 0000000..0c3e7f4
--- /dev/null
+++ b/em-format/e-mail-part-image.h
@@ -0,0 +1,65 @@
+/*
+ * e-mail-part-image.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_IMAGE_H
+#define E_MAIL_PART_IMAGE_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_IMAGE \
+       (e_mail_part_image_get_type ())
+#define E_MAIL_PART_IMAGE(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART_IMAGE, EMailPartImage))
+#define E_MAIL_PART_IMAGE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART_IMAGE, EMailPartImageClass))
+#define E_IS_MAIL_PART_IMAGE(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_PART_IMAGE))
+#define E_IS_MAIL_PART_IMAGE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_PART_IMAGE))
+#define E_MAIL_PART_IMAGE_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART_IMAGE, EMailPartImageClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartImage EMailPartImage;
+typedef struct _EMailPartImageClass EMailPartImageClass;
+typedef struct _EMailPartImagePrivate EMailPartImagePrivate;
+
+struct _EMailPartImage {
+       EMailPart parent;
+       EMailPartImagePrivate *priv;
+};
+
+struct _EMailPartImageClass {
+       EMailPartClass parent_class;
+};
+
+GType          e_mail_part_image_get_type      (void) G_GNUC_CONST;
+EMailPart *    e_mail_part_image_new           (CamelMimePart *mime_part,
+                                                const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_IMAGE_H */
+
diff --git a/em-format/e-mail-part-list.c b/em-format/e-mail-part-list.c
index f7adcf9..c866e6a 100644
--- a/em-format/e-mail-part-list.c
+++ b/em-format/e-mail-part-list.c
@@ -161,7 +161,7 @@ mail_part_list_dispose (GObject *object)
 
        g_mutex_lock (&priv->queue_lock);
        while (!g_queue_is_empty (&priv->queue))
-               e_mail_part_unref (g_queue_pop_head (&priv->queue));
+               g_object_unref (g_queue_pop_head (&priv->queue));
        g_mutex_unlock (&priv->queue_lock);
 
        /* Chain up to parent's dispose() method. */
@@ -295,7 +295,7 @@ e_mail_part_list_add_part (EMailPartList *part_list,
 
        g_queue_push_tail (
                &part_list->priv->queue,
-               e_mail_part_ref (part));
+               g_object_ref (part));
 
        g_mutex_unlock (&part_list->priv->queue_lock);
 }
@@ -327,7 +327,7 @@ e_mail_part_list_ref_part (EMailPartList *part_list,
                        candidate_id = e_mail_part_get_id (candidate);
 
                if (g_strcmp0 (candidate_id, part_id) == 0) {
-                       match = e_mail_part_ref (candidate);
+                       match = g_object_ref (candidate);
                        break;
                }
        }
@@ -348,7 +348,7 @@ e_mail_part_list_ref_part (EMailPartList *part_list,
  * of #EMailPart instances is queued.
  *
  * Each #EMailPart is referenced for thread-safety and should be unreferenced
- * with e_mail_part_unref().
+ * with g_object_unref().
  *
  * Returns: the number of parts added to @result_queue
  **/
@@ -386,7 +386,7 @@ e_mail_part_list_queue_parts (EMailPartList *part_list,
                if (part == NULL)
                        continue;
 
-               g_queue_push_tail (result_queue, e_mail_part_ref (part));
+               g_queue_push_tail (result_queue, g_object_ref (part));
                parts_queued++;
        }
 
diff --git a/em-format/e-mail-part.c b/em-format/e-mail-part.c
index 2339e0e..abd405d 100644
--- a/em-format/e-mail-part.c
+++ b/em-format/e-mail-part.c
@@ -22,8 +22,6 @@
  * The #EMailPart is a wrapper around #CamelMimePart which holds additional
  * information about the mime part, like it's ID, encryption type etc.
  *
- * #EMailPart is not GObject-based, but has a simple reference counting.
- *
  * Each #EMailPart must have a unique ID. The ID is a dot-separated
  * hierarchical description of the location of the part within the email
  * message.
@@ -33,12 +31,34 @@
 
 #include <string.h>
 
+#define E_MAIL_PART_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_MAIL_PART, EMailPartPrivate))
+
 struct _EMailPartPrivate {
-       guint ref_cnt;
-       gsize instance_size;
-       GFreeFunc free_func;
+       CamelMimePart *mime_part;
+
+       gchar *id;
+       gchar *cid;
+       gchar *mime_type;
+
+       gboolean is_attachment;
+};
+
+enum {
+       PROP_0,
+       PROP_CID,
+       PROP_ID,
+       PROP_IS_ATTACHMENT,
+       PROP_MIME_PART,
+       PROP_MIME_TYPE
 };
 
+G_DEFINE_TYPE (
+       EMailPart,
+       e_mail_part,
+       G_TYPE_OBJECT)
+
 static void
 mail_part_validity_pair_free (gpointer ptr)
 {
@@ -52,185 +72,296 @@ mail_part_validity_pair_free (gpointer ptr)
 }
 
 static void
-mail_part_free (EMailPart *part)
+mail_part_set_id (EMailPart *part,
+                  const gchar *id)
 {
-       EMailPartValidityPair *pair;
+       g_return_if_fail (part->priv->id == NULL);
 
-       if (!part)
-               return;
+       part->priv->id = g_strdup (id);
+}
 
-       if (part->part) {
-               g_object_unref (part->part);
-               part->part = NULL;
-       }
+static void
+mail_part_set_mime_part (EMailPart *part,
+                         CamelMimePart *mime_part)
+{
+       g_return_if_fail (part->priv->mime_part == NULL);
 
-       if (part->cid) {
-               g_free (part->cid);
-               part->cid = NULL;
-       }
+       /* The CamelMimePart is optional. */
+       if (mime_part != NULL)
+               part->priv->mime_part = g_object_ref (mime_part);
+}
 
-       if (part->mime_type) {
-               g_free (part->mime_type);
-               part->mime_type = NULL;
+static void
+mail_part_set_property (GObject *object,
+                        guint property_id,
+                        const GValue *value,
+                        GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CID:
+                       e_mail_part_set_cid (
+                               E_MAIL_PART (object),
+                               g_value_get_string (value));
+                       return;
+
+               case PROP_ID:
+                       mail_part_set_id (
+                               E_MAIL_PART (object),
+                               g_value_get_string (value));
+                       return;
+
+               case PROP_IS_ATTACHMENT:
+                       e_mail_part_set_is_attachment (
+                               E_MAIL_PART (object),
+                               g_value_get_boolean (value));
+                       return;
+
+               case PROP_MIME_PART:
+                       mail_part_set_mime_part (
+                               E_MAIL_PART (object),
+                               g_value_get_object (value));
+                       return;
+
+               case PROP_MIME_TYPE:
+                       e_mail_part_set_mime_type (
+                               E_MAIL_PART (object),
+                               g_value_get_string (value));
+                       return;
        }
 
-       while ((pair = g_queue_pop_head (&part->validities)) != NULL)
-               mail_part_validity_pair_free (pair);
-
-       if (part->priv->free_func) {
-               part->priv->free_func (part);
-               part->priv->free_func = NULL;
-       }
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
 
-       if (part->id) {
-               g_free (part->id);
-               part->id = NULL;
+static void
+mail_part_get_property (GObject *object,
+                        guint property_id,
+                        GValue *value,
+                        GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CID:
+                       g_value_set_string (
+                               value,
+                               e_mail_part_get_cid (
+                               E_MAIL_PART (object)));
+                       return;
+
+               case PROP_ID:
+                       g_value_set_string (
+                               value,
+                               e_mail_part_get_id (
+                               E_MAIL_PART (object)));
+                       return;
+
+               case PROP_IS_ATTACHMENT:
+                       g_value_set_boolean (
+                               value,
+                               e_mail_part_get_is_attachment (
+                               E_MAIL_PART (object)));
+                       return;
+
+               case PROP_MIME_PART:
+                       g_value_take_object (
+                               value,
+                               e_mail_part_ref_mime_part (
+                               E_MAIL_PART (object)));
+                       return;
+
+               case PROP_MIME_TYPE:
+                       g_value_set_string (
+                               value,
+                               e_mail_part_get_mime_type (
+                               E_MAIL_PART (object)));
+                       return;
        }
 
-       g_free (part->priv);
-       part->priv = NULL;
-
-       g_free (part);
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-/**
- * e_mail_part_new:
- * @part: (allow-none) a #CamelMimePart or %NULL
- * @id: part ID
- *
- * Creates a new #EMailPart for given mime part.
- *
- * Return value: a new #EMailPart
- */
-EMailPart *
-e_mail_part_new (CamelMimePart *part,
-                 const gchar *id)
+static void
+mail_part_dispose (GObject *object)
 {
-       return e_mail_part_subclass_new (part, id, sizeof (EMailPart), NULL);
-}
+       EMailPartPrivate *priv;
 
-/**
- * e_mail_part_new:
- * @part: (allow-none) a #CamelMimePart or %NULL
- * @id: part ID
- * @size: Size of the EMailPart subclass
- *
- * Allocates a @size bytes representing an #EMailPart subclass.
- *
- * Return value: a new #EMailPart-based object
- */
-EMailPart *
-e_mail_part_subclass_new (CamelMimePart *part,
-                          const gchar *id,
-                          gsize size,
-                          GFreeFunc free_func)
-{
-       EMailPart *mail_part;
+       priv = E_MAIL_PART_GET_PRIVATE (object);
 
-       g_return_val_if_fail (size >= sizeof (EMailPart), NULL);
+       g_clear_object (&priv->mime_part);
 
-       mail_part = g_malloc0 (size);
-       mail_part->priv = g_new0 (EMailPartPrivate, 1);
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_mail_part_parent_class)->dispose (object);
+}
 
-       mail_part->priv->ref_cnt = 1;
-       mail_part->priv->free_func = free_func;
-       mail_part->priv->instance_size = size;
+static void
+mail_part_finalize (GObject *object)
+{
+       EMailPart *part = E_MAIL_PART (object);
+       EMailPartValidityPair *pair;
 
-       if (part) {
-               mail_part->part = g_object_ref (part);
-       }
+       g_free (part->priv->id);
+       g_free (part->priv->cid);
+       g_free (part->priv->mime_type);
 
-       if (id) {
-               mail_part->id = g_strdup (id);
-       }
+       while ((pair = g_queue_pop_head (&part->validities)) != NULL)
+               mail_part_validity_pair_free (pair);
 
-       return mail_part;
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_mail_part_parent_class)->finalize (object);
 }
 
-EMailPart *
-e_mail_part_ref (EMailPart *part)
+static void
+e_mail_part_class_init (EMailPartClass *class)
 {
-       g_return_val_if_fail (part != NULL, NULL);
-       g_return_val_if_fail (part->priv != NULL, NULL);
-
-       g_atomic_int_inc (&part->priv->ref_cnt);
-
-       return part;
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (EMailPartPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = mail_part_set_property;
+       object_class->get_property = mail_part_get_property;
+       object_class->dispose = mail_part_dispose;
+       object_class->finalize = mail_part_finalize;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_CID,
+               g_param_spec_string (
+                       "cid",
+                       "Content ID",
+                       "The MIME Content-ID",
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_ID,
+               g_param_spec_string (
+                       "id",
+                       "Part ID",
+                       "The part ID",
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_IS_ATTACHMENT,
+               g_param_spec_boolean (
+                       "is-attachment",
+                       "Is Attachment",
+                       "Format the part as an attachment",
+                       FALSE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_MIME_PART,
+               g_param_spec_object (
+                       "mime-part",
+                       "MIME Part",
+                       "The MIME part",
+                       CAMEL_TYPE_MIME_PART,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_MIME_TYPE,
+               g_param_spec_string (
+                       "mime-type",
+                       "MIME Type",
+                       "The MIME type",
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_STATIC_STRINGS));
 }
 
-void
-e_mail_part_unref (EMailPart *part)
+static void
+e_mail_part_init (EMailPart *part)
 {
-       g_return_if_fail (part != NULL);
-       g_return_if_fail (part->priv != NULL);
-
-       if (g_atomic_int_dec_and_test (&part->priv->ref_cnt)) {
-               mail_part_free (part);
-       }
+       part->priv = E_MAIL_PART_GET_PRIVATE (part);
 }
 
-gsize
-e_mail_part_get_instance_size (EMailPart *part)
+/**
+ * e_mail_part_new:
+ * @mime_part: (allow-none) a #CamelMimePart or %NULL
+ * @id: part ID
+ *
+ * Creates a new #EMailPart for the given @mime_part.
+ *
+ * Return value: a new #EMailPart
+ */
+EMailPart *
+e_mail_part_new (CamelMimePart *mime_part,
+                 const gchar *id)
 {
-       g_return_val_if_fail (part != NULL, 0);
+       g_return_val_if_fail (id != NULL, NULL);
 
-       return part->priv->instance_size;
+       return g_object_new (
+               E_TYPE_MAIL_PART,
+               "id", id, "mime-part", mime_part, NULL);
 }
 
 const gchar *
 e_mail_part_get_id (EMailPart *part)
 {
-       g_return_val_if_fail (part != NULL, NULL);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
 
-       return part->id;
+       return part->priv->id;
 }
 
 const gchar *
 e_mail_part_get_cid (EMailPart *part)
 {
-       g_return_val_if_fail (part != NULL, NULL);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
 
-       return part->cid;
+       return part->priv->cid;
 }
 
 void
 e_mail_part_set_cid (EMailPart *part,
                      const gchar *cid)
 {
-       g_return_if_fail (part != NULL);
+       g_return_if_fail (E_IS_MAIL_PART (part));
+
+       g_free (part->priv->cid);
+       part->priv->cid = g_strdup (cid);
 
-       g_free (part->cid);
-       part->cid = g_strdup (cid);
+       g_object_notify (G_OBJECT (part), "cid");
 }
 
 gboolean
 e_mail_part_id_has_prefix (EMailPart *part,
                            const gchar *prefix)
 {
-       g_return_val_if_fail (part != NULL, FALSE);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
        g_return_val_if_fail (prefix != NULL, FALSE);
 
-       return g_str_has_prefix (part->id, prefix);
+       return g_str_has_prefix (part->priv->id, prefix);
 }
 
 gboolean
 e_mail_part_id_has_suffix (EMailPart *part,
                            const gchar *suffix)
 {
-       g_return_val_if_fail (part != NULL, FALSE);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
        g_return_val_if_fail (suffix != NULL, FALSE);
 
-       return g_str_has_suffix (part->id, suffix);
+       return g_str_has_suffix (part->priv->id, suffix);
 }
 
 gboolean
 e_mail_part_id_has_substr (EMailPart *part,
                            const gchar *substr)
 {
-       g_return_val_if_fail (part != NULL, FALSE);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
        g_return_val_if_fail (substr != NULL, FALSE);
 
-       return (strstr (part->id, substr) != NULL);
+       return (strstr (part->priv->id, substr) != NULL);
 }
 
 CamelMimePart *
@@ -238,10 +369,10 @@ e_mail_part_ref_mime_part (EMailPart *part)
 {
        CamelMimePart *mime_part = NULL;
 
-       g_return_val_if_fail (part != NULL, NULL);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
 
-       if (part->part != NULL)
-               mime_part = g_object_ref (part->part);
+       if (part->priv->mime_part != NULL)
+               mime_part = g_object_ref (part->priv->mime_part);
 
        return mime_part;
 }
@@ -249,44 +380,66 @@ e_mail_part_ref_mime_part (EMailPart *part)
 const gchar *
 e_mail_part_get_mime_type (EMailPart *part)
 {
-       g_return_val_if_fail (part != NULL, NULL);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
 
-       return part->mime_type;
+       return part->priv->mime_type;
 }
 
 void
 e_mail_part_set_mime_type (EMailPart *part,
                            const gchar *mime_type)
 {
-       g_return_if_fail (part != NULL);
+       g_return_if_fail (E_IS_MAIL_PART (part));
 
-       if (g_strcmp0 (mime_type, part->mime_type) == 0)
+       if (g_strcmp0 (mime_type, part->priv->mime_type) == 0)
                return;
 
-       g_free (part->mime_type);
-       part->mime_type = g_strdup (mime_type);
+       g_free (part->priv->mime_type);
+       part->priv->mime_type = g_strdup (mime_type);
+
+       g_object_notify (G_OBJECT (part), "mime-type");
 }
 
 gboolean
 e_mail_part_get_is_attachment (EMailPart *part)
 {
-       g_return_val_if_fail (part != NULL, FALSE);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
 
-       return part->is_attachment;
+       return part->priv->is_attachment;
 }
 
 void
 e_mail_part_set_is_attachment (EMailPart *part,
                                gboolean is_attachment)
 {
-       g_return_if_fail (part != NULL);
+       g_return_if_fail (E_IS_MAIL_PART (part));
+
+       if (is_attachment == part->priv->is_attachment)
+               return;
+
+       part->priv->is_attachment = is_attachment;
+
+       g_object_notify (G_OBJECT (part), "is-attachment");
+}
+
+void
+e_mail_part_bind_dom_element (EMailPart *part,
+                              WebKitDOMElement *element)
+{
+       EMailPartClass *class;
+
+       g_return_if_fail (E_IS_MAIL_PART (part));
+       g_return_if_fail (WEBKIT_DOM_IS_ELEMENT (element));
 
-       part->is_attachment = is_attachment;
+       class = E_MAIL_PART_GET_CLASS (part);
+
+       if (class->bind_dom_element != NULL)
+               class->bind_dom_element (part, element);
 }
 
 static EMailPartValidityPair *
 mail_part_find_validity_pair (EMailPart *part,
-                              guint32 validity_type)
+                              EMailPartValidityFlags validity_type)
 {
        GList *head, *link;
 
@@ -319,13 +472,16 @@ mail_part_find_validity_pair (EMailPart *part,
 void
 e_mail_part_update_validity (EMailPart *part,
                              CamelCipherValidity *validity,
-                             guint32 validity_type)
+                             EMailPartValidityFlags validity_type)
 {
        EMailPartValidityPair *pair;
+       EMailPartValidityFlags mask;
+
+       g_return_if_fail (E_IS_MAIL_PART (part));
 
-       g_return_if_fail (part != NULL);
+       mask = E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SMIME;
 
-       pair = mail_part_find_validity_pair (part, validity_type & (E_MAIL_PART_VALIDITY_PGP | 
E_MAIL_PART_VALIDITY_SMIME));
+       pair = mail_part_find_validity_pair (part, validity_type & mask);
        if (pair != NULL) {
                pair->validity_type |= validity_type;
                camel_cipher_validity_envelope (pair->validity, validity);
@@ -352,21 +508,21 @@ e_mail_part_update_validity (EMailPart *part,
  */
 CamelCipherValidity *
 e_mail_part_get_validity (EMailPart *part,
-                          guint32 validity_type)
+                          EMailPartValidityFlags validity_type)
 {
        EMailPartValidityPair *pair;
 
-       g_return_val_if_fail (part != NULL, NULL);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
 
        pair = mail_part_find_validity_pair (part, validity_type);
 
-       return pair ? pair->validity : NULL;
+       return (pair != NULL) ? pair->validity : NULL;
 }
 
 gboolean
 e_mail_part_has_validity (EMailPart *part)
 {
-       g_return_val_if_fail (part != NULL, FALSE);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
 
        return !g_queue_is_empty (&part->validities);
 }
@@ -377,7 +533,7 @@ e_mail_part_get_validity_flags (EMailPart *part)
        EMailPartValidityFlags flags = 0;
        GList *head, *link;
 
-       g_return_val_if_fail (part != NULL, 0);
+       g_return_val_if_fail (E_IS_MAIL_PART (part), 0);
 
        head = g_queue_peek_head_link (&part->validities);
 
diff --git a/em-format/e-mail-part.h b/em-format/e-mail-part.h
index cb25cb3..6ead93b 100644
--- a/em-format/e-mail-part.h
+++ b/em-format/e-mail-part.h
@@ -24,18 +24,31 @@
 
 #include <e-util/e-util.h>
 
-#define E_MAIL_PART_IS(p,s_t) \
-               ((p != NULL) && (e_mail_part_get_instance_size (p) == sizeof (s_t)))
-#define E_MAIL_PART(o) ((EMailPart *) o)
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART \
+       (e_mail_part_get_type ())
+#define E_MAIL_PART(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART, EMailPart))
+#define E_MAIL_PART_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART, EMailPartClass))
+#define E_IS_MAIL_PART(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_PART))
+#define E_IS_MAIL_PART_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_PART))
+#define E_MAIL_PART_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART, EMailPartClass))
 
 G_BEGIN_DECLS
 
 typedef struct _EMailPart EMailPart;
+typedef struct _EMailPartClass EMailPartClass;
 typedef struct _EMailPartPrivate EMailPartPrivate;
 
-typedef void   (*EMailPartDOMBindFunc) (EMailPart *part,
-                                        WebKitDOMElement *element);
-
 typedef enum {
        E_MAIL_PART_VALIDITY_NONE      = 0,
        E_MAIL_PART_VALIDITY_PGP       = 1 << 0,
@@ -52,19 +65,11 @@ struct _EMailPartValidityPair {
 };
 
 struct _EMailPart {
+       GObject parent;
        EMailPartPrivate *priv;
 
-       EMailPartDOMBindFunc bind_func;
-
-       CamelMimePart *part;
-       gchar *id;
-       gchar *cid;
-       gchar *mime_type;
-
        GQueue validities;  /* element-type: EMailPartValidityPair */
 
-       gint is_attachment: 1;
-
        /* Whether the part should be rendered or not.
         * This is used for example to prevent images
         * related to text/html parts from being
@@ -83,18 +88,16 @@ struct _EMailPart {
        gint is_error: 1;
 };
 
-EMailPart *    e_mail_part_new                 (CamelMimePart *part,
-                                                const gchar *id);
-EMailPart *    e_mail_part_subclass_new        (CamelMimePart *part,
-                                                const gchar *id,
-                                                gsize size,
-                                                GFreeFunc free_func);
-
-EMailPart *    e_mail_part_ref                 (EMailPart *part);
-void           e_mail_part_unref               (EMailPart *part);
+struct _EMailPartClass {
+       GObjectClass parent_class;
 
-gsize          e_mail_part_get_instance_size   (EMailPart *part);
+       void            (*bind_dom_element)     (EMailPart *part,
+                                                WebKitDOMElement *element);
+};
 
+GType          e_mail_part_get_type            (void) G_GNUC_CONST;
+EMailPart *    e_mail_part_new                 (CamelMimePart *mime_part,
+                                                const gchar *id);
 const gchar *  e_mail_part_get_id              (EMailPart *part);
 const gchar *  e_mail_part_get_cid             (EMailPart *part);
 void           e_mail_part_set_cid             (EMailPart *part,
@@ -112,12 +115,14 @@ void              e_mail_part_set_mime_type       (EMailPart *part,
 gboolean       e_mail_part_get_is_attachment   (EMailPart *part);
 void           e_mail_part_set_is_attachment   (EMailPart *part,
                                                 gboolean is_attachment);
+void           e_mail_part_bind_dom_element    (EMailPart *part,
+                                                WebKitDOMElement *element);
 void           e_mail_part_update_validity     (EMailPart *part,
                                                 CamelCipherValidity *validity,
-                                                guint32 validity_type);
+                                                EMailPartValidityFlags validity_type);
 CamelCipherValidity *
                e_mail_part_get_validity        (EMailPart *part,
-                                                guint32 validity_type);
+                                                EMailPartValidityFlags validity_type);
 gboolean       e_mail_part_has_validity        (EMailPart *part);
 EMailPartValidityFlags
                e_mail_part_get_validity_flags  (EMailPart *part);
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 3861fbb..a809d23 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -991,7 +991,7 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
 
 exit:
        if (part != NULL)
-               e_mail_part_unref (part);
+               g_object_unref (part);
 
        return widget;
 }
@@ -1217,12 +1217,12 @@ mail_parts_bind_dom (GObject *object,
                part_id = e_mail_part_get_id (part);
                element = find_element_by_id (document, part_id);
 
-               if (element != NULL && part->bind_func != NULL)
-                       part->bind_func (part, element);
+               if (element != NULL)
+                       e_mail_part_bind_dom_element (part, element);
        }
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 }
 
 static void
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index 79945dc..a49baf7 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -1410,7 +1410,7 @@ e_mail_reader_reply_to_message (EMailReader *reader,
                                        validity_smime_sum |= vpair->validity_type;
                        }
 
-                       e_mail_part_unref (part);
+                       g_object_unref (part);
                }
        }
 
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index b4ecfce..892065c 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -169,7 +169,7 @@ handle_mail_request (GSimpleAsyncResult *res,
                                        mime_type, cancellable);
                        }
 
-                       e_mail_part_unref (part);
+                       g_object_unref (part);
                } else {
                        g_warning ("Failed to lookup requested part '%s' - this should not happen!", part_id);
                }
diff --git a/mail/em-utils.c b/mail/em-utils.c
index 6a12e3c..7af920c 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -1341,7 +1341,7 @@ em_utils_message_to_html (CamelSession *session,
        }
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 
        if (validity_found != NULL)
                *validity_found = is_validity_found;
diff --git a/modules/audio-inline/Makefile.am b/modules/audio-inline/Makefile.am
index b53c291..ad75a62 100644
--- a/modules/audio-inline/Makefile.am
+++ b/modules/audio-inline/Makefile.am
@@ -15,6 +15,7 @@ module_audio_inline_la_SOURCES =                              \
        e-mail-formatter-audio.h                                        \
        e-mail-parser-audio.c                                           \
        e-mail-parser-audio.h                                           \
+       e-mail-part-audio.c                                             \
        e-mail-part-audio.h                                             \
        evolution-module-audio-inline.c
 
diff --git a/modules/audio-inline/e-mail-formatter-audio.c b/modules/audio-inline/e-mail-formatter-audio.c
index b700651..fc27bb7 100644
--- a/modules/audio-inline/e-mail-formatter-audio.c
+++ b/modules/audio-inline/e-mail-formatter-audio.c
@@ -287,7 +287,8 @@ mail_formatter_audio_get_widget (EMailFormatterExtension *extension,
        GtkWidget *box;
        EMailPartAudio *ai_part;
 
-       g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAudio), NULL);
+       g_return_val_if_fail (E_IS_MAIL_PART_AUDIO (part), NULL);
+
        ai_part = (EMailPartAudio *) part;
 
        /* it is OK to call UI functions here, since we are called from UI thread */
diff --git a/modules/audio-inline/e-mail-parser-audio.c b/modules/audio-inline/e-mail-parser-audio.c
index c81a94b..c9c4133 100644
--- a/modules/audio-inline/e-mail-parser-audio.c
+++ b/modules/audio-inline/e-mail-parser-audio.c
@@ -23,7 +23,6 @@
 #include <gtk/gtk.h>
 #include <glib.h>
 #include <glib/gi18n.h>
-#include <glib/gstdio.h>
 
 #include "e-mail-parser-audio.h"
 #include "e-mail-part-audio.h"
@@ -75,33 +74,6 @@ static const gchar *parser_mime_types[] = {
        NULL
 };
 
-static void
-mail_part_audio_free (EMailPart *mail_part)
-{
-       EMailPartAudio *ai_part = (EMailPartAudio *) mail_part;
-
-       g_clear_object (&ai_part->play_button);
-       g_clear_object (&ai_part->pause_button);
-       g_clear_object (&ai_part->stop_button);
-
-       if (ai_part->filename) {
-               g_unlink (ai_part->filename);
-               g_free (ai_part->filename);
-               ai_part->filename = NULL;
-       }
-
-       if (ai_part->bus_id) {
-               g_source_remove (ai_part->bus_id);
-               ai_part->bus_id = 0;
-       }
-
-       if (ai_part->playbin) {
-               gst_element_set_state (ai_part->playbin, GST_STATE_NULL);
-               gst_object_unref (ai_part->playbin);
-               ai_part->playbin = NULL;
-       }
-}
-
 static gint
 mail_parser_audio_parse (EMailParserExtension *extension,
                          EMailParser *parser,
@@ -110,7 +82,7 @@ mail_parser_audio_parse (EMailParserExtension *extension,
                          GCancellable *cancellable,
                          GQueue *out_mail_queue)
 {
-       EMailPartAudio *mail_part;
+       EMailPart *mail_part;
        GQueue work_queue = G_QUEUE_INIT;
        gint len;
        gint n_parts_added = 0;
@@ -120,12 +92,8 @@ mail_parser_audio_parse (EMailParserExtension *extension,
 
        d (printf ("audio formatter: format classid %s\n", part_id->str));
 
-       mail_part = (EMailPartAudio *) e_mail_part_subclass_new (
-               part, part_id->str, sizeof (EMailPartAudio),
-               (GFreeFunc) mail_part_audio_free);
-       mail_part->parent.mime_type = camel_content_type_simple (
-               camel_mime_part_get_content_type (part));
-       mail_part->parent.is_attachment = TRUE;
+       mail_part = e_mail_part_audio_new (part, part_id->str);
+
        g_string_truncate (part_id, len);
 
        g_queue_push_tail (&work_queue, mail_part);
diff --git a/modules/audio-inline/e-mail-part-audio.c b/modules/audio-inline/e-mail-part-audio.c
new file mode 100644
index 0000000..0c8ae7f
--- /dev/null
+++ b/modules/audio-inline/e-mail-part-audio.c
@@ -0,0 +1,142 @@
+/*
+ * e-mail-part-audio.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-audio.h"
+
+#include <glib/gstdio.h>
+
+#define E_MAIL_PART_AUDIO_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_MAIL_PART_AUDIO, EMailPartAudioPrivate))
+
+struct _EMailPartAudioPrivate {
+       gint placeholder;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+       EMailPartAudio,
+       e_mail_part_audio,
+       E_TYPE_MAIL_PART)
+
+static void
+mail_part_audio_dispose (GObject *object)
+{
+       EMailPartAudio *part = E_MAIL_PART_AUDIO (object);
+
+       if (part->bus_id > 0) {
+               g_source_remove (part->bus_id);
+               part->bus_id = 0;
+       }
+
+       if (part->playbin != NULL) {
+               gst_element_set_state (part->playbin, GST_STATE_NULL);
+               gst_object_unref (part->playbin);
+               part->playbin = NULL;
+       }
+
+       g_clear_object (&part->play_button);
+       g_clear_object (&part->pause_button);
+       g_clear_object (&part->stop_button);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_mail_part_audio_parent_class)->dispose (object);
+}
+
+static void
+mail_part_audio_finalize (GObject *object)
+{
+       EMailPartAudio *part = E_MAIL_PART_AUDIO (object);
+
+       if (part->filename != NULL) {
+               g_unlink (part->filename);
+               g_free (part->filename);
+       }
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_mail_part_audio_parent_class)->finalize (object);
+}
+
+static void
+mail_part_audio_constructed (GObject *object)
+{
+       EMailPart *part;
+       CamelMimePart *mime_part;
+       CamelContentType *content_type;
+       gchar *mime_type;
+
+       part = E_MAIL_PART (object);
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_mail_part_audio_parent_class)->constructed (object);
+
+       e_mail_part_set_is_attachment (part, TRUE);
+
+       mime_part = e_mail_part_ref_mime_part (part);
+
+       content_type = camel_mime_part_get_content_type (mime_part);
+       mime_type = camel_content_type_simple (content_type);
+       e_mail_part_set_mime_type (part, mime_type);
+       g_free (mime_type);
+
+       g_object_unref (mime_part);
+}
+
+static void
+e_mail_part_audio_class_init (EMailPartAudioClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (EMailPartAudioPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = mail_part_audio_dispose;
+       object_class->finalize = mail_part_audio_finalize;
+       object_class->constructed = mail_part_audio_constructed;
+}
+
+static void
+e_mail_part_audio_class_finalize (EMailPartAudioClass *class)
+{
+}
+
+static void
+e_mail_part_audio_init (EMailPartAudio *part)
+{
+       part->priv = E_MAIL_PART_AUDIO_GET_PRIVATE (part);
+}
+
+void
+e_mail_part_audio_type_register (GTypeModule *type_module)
+{
+       /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+        *     function, so we have to wrap it with a public function in
+        *     order to register types from a separate compilation unit. */
+       e_mail_part_audio_register_type (type_module);
+}
+
+EMailPart *
+e_mail_part_audio_new (CamelMimePart *mime_part,
+                       const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+
+       return g_object_new (
+               E_TYPE_MAIL_PART_AUDIO,
+               "id", id, "mime-part", mime_part, NULL);
+}
+
diff --git a/modules/audio-inline/e-mail-part-audio.h b/modules/audio-inline/e-mail-part-audio.h
index 628da0b..42459e0 100644
--- a/modules/audio-inline/e-mail-part-audio.h
+++ b/modules/audio-inline/e-mail-part-audio.h
@@ -19,17 +19,37 @@
 #ifndef E_MAIL_PART_AUDIO_H
 #define E_MAIL_PART_AUDIO_H
 
-#include <glib-object.h>
-
 #include <em-format/e-mail-part.h>
 #include <gst/gst.h>
 
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_AUDIO \
+       (e_mail_part_audio_get_type ())
+#define E_MAIL_PART_AUDIO(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART_AUDIO, EMailPartAudio))
+#define E_MAIL_PART_AUDIO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART_AUDIO, EMailPartAudioClass))
+#define E_IS_MAIL_PART_AUDIO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_PART_AUDIO))
+#define E_IS_MAIL_PART_AUDIO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_PART_AUDIO))
+#define E_MAIL_PART_AUDIO_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART_AUDIO, EMailPartAudioClass))
+
 G_BEGIN_DECLS
 
 typedef struct _EMailPartAudio EMailPartAudio;
+typedef struct _EMailPartAudioClass EMailPartAudioClass;
+typedef struct _EMailPartAudioPrivate EMailPartAudioPrivate;
 
 struct _EMailPartAudio {
        EMailPart parent;
+       EMailPartAudioPrivate *priv;
 
        gchar *filename;
        GstElement *playbin;
@@ -40,6 +60,15 @@ struct _EMailPartAudio {
        GtkWidget  *stop_button;
 };
 
+struct _EMailPartAudioClass {
+       EMailPartClass parent_class;
+};
+
+GType          e_mail_part_audio_get_type      (void) G_GNUC_CONST;
+void           e_mail_part_audio_type_register (GTypeModule *type_module);
+EMailPart *    e_mail_part_audio_new           (CamelMimePart *mime_part,
+                                                const gchar *id);
+
 G_END_DECLS
 
 #endif /* E_MAIL_PART_AUDIO_H */
diff --git a/modules/audio-inline/evolution-module-audio-inline.c 
b/modules/audio-inline/evolution-module-audio-inline.c
index d58883a..678bfe4 100644
--- a/modules/audio-inline/evolution-module-audio-inline.c
+++ b/modules/audio-inline/evolution-module-audio-inline.c
@@ -18,6 +18,7 @@
 
 #include "e-mail-formatter-audio.h"
 #include "e-mail-parser-audio.h"
+#include "e-mail-part-audio.h"
 
 #include <gmodule.h>
 
@@ -28,6 +29,7 @@ const gchar * g_module_check_init (GModule *module);
 G_MODULE_EXPORT void
 e_module_load (GTypeModule *type_module)
 {
+       e_mail_part_audio_type_register (type_module);
        e_mail_parser_audio_type_register (type_module);
        e_mail_formatter_audio_type_register (type_module);
 }
diff --git a/modules/itip-formatter/Makefile.am b/modules/itip-formatter/Makefile.am
index abb45f3..240e09f 100644
--- a/modules/itip-formatter/Makefile.am
+++ b/modules/itip-formatter/Makefile.am
@@ -20,6 +20,7 @@ module_itip_formatter_la_SOURCES =                                    \
        e-mail-formatter-itip.h                                         \
        e-mail-parser-itip.c                                            \
        e-mail-parser-itip.h                                            \
+       e-mail-part-itip.c                                              \
        e-mail-part-itip.h                                              \
        e-source-conflict-search.c                                      \
        e-source-conflict-search.h                                      \
diff --git a/modules/itip-formatter/e-mail-parser-itip.c b/modules/itip-formatter/e-mail-parser-itip.c
index 088f79d..04c08e9 100644
--- a/modules/itip-formatter/e-mail-parser-itip.c
+++ b/modules/itip-formatter/e-mail-parser-itip.c
@@ -62,106 +62,6 @@ static const gchar *parser_mime_types[] = {
        NULL
 };
 
-static void
-mail_part_itip_free (EMailPart *mail_part)
-{
-       EMailPartItip *pitip = (EMailPartItip *) mail_part;
-
-       g_cancellable_cancel (pitip->cancellable);
-       g_clear_object (&pitip->cancellable);
-       g_clear_object (&pitip->client_cache);
-
-       g_free (pitip->vcalendar);
-       pitip->vcalendar = NULL;
-
-       if (pitip->comp) {
-               g_object_unref (pitip->comp);
-               pitip->comp = NULL;
-       }
-
-       if (pitip->top_level) {
-               icalcomponent_free (pitip->top_level);
-               pitip->top_level = NULL;
-       }
-
-       if (pitip->main_comp) {
-               icalcomponent_free (pitip->main_comp);
-               pitip->main_comp = NULL;
-       }
-       pitip->ical_comp = NULL;
-
-       g_free (pitip->calendar_uid);
-       pitip->calendar_uid = NULL;
-
-       g_free (pitip->from_address);
-       pitip->from_address = NULL;
-       g_free (pitip->from_name);
-       pitip->from_name = NULL;
-       g_free (pitip->to_address);
-       pitip->to_address = NULL;
-       g_free (pitip->to_name);
-       pitip->to_name = NULL;
-       g_free (pitip->delegator_address);
-       pitip->delegator_address = NULL;
-       g_free (pitip->delegator_name);
-       pitip->delegator_name = NULL;
-       g_free (pitip->my_address);
-       pitip->my_address = NULL;
-       g_free (pitip->uid);
-       g_hash_table_destroy (pitip->real_comps);
-
-       g_clear_object (&pitip->view);
-}
-
-/******************************************************************************/
-
-static void
-bind_itip_view (EMailPart *part,
-                WebKitDOMElement *element)
-{
-       GString *buffer;
-       WebKitDOMDocument *document;
-       ItipView *view;
-       EMailPartItip *pitip;
-
-       if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
-
-               WebKitDOMNodeList *nodes;
-               guint length, i;
-
-               nodes = webkit_dom_element_get_elements_by_tag_name (
-                               element, "iframe");
-               length = webkit_dom_node_list_get_length (nodes);
-               for (i = 0; i < length; i++) {
-
-                       element = WEBKIT_DOM_ELEMENT (
-                                       webkit_dom_node_list_item (nodes, i));
-                       break;
-               }
-
-       }
-
-       g_return_if_fail (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element));
-
-       buffer = g_string_new ("");
-       document = webkit_dom_html_iframe_element_get_content_document (
-                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
-       pitip = E_MAIL_PART_ITIP (part);
-
-       view = itip_view_new (pitip, pitip->client_cache);
-       g_object_set_data_full (
-               G_OBJECT (element), "view", view,
-               (GDestroyNotify) g_object_unref);
-
-       itip_view_create_dom_bindings (
-               view, webkit_dom_document_get_document_element (document));
-
-       itip_view_init_view (view);
-       g_string_free (buffer, TRUE);
-}
-
-/*******************************************************************************/
-
 static gboolean
 empe_itip_parse (EMailParserExtension *extension,
                  EMailParser *parser,
@@ -189,13 +89,7 @@ empe_itip_parse (EMailParserExtension *extension,
        shell = e_shell_get_default ();
        client_cache = e_shell_get_client_cache (shell);
 
-       itip_part = (EMailPartItip *) e_mail_part_subclass_new (
-               part, part_id->str,
-               sizeof (EMailPartItip),
-               (GFreeFunc) mail_part_itip_free);
-       itip_part->parent.mime_type = g_strdup ("text/calendar");
-       itip_part->parent.bind_func = bind_itip_view;
-       itip_part->parent.force_collapse = TRUE;
+       itip_part = e_mail_part_itip_new (part, part_id->str);
        itip_part->delete_message = g_settings_get_boolean (settings, CONF_KEY_DELETE);
        itip_part->has_organizer = FALSE;
        itip_part->no_reply_wanted = FALSE;
diff --git a/modules/itip-formatter/e-mail-part-itip.c b/modules/itip-formatter/e-mail-part-itip.c
new file mode 100644
index 0000000..e4e6302
--- /dev/null
+++ b/modules/itip-formatter/e-mail-part-itip.c
@@ -0,0 +1,171 @@
+/*
+ * e-mail-part-itip.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-itip.h"
+
+#define E_MAIL_PART_ITIP_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_MAIL_PART_ITIP, EMailPartItipPrivate))
+
+struct _EMailPartItipPrivate {
+       gint placeholder;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+       EMailPartItip,
+       e_mail_part_itip,
+       E_TYPE_MAIL_PART)
+
+static void
+mail_part_itip_dispose (GObject *object)
+{
+       EMailPartItip *part = E_MAIL_PART_ITIP (object);
+
+       g_cancellable_cancel (part->cancellable);
+
+       g_clear_object (&part->cancellable);
+       g_clear_object (&part->client_cache);
+       g_clear_object (&part->comp);
+       g_clear_object (&part->view);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_mail_part_itip_parent_class)->dispose (object);
+}
+
+static void
+mail_part_itip_finalize (GObject *object)
+{
+       EMailPartItip *part = E_MAIL_PART_ITIP (object);
+
+       g_free (part->vcalendar);
+       g_free (part->calendar_uid);
+       g_free (part->from_address);
+       g_free (part->from_name);
+       g_free (part->to_address);
+       g_free (part->to_name);
+       g_free (part->delegator_address);
+       g_free (part->delegator_name);
+       g_free (part->my_address);
+       g_free (part->uid);
+
+       if (part->top_level != NULL)
+               icalcomponent_free (part->top_level);
+
+       if (part->main_comp != NULL)
+               icalcomponent_free (part->main_comp);
+
+       g_hash_table_destroy (part->real_comps);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_mail_part_itip_parent_class)->finalize (object);
+}
+
+static void
+mail_part_itip_bind_dom_element (EMailPart *part,
+                                 WebKitDOMElement *element)
+{
+       GString *buffer;
+       WebKitDOMDocument *document;
+       ItipView *view;
+       EMailPartItip *pitip;
+
+       pitip = E_MAIL_PART_ITIP (part);
+
+       if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
+               WebKitDOMNodeList *nodes;
+               guint ii, length;
+
+               nodes = webkit_dom_element_get_elements_by_tag_name (
+                       element, "iframe");
+               length = webkit_dom_node_list_get_length (nodes);
+               for (ii = 0; ii < length; ii++) {
+                       element = WEBKIT_DOM_ELEMENT (
+                               webkit_dom_node_list_item (nodes, ii));
+                       break;
+               }
+       }
+
+       g_return_if_fail (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element));
+
+       buffer = g_string_new ("");
+       document = webkit_dom_html_iframe_element_get_content_document (
+               WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+
+       view = itip_view_new (pitip, pitip->client_cache);
+       g_object_set_data_full (
+               G_OBJECT (element), "view", view,
+               (GDestroyNotify) g_object_unref);
+
+       itip_view_create_dom_bindings (
+               view, webkit_dom_document_get_document_element (document));
+
+       itip_view_init_view (view);
+       g_string_free (buffer, TRUE);
+}
+
+static void
+e_mail_part_itip_class_init (EMailPartItipClass *class)
+{
+       GObjectClass *object_class;
+       EMailPartClass *mail_part_class;
+
+       g_type_class_add_private (class, sizeof (EMailPartItipPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = mail_part_itip_dispose;
+       object_class->finalize = mail_part_itip_finalize;
+
+       mail_part_class = E_MAIL_PART_CLASS (class);
+       mail_part_class->bind_dom_element = mail_part_itip_bind_dom_element;
+}
+
+static void
+e_mail_part_itip_class_finalize (EMailPartItipClass *class)
+{
+}
+
+static void
+e_mail_part_itip_init (EMailPartItip *part)
+{
+       part->priv = E_MAIL_PART_ITIP_GET_PRIVATE (part);
+
+       e_mail_part_set_mime_type (E_MAIL_PART (part), "text/calendar");
+
+       E_MAIL_PART (part)->force_collapse = TRUE;
+}
+
+void
+e_mail_part_itip_type_register (GTypeModule *type_module)
+{
+       /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+        *     function, so we have to wrap it with a public function in
+        *     order to register types from a separate compilation unit. */
+       e_mail_part_itip_register_type (type_module);
+}
+
+EMailPartItip *
+e_mail_part_itip_new (CamelMimePart *mime_part,
+                      const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+
+       return g_object_new (
+               E_TYPE_MAIL_PART_ITIP,
+               "id", id, "mime-part", mime_part, NULL);
+}
+
diff --git a/modules/itip-formatter/e-mail-part-itip.h b/modules/itip-formatter/e-mail-part-itip.h
index 78004bc..ef978be 100644
--- a/modules/itip-formatter/e-mail-part-itip.h
+++ b/modules/itip-formatter/e-mail-part-itip.h
@@ -26,17 +26,34 @@
 
 #include "itip-view.h"
 
-#define E_MAIL_PART_ITIP(part) \
-       ((EMailPartItip *) part)
-#define E_IS_MAIL_PART_ITIP(part) \
-       (E_MAIL_PART_IS (part, EMailPartItip))
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_ITIP \
+       (e_mail_part_itip_get_type ())
+#define E_MAIL_PART_ITIP(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART_ITIP, EMailPartItip))
+#define E_MAIL_PART_ITIP_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART_ITIP, EMailPartItipClass))
+#define E_IS_MAIL_PART_ITIP(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_PART_ITIP))
+#define E_IS_MAIL_PART_ITIP_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_PART_ITIP))
+#define E_MAIL_PART_ITIP_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART_ITIP, EMailPartItipClass))
 
 G_BEGIN_DECLS
 
 typedef struct _EMailPartItip EMailPartItip;
+typedef struct _EMailPartItipClass EMailPartItipClass;
+typedef struct _EMailPartItipPrivate EMailPartItipPrivate;
 
 struct _EMailPartItip {
        EMailPart parent;
+       EMailPartItipPrivate *priv;
 
        CamelFolder *folder;
        CamelMimeMessage *msg;
@@ -114,6 +131,15 @@ struct _EMailPartItip {
        ItipView *view;
 };
 
+struct _EMailPartItipClass {
+       EMailPartClass parent_class;
+};
+
+GType          e_mail_part_itip_get_type       (void) G_GNUC_CONST;
+void           e_mail_part_itip_type_register  (GTypeModule *type_module);
+EMailPartItip *        e_mail_part_itip_new            (CamelMimePart *mime_part,
+                                                const gchar *id);
+
 G_END_DECLS
 
 #endif /* E_MAIL_PART_ITIP_H */
diff --git a/modules/itip-formatter/evolution-module-itip-formatter.c 
b/modules/itip-formatter/evolution-module-itip-formatter.c
index 13a73a3..af1a235 100644
--- a/modules/itip-formatter/evolution-module-itip-formatter.c
+++ b/modules/itip-formatter/evolution-module-itip-formatter.c
@@ -18,6 +18,7 @@
 
 #include "e-mail-formatter-itip.h"
 #include "e-mail-parser-itip.h"
+#include "e-mail-part-itip.h"
 
 #include <gmodule.h>
 #include <gio/gio.h>
@@ -49,6 +50,7 @@ e_module_load (GTypeModule *type_module)
 
        }
 
+       e_mail_part_itip_type_register (type_module);
        e_mail_parser_itip_type_register (type_module);
        e_mail_formatter_itip_type_register (type_module);
 
diff --git a/modules/prefer-plain/e-mail-display-popup-prefer-plain.c 
b/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
index 91df97c..60d183a 100644
--- a/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
+++ b/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
@@ -342,7 +342,7 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte
        }
 
        while (!g_queue_is_empty (&queue))
-               e_mail_part_unref (g_queue_pop_head (&queue));
+               g_object_unref (g_queue_pop_head (&queue));
 
        if (action_name) {
                action = gtk_action_group_get_action (
diff --git a/modules/vcard-inline/Makefile.am b/modules/vcard-inline/Makefile.am
index 324a7ab..32f79d9 100644
--- a/modules/vcard-inline/Makefile.am
+++ b/modules/vcard-inline/Makefile.am
@@ -14,6 +14,7 @@ module_vcard_inline_la_SOURCES =                              \
        e-mail-formatter-vcard.h                                        \
        e-mail-parser-vcard.c                                           \
        e-mail-parser-vcard.h                                           \
+       e-mail-part-vcard.c                                             \
        e-mail-part-vcard.h                                             \
        evolution-module-vcard-inline.c
 
diff --git a/modules/vcard-inline/e-mail-parser-vcard.c b/modules/vcard-inline/e-mail-parser-vcard.c
index 5fbc3c0..fc28817 100644
--- a/modules/vcard-inline/e-mail-parser-vcard.c
+++ b/modules/vcard-inline/e-mail-parser-vcard.c
@@ -33,14 +33,10 @@
 #include <em-format/e-mail-extension-registry.h>
 #include <em-format/e-mail-parser-extension.h>
 #include <em-format/e-mail-part.h>
-#include <em-format/e-mail-part-utils.h>
-#include <em-format/e-mail-formatter-utils.h>
 
 #include <libebook/libebook.h>
 #include <libedataserver/libedataserver.h>
 
-#include <shell/e-shell.h>
-#include <addressbook/gui/merging/eab-contact-merging.h>
 #include <addressbook/util/eab-book-util.h>
 
 #include <libebackend/libebackend.h>
@@ -68,228 +64,6 @@ static const gchar *parser_mime_types[] = {
 };
 
 static void
-mail_part_vcard_free (EMailPart *mail_part)
-{
-       EMailPartVCard *vi_part = (EMailPartVCard *) mail_part;
-
-       g_clear_object (&vi_part->contact_display);
-       g_clear_object (&vi_part->message_label);
-       g_clear_object (&vi_part->formatter);
-       g_clear_object (&vi_part->iframe);
-       g_clear_object (&vi_part->save_button);
-       g_clear_object (&vi_part->toggle_button);
-       g_clear_object (&vi_part->folder);
-
-       if (vi_part->message_uid) {
-               g_free (vi_part->message_uid);
-               vi_part->message_uid = NULL;
-       }
-}
-
-static void
-client_connect_cb (GObject *source_object,
-                   GAsyncResult *result,
-                   gpointer user_data)
-{
-       GSList *contact_list = user_data;
-       EShell *shell;
-       EClient *client;
-       EBookClient *book_client;
-       ESourceRegistry *registry;
-       GSList *iter;
-       GError *error = NULL;
-
-       client = e_book_client_connect_finish (result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-               goto exit;
-       }
-
-       book_client = E_BOOK_CLIENT (client);
-
-       shell = e_shell_get_default ();
-       registry = e_shell_get_registry (shell);
-
-       for (iter = contact_list; iter != NULL; iter = iter->next) {
-               EContact *contact;
-
-               contact = E_CONTACT (iter->data);
-               eab_merging_book_add_contact (
-                       registry, book_client, contact, NULL, NULL);
-       }
-
-       g_object_unref (client);
-
- exit:
-       g_slist_free_full (contact_list, (GDestroyNotify) g_object_unref);
-}
-
-static void
-save_vcard_cb (WebKitDOMEventTarget *button,
-               WebKitDOMEvent *event,
-               EMailPartVCard *vcard_part)
-{
-       EShell *shell;
-       ESource *source;
-       ESourceRegistry *registry;
-       ESourceSelector *selector;
-       GSList *contact_list;
-       const gchar *extension_name;
-       GtkWidget *dialog;
-
-       shell = e_shell_get_default ();
-       registry = e_shell_get_registry (shell);
-       extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
-
-       dialog = e_source_selector_dialog_new (NULL, registry, extension_name);
-
-       selector = e_source_selector_dialog_get_selector (
-               E_SOURCE_SELECTOR_DIALOG (dialog));
-
-       source = e_source_registry_ref_default_address_book (registry);
-       e_source_selector_set_primary_selection (selector, source);
-       g_object_unref (source);
-
-       if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) {
-               gtk_widget_destroy (dialog);
-               return;
-       }
-
-       source = e_source_selector_dialog_peek_primary_selection (
-               E_SOURCE_SELECTOR_DIALOG (dialog));
-
-       gtk_widget_destroy (dialog);
-
-       g_return_if_fail (source != NULL);
-
-       contact_list = g_slist_copy_deep (
-               vcard_part->contact_list,
-               (GCopyFunc) g_object_ref, NULL);
-
-       e_book_client_connect (
-               source, NULL, client_connect_cb, contact_list);
-}
-
-static void
-display_mode_toggle_cb (WebKitDOMEventTarget *button,
-                        WebKitDOMEvent *event,
-                        EMailPartVCard *vcard_part)
-{
-       EABContactDisplayMode mode;
-       gchar *uri;
-       gchar *html_label, *access_key;
-
-       mode = eab_contact_formatter_get_display_mode (vcard_part->formatter);
-       if (mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) {
-               mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT;
-
-               html_label = e_mail_formatter_parse_html_mnemonics (
-                               _("Show F_ull vCard"), &access_key);
-
-               webkit_dom_html_element_set_inner_html (
-                       WEBKIT_DOM_HTML_ELEMENT (button),
-                       html_label, NULL);
-               if (access_key) {
-                       webkit_dom_html_element_set_access_key (
-                               WEBKIT_DOM_HTML_ELEMENT (button),
-                               access_key);
-                       g_free (access_key);
-               }
-
-               g_free (html_label);
-
-       } else {
-               mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
-
-               html_label = e_mail_formatter_parse_html_mnemonics (
-                               _("Show Com_pact vCard"), &access_key);
-
-               webkit_dom_html_element_set_inner_html (
-                       WEBKIT_DOM_HTML_ELEMENT (button),
-                       html_label, NULL);
-               if (access_key) {
-                       webkit_dom_html_element_set_access_key (
-                               WEBKIT_DOM_HTML_ELEMENT (button),
-                               access_key);
-                       g_free (access_key);
-               }
-
-               g_free (html_label);
-       }
-
-       eab_contact_formatter_set_display_mode (vcard_part->formatter, mode);
-
-       uri = e_mail_part_build_uri (
-               vcard_part->folder, vcard_part->message_uid,
-               "part_id", G_TYPE_STRING, vcard_part->parent.id,
-               "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, NULL);
-
-       webkit_dom_html_iframe_element_set_src (
-               WEBKIT_DOM_HTML_IFRAME_ELEMENT (vcard_part->iframe), uri);
-
-       g_free (uri);
-}
-
-static void
-bind_dom (EMailPartVCard *vcard_part,
-          WebKitDOMElement *attachment)
-{
-       WebKitDOMNodeList *list;
-       WebKitDOMElement *iframe, *toggle_button, *save_button;
-
-        /* IFRAME */
-       list = webkit_dom_element_get_elements_by_tag_name (attachment, "iframe");
-       if (webkit_dom_node_list_get_length (list) != 1)
-               return;
-       iframe = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
-       if (vcard_part->iframe)
-               g_object_unref (vcard_part->iframe);
-       vcard_part->iframe = g_object_ref (iframe);
-
-       /* TOGGLE DISPLAY MODE BUTTON */
-       list = webkit_dom_element_get_elements_by_class_name (
-               attachment, "org-gnome-vcard-display-mode-button");
-       if (webkit_dom_node_list_get_length (list) != 1)
-               return;
-       toggle_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
-       if (vcard_part->toggle_button)
-               g_object_unref (vcard_part->toggle_button);
-       vcard_part->toggle_button = g_object_ref (toggle_button);
-
-       /* SAVE TO ADDRESSBOOK BUTTON */
-       list = webkit_dom_element_get_elements_by_class_name (
-               attachment, "org-gnome-vcard-save-button");
-       if (webkit_dom_node_list_get_length (list) != 1)
-               return;
-       save_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
-       if (vcard_part->save_button)
-               g_object_unref (vcard_part->save_button);
-       vcard_part->save_button = g_object_ref (save_button);
-
-       webkit_dom_event_target_add_event_listener (
-               WEBKIT_DOM_EVENT_TARGET (toggle_button),
-               "click", G_CALLBACK (display_mode_toggle_cb),
-               FALSE, vcard_part);
-
-       webkit_dom_event_target_add_event_listener (
-               WEBKIT_DOM_EVENT_TARGET (save_button),
-               "click", G_CALLBACK (save_vcard_cb),
-               FALSE, vcard_part);
-
-       /* Bind collapse buttons for contact lists. */
-       eab_contact_formatter_bind_dom (
-               webkit_dom_html_iframe_element_get_content_document (
-                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe)));
-}
-
-static void
 decode_vcard (EMailPartVCard *vcard_part,
               CamelMimePart *mime_part)
 {
@@ -336,13 +110,8 @@ empe_vcard_parse (EMailParserExtension *extension,
        len = part_id->len;
        g_string_append (part_id, ".org-gnome-vcard-display");
 
-       vcard_part = (EMailPartVCard *) e_mail_part_subclass_new (
-               part, part_id->str, sizeof (EMailPartVCard),
-               (GFreeFunc) mail_part_vcard_free);
-       vcard_part->parent.mime_type = camel_content_type_simple (
-               camel_mime_part_get_content_type (part));
-       vcard_part->parent.bind_func = (EMailPartDOMBindFunc) bind_dom;
-       vcard_part->parent.is_attachment = TRUE;
+       vcard_part = e_mail_part_vcard_new (part, part_id->str);
+
        vcard_part->formatter = g_object_new (
                EAB_TYPE_CONTACT_FORMATTER,
                "display-mode", EAB_CONTACT_DISPLAY_RENDER_COMPACT,
diff --git a/modules/vcard-inline/e-mail-part-vcard.c b/modules/vcard-inline/e-mail-part-vcard.c
new file mode 100644
index 0000000..5986154
--- /dev/null
+++ b/modules/vcard-inline/e-mail-part-vcard.c
@@ -0,0 +1,353 @@
+/*
+ * e-mail-part-vcard.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-vcard.h"
+
+#include <config.h>
+#include <glib/gi18n.h>
+
+#include <em-format/e-mail-formatter-utils.h>
+#include <em-format/e-mail-part-utils.h>
+
+#include <shell/e-shell.h>
+#include <addressbook/gui/merging/eab-contact-merging.h>
+
+#define E_MAIL_PART_VCARD_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_MAIL_PART_VCARD, EMailPartVCardPrivate))
+
+struct _EMailPartVCardPrivate {
+       gint placeholder;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+       EMailPartVCard,
+       e_mail_part_vcard,
+       E_TYPE_MAIL_PART)
+
+static void
+client_connect_cb (GObject *source_object,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+       GSList *contact_list = user_data;
+       EShell *shell;
+       EClient *client;
+       EBookClient *book_client;
+       ESourceRegistry *registry;
+       GSList *iter;
+       GError *error = NULL;
+
+       client = e_book_client_connect_finish (result, &error);
+
+       /* Sanity check. */
+       g_return_if_fail (
+               ((client != NULL) && (error == NULL)) ||
+               ((client == NULL) && (error != NULL)));
+
+       if (error != NULL) {
+               g_warning ("%s: %s", G_STRFUNC, error->message);
+               g_error_free (error);
+               goto exit;
+       }
+
+       book_client = E_BOOK_CLIENT (client);
+
+       shell = e_shell_get_default ();
+       registry = e_shell_get_registry (shell);
+
+       for (iter = contact_list; iter != NULL; iter = iter->next) {
+               EContact *contact;
+
+               contact = E_CONTACT (iter->data);
+               eab_merging_book_add_contact (
+                       registry, book_client, contact, NULL, NULL);
+       }
+
+       g_object_unref (client);
+
+ exit:
+       g_slist_free_full (contact_list, (GDestroyNotify) g_object_unref);
+}
+
+static void
+save_vcard_cb (WebKitDOMEventTarget *button,
+               WebKitDOMEvent *event,
+               EMailPartVCard *vcard_part)
+{
+       EShell *shell;
+       ESource *source;
+       ESourceRegistry *registry;
+       ESourceSelector *selector;
+       GSList *contact_list;
+       const gchar *extension_name;
+       GtkWidget *dialog;
+
+       shell = e_shell_get_default ();
+       registry = e_shell_get_registry (shell);
+       extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+
+       dialog = e_source_selector_dialog_new (NULL, registry, extension_name);
+
+       selector = e_source_selector_dialog_get_selector (
+               E_SOURCE_SELECTOR_DIALOG (dialog));
+
+       source = e_source_registry_ref_default_address_book (registry);
+       e_source_selector_set_primary_selection (selector, source);
+       g_object_unref (source);
+
+       if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) {
+               gtk_widget_destroy (dialog);
+               return;
+       }
+
+       source = e_source_selector_dialog_peek_primary_selection (
+               E_SOURCE_SELECTOR_DIALOG (dialog));
+
+       gtk_widget_destroy (dialog);
+
+       g_return_if_fail (source != NULL);
+
+       contact_list = g_slist_copy_deep (
+               vcard_part->contact_list,
+               (GCopyFunc) g_object_ref, NULL);
+
+       e_book_client_connect (
+               source, NULL, client_connect_cb, contact_list);
+}
+
+static void
+display_mode_toggle_cb (WebKitDOMEventTarget *button,
+                        WebKitDOMEvent *event,
+                        EMailPartVCard *vcard_part)
+{
+       EABContactDisplayMode mode;
+       gchar *uri;
+       gchar *html_label;
+       gchar *access_key;
+       const gchar *part_id;
+
+       part_id = e_mail_part_get_id (E_MAIL_PART (vcard_part));
+
+       mode = eab_contact_formatter_get_display_mode (vcard_part->formatter);
+       if (mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) {
+               mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT;
+
+               html_label = e_mail_formatter_parse_html_mnemonics (
+                               _("Show F_ull vCard"), &access_key);
+
+               webkit_dom_html_element_set_inner_html (
+                       WEBKIT_DOM_HTML_ELEMENT (button),
+                       html_label, NULL);
+               if (access_key) {
+                       webkit_dom_html_element_set_access_key (
+                               WEBKIT_DOM_HTML_ELEMENT (button),
+                               access_key);
+                       g_free (access_key);
+               }
+
+               g_free (html_label);
+
+       } else {
+               mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
+
+               html_label = e_mail_formatter_parse_html_mnemonics (
+                               _("Show Com_pact vCard"), &access_key);
+
+               webkit_dom_html_element_set_inner_html (
+                       WEBKIT_DOM_HTML_ELEMENT (button),
+                       html_label, NULL);
+               if (access_key) {
+                       webkit_dom_html_element_set_access_key (
+                               WEBKIT_DOM_HTML_ELEMENT (button),
+                               access_key);
+                       g_free (access_key);
+               }
+
+               g_free (html_label);
+       }
+
+       eab_contact_formatter_set_display_mode (vcard_part->formatter, mode);
+
+       uri = e_mail_part_build_uri (
+               vcard_part->folder, vcard_part->message_uid,
+               "part_id", G_TYPE_STRING, part_id,
+               "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, NULL);
+
+       webkit_dom_html_iframe_element_set_src (
+               WEBKIT_DOM_HTML_IFRAME_ELEMENT (vcard_part->iframe), uri);
+
+       g_free (uri);
+}
+
+static void
+mail_part_vcard_dispose (GObject *object)
+{
+       EMailPartVCard *part = E_MAIL_PART_VCARD (object);
+
+       g_clear_object (&part->contact_display);
+       g_clear_object (&part->message_label);
+       g_clear_object (&part->formatter);
+       g_clear_object (&part->iframe);
+       g_clear_object (&part->save_button);
+       g_clear_object (&part->toggle_button);
+       g_clear_object (&part->folder);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_mail_part_vcard_parent_class)->dispose (object);
+}
+
+static void
+mail_part_vcard_finalize (GObject *object)
+{
+       EMailPartVCard *part = E_MAIL_PART_VCARD (object);
+
+       g_free (part->message_uid);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_mail_part_vcard_parent_class)->finalize (object);
+}
+
+static void
+mail_part_vcard_constructed (GObject *object)
+{
+       EMailPart *part;
+       CamelMimePart *mime_part;
+       CamelContentType *content_type;
+       gchar *mime_type;
+
+       part = E_MAIL_PART (object);
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_mail_part_vcard_parent_class)->constructed (object);
+
+       e_mail_part_set_is_attachment (part, TRUE);
+
+       mime_part = e_mail_part_ref_mime_part (part);
+
+       content_type = camel_mime_part_get_content_type (mime_part);
+       mime_type = camel_content_type_simple (content_type);
+       e_mail_part_set_mime_type (part, mime_type);
+       g_free (mime_type);
+
+       g_object_unref (mime_part);
+}
+
+static void
+mail_part_vcard_bind_dom_element (EMailPart *part,
+                                  WebKitDOMElement *element)
+{
+       EMailPartVCard *vcard_part;
+       WebKitDOMNodeList *list;
+       WebKitDOMElement *iframe;
+       WebKitDOMElement *toggle_button;
+       WebKitDOMElement *save_button;
+
+       vcard_part = E_MAIL_PART_VCARD (part);
+
+       /* IFRAME */
+       list = webkit_dom_element_get_elements_by_tag_name (
+               element, "iframe");
+       if (webkit_dom_node_list_get_length (list) != 1)
+               return;
+       iframe = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
+       g_clear_object (&vcard_part->iframe);
+       vcard_part->iframe = g_object_ref (iframe);
+
+       /* TOGGLE DISPLAY MODE BUTTON */
+       list = webkit_dom_element_get_elements_by_class_name (
+               element, "org-gnome-vcard-display-mode-button");
+       if (webkit_dom_node_list_get_length (list) != 1)
+               return;
+       toggle_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
+       g_clear_object (&vcard_part->toggle_button);
+       vcard_part->toggle_button = g_object_ref (toggle_button);
+
+       /* SAVE TO ADDRESSBOOK BUTTON */
+       list = webkit_dom_element_get_elements_by_class_name (
+               element, "org-gnome-vcard-save-button");
+       if (webkit_dom_node_list_get_length (list) != 1)
+               return;
+       save_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
+       g_clear_object (&vcard_part->save_button);
+       vcard_part->save_button = g_object_ref (save_button);
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (toggle_button),
+               "click", G_CALLBACK (display_mode_toggle_cb),
+               FALSE, vcard_part);
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (save_button),
+               "click", G_CALLBACK (save_vcard_cb),
+               FALSE, vcard_part);
+
+       /* Bind collapse buttons for contact lists. */
+       eab_contact_formatter_bind_dom (
+               webkit_dom_html_iframe_element_get_content_document (
+                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe)));
+}
+
+static void
+e_mail_part_vcard_class_init (EMailPartVCardClass *class)
+{
+       GObjectClass *object_class;
+       EMailPartClass *mail_part_class;
+
+       g_type_class_add_private (class, sizeof (EMailPartVCardPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = mail_part_vcard_dispose;
+       object_class->finalize = mail_part_vcard_finalize;
+       object_class->constructed = mail_part_vcard_constructed;
+
+       mail_part_class = E_MAIL_PART_CLASS (class);
+       mail_part_class->bind_dom_element = mail_part_vcard_bind_dom_element;
+}
+
+static void
+e_mail_part_vcard_class_finalize (EMailPartVCardClass *class)
+{
+}
+
+static void
+e_mail_part_vcard_init (EMailPartVCard *part)
+{
+       part->priv = E_MAIL_PART_VCARD_GET_PRIVATE (part);
+}
+
+void
+e_mail_part_vcard_type_register (GTypeModule *type_module)
+{
+       /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+        *     function, so we have to wrap it with a public function in
+        *     order to register types from a separate compilation unit. */
+       e_mail_part_vcard_register_type (type_module);
+}
+
+EMailPartVCard *
+e_mail_part_vcard_new (CamelMimePart *mime_part,
+                       const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+
+       return g_object_new (
+               E_TYPE_MAIL_PART_VCARD,
+               "id", id, "mime-part", mime_part, NULL);
+}
+
diff --git a/modules/vcard-inline/e-mail-part-vcard.h b/modules/vcard-inline/e-mail-part-vcard.h
index c05b0a8..a6d7267 100644
--- a/modules/vcard-inline/e-mail-part-vcard.h
+++ b/modules/vcard-inline/e-mail-part-vcard.h
@@ -24,15 +24,34 @@
 #include <addressbook/gui/widgets/eab-contact-formatter.h>
 #include <webkit/webkitdom.h>
 
-#define E_IS_MAIL_PART_VCARD(part) \
-       (E_MAIL_PART_IS (part, EMailPartVCard))
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_VCARD \
+       (e_mail_part_vcard_get_type ())
+#define E_MAIL_PART_VCARD(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART_VCARD, EMailPartVCard))
+#define E_MAIL_PART_VCARD_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART_VCARD, EMailPartVCardClass))
+#define E_IS_MAIL_PART_VCARD(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_PART_VCARD))
+#define E_IS_MAIL_PART_VCARD_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_PART_VCARD))
+#define E_MAIL_PART_VCARD_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART_VCARD, EMailPartVCardClass))
 
 G_BEGIN_DECLS
 
 typedef struct _EMailPartVCard EMailPartVCard;
+typedef struct _EMailPartVCardClass EMailPartVCardClass;
+typedef struct _EMailPartVCardPrivate EMailPartVCardPrivate;
 
 struct _EMailPartVCard {
        EMailPart parent;
+       EMailPartVCardPrivate *priv;
 
        GSList *contact_list;
        GtkWidget *contact_display;
@@ -47,6 +66,16 @@ struct _EMailPartVCard {
        gchar *message_uid;
 };
 
+struct _EMailPartVCardClass {
+       EMailPartClass parent_class;
+};
+
+GType          e_mail_part_vcard_get_type      (void) G_GNUC_CONST;
+void           e_mail_part_vcard_type_register (GTypeModule *type_module);
+EMailPartVCard *
+               e_mail_part_vcard_new           (CamelMimePart *mime_part,
+                                                const gchar *id);
+
 G_END_DECLS
 
 #endif /* E_MAIL_PART_VCARD_H */
diff --git a/modules/vcard-inline/evolution-module-vcard-inline.c 
b/modules/vcard-inline/evolution-module-vcard-inline.c
index abf4d36..978ecdb 100644
--- a/modules/vcard-inline/evolution-module-vcard-inline.c
+++ b/modules/vcard-inline/evolution-module-vcard-inline.c
@@ -18,6 +18,7 @@
 
 #include "e-mail-formatter-vcard.h"
 #include "e-mail-parser-vcard.h"
+#include "e-mail-part-vcard.h"
 
 #include <gmodule.h>
 
@@ -30,6 +31,7 @@ e_module_load (GTypeModule *type_module)
 {
        e_mail_formatter_vcard_type_register (type_module);
        e_mail_parser_vcard_type_register (type_module);
+       e_mail_part_vcard_type_register (type_module);
 }
 
 G_MODULE_EXPORT void


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