[evolution] Commit the rest of the attachment UI rewrite



commit 4449a34101406bffe508dd40b8b653f7c7d14c7d
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon Apr 27 15:36:19 2009 -0400

    Commit the rest of the attachment UI rewrite
    
    Oops, last commit only included the -new- files.
    This also removes EExpander, which is no longer used.
---
 a11y/e-table/Makefile.am                           |    5 +-
 a11y/widgets/Makefile.am                           |    2 -
 a11y/widgets/ea-expander.c                         |  165 --
 a11y/widgets/ea-expander.h                         |   51 -
 a11y/widgets/ea-widgets.c                          |    7 -
 a11y/widgets/ea-widgets.h                          |    1 -
 calendar/gui/Makefile.am                           |    2 +
 calendar/gui/calendar-component.c                  |    4 +
 calendar/gui/dialogs/comp-editor.c                 | 1229 ++------
 calendar/gui/dialogs/event-editor.c                |    2 -
 calendar/gui/e-cal-popup.c                         |  417 ---
 calendar/gui/e-cal-popup.h                         |    2 -
 composer/e-composer-actions.c                      |   66 +-
 composer/e-composer-private.c                      |   87 +-
 composer/e-composer-private.h                      |   12 +-
 composer/e-msg-composer.c                          |  697 ++----
 composer/e-msg-composer.h                          |   12 +-
 configure.in                                       |    6 +-
 e-util/e-util.c                                    |  207 ++
 e-util/e-util.h                                    |   16 +
 mail/Makefile.am                                   |    4 +
 mail/em-filter-i18n.h                              |    2 +
 mail/em-format-html-display.c                      |  615 +----
 mail/em-format-html-display.h                      |    2 -
 mail/em-popup.c                                    |  123 +-
 mail/em-popup.h                                    |   35 +-
 mail/mail-component.c                              |    5 +
 plugins/attachment-reminder/attachment-reminder.c  |   13 +-
 plugins/import-ics-attachments/ChangeLog           |  109 -
 plugins/import-ics-attachments/Makefile.am         |   35 -
 plugins/import-ics-attachments/icsimporter.c       |  435 ---
 ...evolution-mail-attachments-import-ics.eplug.xml |   26 -
 plugins/save-attachments/ChangeLog                 |  102 -
 plugins/save-attachments/Makefile.am               |   31 -
 .../org-gnome-save-attachments.eplug.xml           |   26 -
 .../org-gnome-save-attachments.xml                 |   20 -
 plugins/save-attachments/save-attachments.c        |  392 ---
 shell/apps_evolution_shell.schemas.in              |   30 +-
 widgets/misc/Makefile.am                           |   22 +-
 widgets/misc/e-attachment-bar.c                    | 1504 ----------
 widgets/misc/e-attachment-bar.h                    |  105 -
 widgets/misc/e-attachment.c                        | 3021 ++++++++++++++++----
 widgets/misc/e-attachment.h                        |  186 +-
 widgets/misc/e-expander.c                          | 1341 ---------
 widgets/misc/e-expander.h                          |   82 -
 widgets/text/Makefile.am                           |    2 +
 46 files changed, 3430 insertions(+), 7828 deletions(-)

diff --git a/a11y/e-table/Makefile.am b/a11y/e-table/Makefile.am
index 1884c3a..f344d7b 100644
--- a/a11y/e-table/Makefile.am
+++ b/a11y/e-table/Makefile.am
@@ -1,6 +1,7 @@
 INCLUDES =					\
-	-I$(top_srcdir)                         \
-	-I$(top_srcdir)/widgets                 \
+	-I$(top_srcdir)				\
+	-I$(top_srcdir)/widgets			\
+	$(E_UTIL_CFLAGS)			\
 	$(GNOME_PLATFORM_CFLAGS)		\
         -DG_LOG_DOMAIN=\"e-table\"
 
diff --git a/a11y/widgets/Makefile.am b/a11y/widgets/Makefile.am
index e157f82..6fb8c80 100644
--- a/a11y/widgets/Makefile.am
+++ b/a11y/widgets/Makefile.am
@@ -22,8 +22,6 @@ libevolution_widgets_a11y_la_SOURCES =		\
 	ea-calendar-cell.h			\
 	ea-combo-button.c			\
 	ea-combo-button.h			\
-	ea-expander.c				\
-	ea-expander.h				\
 	ea-widgets.c				\
 	ea-widgets.h
 
diff --git a/a11y/widgets/ea-expander.c b/a11y/widgets/ea-expander.c
deleted file mode 100644
index ae9da5f..0000000
--- a/a11y/widgets/ea-expander.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *
- * 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/>  
- *
- *
- * Authors:
- *		Boby Wang <boby wang sun com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#include <config.h>
-#include "ea-expander.h"
-#include <glib/gi18n.h>
-
-static AtkObjectClass *parent_class;
-static GType parent_type;
-
-/* Action IDs */
-enum {
-	ACTIVATE,
-	LAST_ACTION
-};
-
-static G_CONST_RETURN gchar*
-ea_expander_get_name (AtkObject *a11y)
-{
-	return _("Toggle Attachment Bar");
-}
-
-/* Action interface */
-static G_CONST_RETURN gchar *
-ea_expander_action_get_name (AtkAction *action, gint i)
-{
-	switch (i)
-	{
-		case ACTIVATE:
-			return _("activate");
-		default:
-			return NULL;
-	}
-}
-
-static gboolean
-ea_expander_do_action (AtkAction *action, gint i)
-{
-	GtkWidget *widget;
-	EExpander *expander;
-
-	widget = GTK_ACCESSIBLE (action)->widget;
-	if (!widget || !GTK_WIDGET_IS_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
-		return FALSE;
-
-	expander = E_EXPANDER (widget);
-
-	switch (i)
-	{
-		case ACTIVATE:
-			g_signal_emit_by_name (expander, "activate");
-			return TRUE;
-		default:
-			return FALSE;
-	}
-}
-
-static gint
-ea_expander_get_n_actions (AtkAction *action)
-{
-	return LAST_ACTION;
-}
-
-static void
-atk_action_interface_init (AtkActionIface *iface)
-{
-	g_return_if_fail (iface != NULL);
-
-	iface->do_action = ea_expander_do_action;
-	iface->get_n_actions = ea_expander_get_n_actions;
-	iface->get_name = ea_expander_action_get_name;
-}
-
-static void
-ea_expander_class_init (EaExpanderClass *klass)
-{
-	AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
-
-	parent_class = g_type_class_ref (parent_type);
-
-	atk_object_class->get_name = ea_expander_get_name;
-}
-
-static void
-ea_expander_init (EaExpander *a11y)
-{
-	/* Empty */
-}
-
-GType
-ea_expander_get_type (void)
-{
-	static GType type = 0;
-
-	if (!type) {
-		AtkObjectFactory *factory;
-		GTypeQuery query;
-
-		GTypeInfo info = {
-			sizeof (EaExpanderClass),
-			(GBaseInitFunc) NULL,
-			(GBaseFinalizeFunc) NULL,
-			(GClassInitFunc) ea_expander_class_init,
-			(GClassFinalizeFunc) NULL,
-			NULL, /* class data */
-			sizeof (EaExpander),
-			0,
-			(GInstanceInitFunc) ea_expander_init,
-			NULL /* value_tree */
-		};
-
-		static const GInterfaceInfo atk_action_info = {
-			(GInterfaceInitFunc) atk_action_interface_init,
-			(GInterfaceFinalizeFunc) NULL,
-			NULL
-		};
-
-		factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_BIN);
-		parent_type = atk_object_factory_get_accessible_type (factory);
-		g_type_query (parent_type, &query);
-
-		info.class_size = query.class_size;
-		info.instance_size = query.instance_size;
-
-		type = g_type_register_static (parent_type, "EaExpander", &info, 0);
-		g_type_add_interface_static (type, ATK_TYPE_ACTION,
-						&atk_action_info);
-	}
-
-	return type;
-}
-
-AtkObject *
-ea_expander_new (GtkWidget *widget)
-{
-	EaExpander *a11y;
-
-	a11y = g_object_new (ea_expander_get_type (), NULL);
-
-	GTK_ACCESSIBLE (a11y)->widget = GTK_WIDGET (widget);
-	ATK_OBJECT (a11y)->role = ATK_ROLE_TOGGLE_BUTTON;
-
-	return ATK_OBJECT (a11y);
-}
-
diff --git a/a11y/widgets/ea-expander.h b/a11y/widgets/ea-expander.h
deleted file mode 100644
index e670ad0..0000000
--- a/a11y/widgets/ea-expander.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *
- * 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/>  
- *
- *
- * Authors:
- *		Boby Wang <boby wang sun com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifndef _EA_EXPANDER_H_
-#define _EA_EXPANDER_H_
-
-#include <gtk/gtk.h>
-#include <misc/e-expander.h>
-
-#define EA_TYPE_EXPANDER           (ea_expander_get_type ())
-#define EA_EXPANDER(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), EA_TYPE_EXPANDER, EaExpander))
-#define EA_EXPANDER_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass,), EA_TYPE_EXPANDER, EaExpanderClass))
-#define EA_IS_EXPANDER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EA_TYPE_EXPANDER))
-#define EA_IS_EXPANDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), EA_TYPE_EXPANDER_CLASS))
-
-typedef struct _EaExpander EaExpander;
-typedef struct _EaExpanderClass EaExpanderClass;
-
-struct _EaExpander {
-	GtkAccessible object;
-};
-
-struct _EaExpanderClass {
-	GtkAccessibleClass parent_class;
-};
-
-/* Standard Glib function */
-GType ea_expander_get_type (void);
-AtkObject* ea_expander_new (GtkWidget *expander);
-
-#endif /* ! _EA_EXPANDER_H_ */
diff --git a/a11y/widgets/ea-widgets.c b/a11y/widgets/ea-widgets.c
index 66c1668..5befb44 100644
--- a/a11y/widgets/ea-widgets.c
+++ b/a11y/widgets/ea-widgets.c
@@ -23,12 +23,10 @@
 #include "ea-factory.h"
 #include "widgets/ea-calendar-item.h"
 #include "widgets/ea-combo-button.h"
-#include "widgets/ea-expander.h"
 #include "ea-widgets.h"
 
 EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_ITEM, ea_calendar_item, ea_calendar_item_new)
 EA_FACTORY (EA_TYPE_COMBO_BUTTON, ea_combo_button, ea_combo_button_new)
-EA_FACTORY (EA_TYPE_EXPANDER, ea_expander, ea_expander_new)
 
 void e_calendar_item_a11y_init (void)
 {
@@ -39,8 +37,3 @@ void e_combo_button_a11y_init (void)
 {
     EA_SET_FACTORY (e_combo_button_get_type (), ea_combo_button);
 }
-
-void e_expander_a11y_init (void)
-{
-     EA_SET_FACTORY (e_expander_get_type (), ea_expander);
-}
diff --git a/a11y/widgets/ea-widgets.h b/a11y/widgets/ea-widgets.h
index f4aff74..20c1c96 100644
--- a/a11y/widgets/ea-widgets.h
+++ b/a11y/widgets/ea-widgets.h
@@ -29,6 +29,5 @@
 
 void e_calendar_item_a11y_init (void);
 void e_combo_button_a11y_init (void);
-void e_expander_a11y_init (void);
 
 #endif /* _EA_WIDGETS_H__ */
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index e61f6a1..b5dab7a 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -69,6 +69,8 @@ etspec_DATA =				\
 
 libevolution_calendar_la_SOURCES =		\
 	$(IDL_GENERATED)			\
+	e-attachment-handler-calendar.c		\
+	e-attachment-handler-calendar.h		\
 	cal-search-bar.c			\
 	cal-search-bar.h			\
 	calendar-config.c			\
diff --git a/calendar/gui/calendar-component.c b/calendar/gui/calendar-component.c
index 942960b..4d30929 100644
--- a/calendar/gui/calendar-component.c
+++ b/calendar/gui/calendar-component.c
@@ -58,6 +58,7 @@
 #include "e-util/e-error.h"
 #include "e-cal-menu.h"
 #include "e-cal-popup.h"
+#include "e-attachment-handler-calendar.h"
 
 /* IDs for user creatable items */
 #define CREATE_EVENT_ID        "event"
@@ -1576,6 +1577,9 @@ calendar_component_class_init (CalendarComponentClass *class)
 
 	object_class->dispose  = impl_dispose;
 	object_class->finalize = impl_finalize;
+
+	/* Register attachment handler types. */
+	e_attachment_handler_calendar_get_type ();
 }
 
 static void
diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c
index f303435..6456a5c 100644
--- a/calendar/gui/dialogs/comp-editor.c
+++ b/calendar/gui/dialogs/comp-editor.c
@@ -63,9 +63,9 @@
 #include "../e-cal-popup.h"
 #include "../calendar-config-keys.h"
 #include "cal-attachment-select-file.h"
+#include "widgets/misc/e-attachment-view.h"
+#include "widgets/misc/e-attachment-paned.h"
 
-#include "e-attachment-bar.h"
-#include "misc/e-expander.h"
 #include "e-util/e-error.h"
 
 #define COMP_EDITOR_GET_PRIVATE(obj) \
@@ -95,12 +95,7 @@ struct _CompEditorPrivate {
 	GtkNotebook *notebook;
 
 	/* Attachment handling */
-	GtkWidget *attachment_bar;
-	GtkWidget *attachment_scrolled_window;
-	GtkWidget *attachment_expander;
-	GtkWidget *attachment_expander_label;
-	GtkWidget *attachment_expander_icon;
-	GtkWidget *attachment_expander_num;
+	GtkWidget *attachment_view;
 
 	/* Manages menus and toolbars */
 	GtkUIManager *manager;
@@ -151,7 +146,7 @@ static const gchar *ui =
 "    <menu action='view-menu'/>"
 "    <menu action='insert-menu'>"
 "      <menuitem action='attach'/>"
-"      <menuitem action='attach-recent'/>"
+"      <placeholder name='recent-placeholder'/>"
 "    </menu>"
 "    <menu action='options-menu'/>"
 "    <menu action='help-menu'>"
@@ -163,13 +158,10 @@ static const gchar *ui =
 "    <toolitem action='print'/>"
 "    <toolitem action='close'/>"
 "    <separator/>"
-"    <toolitem action='attach'/>"
-"    <separator/>"
 "  </toolbar>"
 "</ui>";
 
 static void comp_editor_show_help (CompEditor *editor);
-static void setup_widgets (CompEditor *editor);
 
 static void real_edit_comp (CompEditor *editor, ECalComponent *comp);
 static gboolean real_send_comp (CompEditor *editor, ECalComponentItipMethod method, gboolean strip_alarms);
@@ -180,441 +172,63 @@ static void page_dates_changed_cb (CompEditor *editor, CompEditorPageDates *date
 
 static void obj_modified_cb (ECal *client, GList *objs, gpointer data);
 static void obj_removed_cb (ECal *client, GList *uids, gpointer data);
-static gboolean open_attachment (EAttachmentBar *bar, CompEditor *editor);
 
 G_DEFINE_TYPE (CompEditor, comp_editor, GTK_TYPE_WINDOW)
 
 enum {
-	DND_TYPE_MESSAGE_RFC822,
-	DND_TYPE_X_UID_LIST,
-	DND_TYPE_TEXT_URI_LIST,
-	DND_TYPE_NETSCAPE_URL,
-	DND_TYPE_TEXT_VCARD,
-	DND_TYPE_TEXT_CALENDAR,
-};
-
-static GtkTargetEntry drop_types[] = {
-	{ "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 },
-	{ "x-uid-list", 0, DND_TYPE_X_UID_LIST },
-	{ "text/uri-list", 0, DND_TYPE_TEXT_URI_LIST },
-	{ "_NETSCAPE_URL", 0, DND_TYPE_NETSCAPE_URL },
-	{ "text/x-vcard", 0, DND_TYPE_TEXT_VCARD },
-	{ "text/calendar", 0, DND_TYPE_TEXT_CALENDAR },
-};
-
-#define num_drop_types (sizeof (drop_types) / sizeof (drop_types[0]))
-
-static struct {
-	char *target;
-	GdkAtom atom;
-	guint32 actions;
-} drag_info[] = {
-	{ "message/rfc822", NULL, GDK_ACTION_COPY },
-	{ "x-uid-list", NULL, GDK_ACTION_ASK|GDK_ACTION_MOVE|GDK_ACTION_COPY },
-	{ "text/uri-list", NULL, GDK_ACTION_COPY },
-	{ "_NETSCAPE_URL", NULL, GDK_ACTION_COPY },
-	{ "text/x-vcard", NULL, GDK_ACTION_COPY },
-	{ "text/calendar", NULL, GDK_ACTION_COPY },
-};
-
-enum {
 	OBJECT_CREATED,
 	LAST_SIGNAL
 };
 
 static guint comp_editor_signals[LAST_SIGNAL] = { 0 };
 
-static void
-attach_message(CompEditor *editor, CamelMimeMessage *msg)
-{
-	CamelMimePart *mime_part;
-	const char *subject;
-	guint i;
-	char *filename = NULL;
-
-	mime_part = camel_mime_part_new();
-	camel_mime_part_set_disposition(mime_part, "inline");
-	subject = camel_mime_message_get_subject(msg);
-	if (subject) {
-		char *desc = g_strdup_printf(_("Attached message - %s"), subject);
-
-		camel_mime_part_set_description(mime_part, desc);
-		g_free(desc);
-	} else
-		camel_mime_part_set_description(mime_part, _("Attached message"));
-
-	i = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
-	i++;
-	filename = g_strdup_printf ("email%d",i);
-	camel_mime_part_set_filename (mime_part, filename);
-
-	camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg);
-	camel_mime_part_set_content_type(mime_part, "message/rfc822");
-	e_attachment_bar_attach_mime_part(E_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part);
-	camel_object_unref(mime_part);
-	g_free (filename);
-}
-
-struct _drop_data {
-	CompEditor *editor;
-
-	GdkDragContext *context;
-	/* Only selection->data and selection->length are valid */
-	GtkSelectionData *selection;
-
-	guint32 action;
-	guint info;
-	guint time;
-
-	unsigned int move:1;
-	unsigned int moved:1;
-	unsigned int aborted:1;
-};
-
-static void
-drop_action(CompEditor *editor, GdkDragContext *context, guint32 action, GtkSelectionData *selection, guint info, guint time)
-{
-	char *tmp, *str, **urls;
-	CamelMimePart *mime_part;
-	CamelStream *stream;
-	CamelURL *url;
-	CamelMimeMessage *msg;
-	char *content_type;
-	int i, success=FALSE, delete=FALSE;
-
-	switch (info) {
-	case DND_TYPE_MESSAGE_RFC822:
-		d(printf ("dropping a message/rfc822\n"));
-		/* write the message(s) out to a CamelStream so we can use it */
-		stream = camel_stream_mem_new ();
-		camel_stream_write (stream, (char *)selection->data, selection->length);
-		camel_stream_reset (stream);
-
-		msg = camel_mime_message_new ();
-		if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) {
-			attach_message(editor, msg);
-			success = TRUE;
-			delete = action == GDK_ACTION_MOVE;
-		}
-
-		camel_object_unref(msg);
-		camel_object_unref(stream);
-		break;
-	case DND_TYPE_TEXT_URI_LIST:
-	case DND_TYPE_NETSCAPE_URL:
-		d(printf ("dropping a text/uri-list\n"));
-		tmp = g_strndup ((char *)selection->data, selection->length);
-		urls = g_strsplit (tmp, "\n", 0);
-		g_free (tmp);
-
-		for (i = 0; urls[i] != NULL; i++) {
-			str = g_strstrip (urls[i]);
-			if (urls[i][0] == '#')
-				continue;
-
-			if (!g_ascii_strncasecmp (str, "mailto:";, 7)) {
-				/* TODO does not handle mailto now */
-			} else {
-				url = camel_url_new (str, NULL);
-
-				if (url == NULL)
-					continue;
-
-				if (!g_ascii_strcasecmp (url->protocol, "file"))
-					e_attachment_bar_attach
-						(E_ATTACHMENT_BAR (editor->priv->attachment_bar),
-					 	url->path,
-						"attachment");
-				else
-					e_attachment_bar_attach_remote_file
-						(E_ATTACHMENT_BAR (editor->priv->attachment_bar),
-						 str, "attachment");
-
-				camel_url_free (url);
-			}
-		}
-
-		g_strfreev (urls);
-		success = TRUE;
-		break;
-	case DND_TYPE_TEXT_VCARD:
-	case DND_TYPE_TEXT_CALENDAR:
-		content_type = gdk_atom_name (selection->type);
-		d(printf ("dropping a %s\n", content_type));
-
-		mime_part = camel_mime_part_new ();
-		camel_mime_part_set_content (mime_part, (char *)selection->data, selection->length, content_type);
-		camel_mime_part_set_disposition (mime_part, "inline");
-
-		e_attachment_bar_attach_mime_part
-			(E_ATTACHMENT_BAR (editor->priv->attachment_bar),
-			 mime_part);
-
-		camel_object_unref (mime_part);
-		g_free (content_type);
-
-		success = TRUE;
-		break;
-	case DND_TYPE_X_UID_LIST: {
-		GPtrArray *uids;
-		char *inptr, *inend;
-		CamelFolder *folder;
-		CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-
-		/* NB: This all runs synchronously, could be very slow/hang/block the ui */
-
-		uids = g_ptr_array_new();
-
-		inptr = (char *)selection->data;
-		inend = (char *)(selection->data + selection->length);
-		while (inptr < inend) {
-			char *start = inptr;
-
-			while (inptr < inend && *inptr)
-				inptr++;
-
-			if (start > (char *)selection->data)
-				g_ptr_array_add(uids, g_strndup(start, inptr-start));
-
-			inptr++;
-		}
-
-		if (uids->len > 0) {
-			folder = mail_tool_uri_to_folder((char *)selection->data, 0, &ex);
-			if (folder) {
-				if (uids->len == 1) {
-					msg = camel_folder_get_message(folder, uids->pdata[0], &ex);
-					if (msg == NULL)
-						goto fail;
-					attach_message(editor, msg);
-				} else {
-					CamelMultipart *mp = camel_multipart_new();
-					char *desc;
-					char *filename = NULL;
-					guint num;
-
-					camel_data_wrapper_set_mime_type((CamelDataWrapper *)mp, "multipart/digest");
-					camel_multipart_set_boundary(mp, NULL);
-					for (i=0;i<uids->len;i++) {
-
-						msg = camel_folder_get_message(folder, uids->pdata[i], &ex);
-						if (msg) {
-							mime_part = camel_mime_part_new();
-							camel_mime_part_set_disposition(mime_part, "inline");
-							camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg);
-							camel_mime_part_set_content_type(mime_part, "message/rfc822");
-							camel_multipart_add_part(mp, mime_part);
-							camel_object_unref(mime_part);
-							camel_object_unref(msg);
-						} else {
-							camel_object_unref(mp);
-							goto fail;
-						}
-					}
-					mime_part = camel_mime_part_new();
-					camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)mp);
-					/* translators, this count will always be >1 */
-					desc = g_strdup_printf(ngettext("Attached message", "%d attached messages", uids->len), uids->len);
-					camel_mime_part_set_description(mime_part, desc);
-					g_free(desc);
-
-					num = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
-					num++;
-					filename = g_strdup_printf ("email%d", num);
-					camel_mime_part_set_filename (mime_part, filename);
-
-					e_attachment_bar_attach_mime_part
-						(E_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part);
-					camel_object_unref(mime_part);
-					camel_object_unref(mp);
-					g_free (filename);
-				}
-				success = TRUE;
-				delete = action == GDK_ACTION_MOVE;
-			fail:
-				if (camel_exception_is_set(&ex)) {
-					char *name;
-
-					camel_object_get(folder, NULL, CAMEL_FOLDER_NAME, &name, NULL);
-					e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages",
-						    name?name:(char *)selection->data, camel_exception_get_description(&ex), NULL);
-					camel_object_free(folder, CAMEL_FOLDER_NAME, name);
-				}
-				camel_object_unref(folder);
-			} else {
-				e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages",
-					    (char *)selection->data, camel_exception_get_description(&ex), NULL);
-			}
-
-			camel_exception_clear(&ex);
-		}
-
-		g_ptr_array_free(uids, TRUE);
-
-		break; }
-	default:
-		d(printf ("dropping an unknown\n"));
-		break;
-	}
-
-	printf("Drag finished, success %d delete %d\n", success, delete);
-
-	gtk_drag_finish(context, success, delete, time);
-}
-
-static void
-drop_popup_copy (EPopup *ep, EPopupItem *item, void *data)
-{
-	struct _drop_data *m = data;
-	drop_action(m->editor, m->context, GDK_ACTION_COPY, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_move (EPopup *ep, EPopupItem *item, void *data)
-{
-	struct _drop_data *m = data;
-	drop_action(m->editor, m->context, GDK_ACTION_MOVE, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data)
-{
-	struct _drop_data *m = data;
-	gtk_drag_finish(m->context, FALSE, FALSE, m->time);
-}
-
-static EPopupItem drop_popup_menu[] = {
-	{ E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "mail-copy", 0 },
-	{ E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "mail-move", 0 },
-	{ E_POPUP_BAR, "10.emc" },
-	{ E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
-};
-
-static void
-drop_popup_free(EPopup *ep, GSList *items, void *data)
-{
-	struct _drop_data *m = data;
-
-	g_slist_free(items);
-
-	g_object_unref(m->context);
-	g_object_unref(m->editor);
-	g_free(m->selection->data);
-	g_free(m->selection);
-	g_free(m);
-}
-
-static void
-drag_data_received (CompEditor *editor, GdkDragContext *context,
-		    int x, int y, GtkSelectionData *selection,
-		    guint info, guint time)
-{
-	if (selection->data == NULL || selection->length == -1)
-		return;
-
-	if (context->action == GDK_ACTION_ASK) {
-		ECalPopup *ecp;
-		GSList *menus = NULL;
-		GtkMenu *menu;
-		int i;
-		struct _drop_data *m;
-
-		m = g_malloc0(sizeof(*m));
-		m->context = context;
-		g_object_ref(context);
-		m->editor = editor;
-		g_object_ref(editor);
-		m->action = context->action;
-		m->info = info;
-		m->time = time;
-		m->selection = g_malloc0(sizeof(*m->selection));
-		m->selection->data = g_malloc(selection->length);
-		memcpy(m->selection->data, selection->data, selection->length);
-		m->selection->length = selection->length;
-
-		ecp = e_cal_popup_new("org.gnome.evolution.calendar.editor.popup.drop");
-		for (i=0;i<sizeof(drop_popup_menu)/sizeof(drop_popup_menu[0]);i++)
-			menus = g_slist_append(menus, &drop_popup_menu[i]);
-
-		e_popup_add_items((EPopup *)ecp, menus, NULL, drop_popup_free, m);
-		menu = e_popup_create_menu_once((EPopup *)ecp, NULL, 0);
-		gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, time);
-	} else {
-		drop_action(editor, context, context->action, selection, info, time);
-	}
-}
-
-static gboolean
-drag_motion(GObject *o, GdkDragContext *context, gint x, gint y, guint time, CompEditor *editor)
-{
-	GList *targets;
-	GdkDragAction action, actions = 0;
-
-	for (targets = context->targets; targets; targets = targets->next) {
-		int i;
-
-		for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
-			if (targets->data == (void *)drag_info[i].atom)
-				actions |= drag_info[i].actions;
-	}
-
-	actions &= context->actions;
-	action = context->suggested_action;
-	/* we default to copy */
-	if (action == GDK_ACTION_ASK && (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != (GDK_ACTION_MOVE|GDK_ACTION_COPY))
-		action = GDK_ACTION_COPY;
-
-	gdk_drag_status(context, action, time);
-
-	return action != 0;
-}
-
-static void
-add_to_bar (CompEditor *editor, GPtrArray *file_list, int is_inline)
-{
-	CompEditorPrivate *priv = editor->priv;
-	int i;
-
-	for (i = 0; i < file_list->len; i++) {
-		CamelURL *url;
-
-		if (!(url = camel_url_new (file_list->pdata[i], NULL)))
-			continue;
-
-		if (!g_ascii_strcasecmp (url->protocol, "file")) {
-			e_attachment_bar_attach((EAttachmentBar *)priv->attachment_bar, url->path, is_inline ? "inline" : "attachment");
-		} else {
-			e_attachment_bar_attach_remote_file ((EAttachmentBar *)priv->attachment_bar, file_list->pdata[i], is_inline ? "inline" : "attachment");
-		}
-
-		camel_url_free (url);
-	}
-}
-
 static GSList *
 get_attachment_list (CompEditor *editor)
 {
-	GSList *parts = NULL, *list = NULL, *p = NULL;
+	EAttachmentStore *store;
+	EAttachmentView *view;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GSList *parts = NULL, *list = NULL;
 	const char *comp_uid = NULL;
 	const char *local_store = e_cal_get_local_attachment_store (editor->priv->client);
+	gboolean valid;
 	int ticker=0;
+
 	e_cal_component_get_uid (editor->priv->comp, &comp_uid);
 
-	parts = e_attachment_bar_get_parts((EAttachmentBar *)editor->priv->attachment_bar);
+	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
+	store = e_attachment_view_get_store (view);
 
-	for (p = parts; p!=NULL ; p = p->next) {
+	model = GTK_TREE_MODEL (store);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+
+	while (valid) {
+		EAttachment *attachment;
 		CamelDataWrapper *wrapper;
+		CamelMimePart *mime_part;
 		CamelStream *stream;
 		char *attach_file_url;
 		char *safe_fname, *utf8_safe_fname;
 		char *filename;
+		gint column_id;
+
+		column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+		mime_part = e_attachment_get_mime_part (attachment);
+		g_object_unref (attachment);
+
+		valid = gtk_tree_model_iter_next (model, &iter);
 
-		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (p->data));
+		if (mime_part == NULL)
+			continue;
+
+		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
 
 		/* Extract the content from the stream and write it down
 		 * as a mime part file into the directory denoting the
 		 * calendar source */
-		utf8_safe_fname = camel_file_util_safe_filename (camel_mime_part_get_filename ((CamelMimePart *) p->data));
+		utf8_safe_fname = camel_file_util_safe_filename (camel_mime_part_get_filename (mime_part));
 
 		/* It is absolutely fine to get a NULL from the filename of 
 		 * mime part. We assume that it is named "Attachment"
@@ -993,20 +607,21 @@ static void
 action_attach_cb (GtkAction *action,
                   CompEditor *editor)
 {
-	GPtrArray *file_list;
-	gboolean is_inline = FALSE;
-	int i;
-
-	file_list = comp_editor_select_file_attachments (editor, &is_inline);
+	EAttachmentStore *store;
+	EAttachmentView *view;
 
-	if (file_list) {
-		add_to_bar (editor, file_list, is_inline);
+	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
+	store = e_attachment_view_get_store (view);
 
-		for (i = 0; i < file_list->len; i++)
-			g_free (file_list->pdata[i]);
+	e_attachment_store_run_load_dialog (store, GTK_WINDOW (editor));
+}
 
-		g_ptr_array_free (file_list, TRUE);
-	}
+static void
+action_classification_cb (GtkRadioAction *action,
+                          GtkRadioAction *current,
+                          CompEditor *editor)
+{
+	comp_editor_set_changed (editor, TRUE);
 }
 
 static void
@@ -1132,12 +747,17 @@ action_save_cb (GtkAction *action,
                 CompEditor *editor)
 {
 	CompEditorPrivate *priv = editor->priv;
+	EAttachmentStore *store;
+	EAttachmentView *view;
 	ECalComponentText text;
 	gboolean delegated = FALSE;
 	gboolean read_only, correct = FALSE;
 	ECalComponent *comp;
 
-	if (e_attachment_bar_get_download_count (E_ATTACHMENT_BAR (editor->priv->attachment_bar)) ){
+	view = E_ATTACHMENT_VIEW (priv->attachment_view);
+	store = e_attachment_view_get_store (view);
+
+	if (e_attachment_store_get_num_loading (store) > 0) {
 		gboolean response = 1;
 	/*FIXME: Cannot use mail functions from calendar!!!! */
 #if 0
@@ -1520,6 +1140,40 @@ static GtkToggleActionEntry coordinated_toggle_entries[] = {
 };
 
 static void
+comp_editor_setup_recent_menu (CompEditor *editor)
+{
+	EAttachmentView *view;
+	GtkUIManager *ui_manager;
+	GtkAction *action;
+	GtkActionGroup *action_group;
+	const gchar *action_name;
+	const gchar *path;
+	guint merge_id;
+
+	ui_manager = editor->priv->manager;
+	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
+	action_group = comp_editor_get_action_group (editor, "individual");
+	merge_id = gtk_ui_manager_new_merge_id (ui_manager);
+	path = "/main-menu/insert-menu/recent-placeholder";
+	action_name = "recent-menu";
+
+	action = e_attachment_view_recent_action_new (
+		view, action_name, _("Recent _Documents"));
+
+	if (action != NULL) {
+		gtk_action_group_add_action (action_group, action);
+		g_object_unref (action);
+
+		gtk_ui_manager_add_ui (
+			ui_manager, merge_id, path,
+			action_name, action_name,
+			GTK_UI_MANAGER_AUTO, FALSE);
+	}
+
+	gtk_ui_manager_ensure_update (ui_manager);
+}
+
+static void
 comp_editor_set_property (GObject *object,
                           guint property_id,
                           const GValue *value,
@@ -1695,15 +1349,89 @@ comp_editor_map (GtkWidget *widget)
 	GTK_WIDGET_CLASS (comp_editor_parent_class)->map (widget);
 }
 
+static gboolean
+comp_editor_delete_event (GtkWidget *widget,
+                          GdkEventAny *event)
+{
+	CompEditor *editor;
+
+	editor = COMP_EDITOR (widget);
+
+	commit_all_fields (editor);
+
+	if (prompt_and_save_changes (editor, TRUE))
+		close_dialog (editor);
+
+	return TRUE;
+}
+
+static gboolean
+comp_editor_key_press_event (GtkWidget *widget,
+                             GdkEventKey *event)
+{
+	CompEditor *editor;
+
+	editor = COMP_EDITOR (widget);
+
+	if (event->keyval == GDK_Escape) {
+		commit_all_fields (editor);
+
+		if (prompt_and_save_changes (editor, TRUE))
+			close_dialog (editor);
+
+		return TRUE;
+	}
+
+	/* Chain up to parent's key_press_event() method. */
+	return GTK_WIDGET_CLASS (comp_editor_parent_class)->
+		key_press_event (widget, event);
+}
+
+static gboolean
+comp_editor_drag_motion (GtkWidget *widget,
+                         GdkDragContext *context,
+                         gint x,
+                         gint y,
+                         guint time)
+{
+	CompEditorPrivate *priv;
+	EAttachmentView *view;
+
+	priv = COMP_EDITOR_GET_PRIVATE (widget);
+	view = E_ATTACHMENT_VIEW (priv->attachment_view);
+
+	return e_attachment_view_drag_motion (view, context, x, y, time);
+}
+
+static void
+comp_editor_drag_data_received (GtkWidget *widget,
+                                GdkDragContext *context,
+                                gint x,
+                                gint y,
+                                GtkSelectionData *selection,
+                                guint info,
+                                guint time)
+{
+	CompEditorPrivate *priv;
+	EAttachmentView *view;
+
+	priv = COMP_EDITOR_GET_PRIVATE (widget);
+	view = E_ATTACHMENT_VIEW (priv->attachment_view);
+
+	/* Forward the data to the attachment view.  Note that calling
+	 * e_attachment_view_drag_data_received() will not work because
+	 * that function only handles the case where all the other drag
+	 * handlers have failed. */
+	e_attachment_paned_drag_data_received (
+		E_ATTACHMENT_PANED (view),
+		context, x, y, selection, info, time);
+}
+
 static void
 comp_editor_class_init (CompEditorClass *class)
 {
 	GObjectClass *object_class;
 	GtkWidgetClass *widget_class;
-	int i;
-
-	for (i = 0; i < G_N_ELEMENTS (drag_info); i++)
-		drag_info[i].atom = gdk_atom_intern(drag_info[i].target, FALSE);
 
 	g_type_class_add_private (class, sizeof (CompEditorPrivate));
 
@@ -1715,6 +1443,10 @@ comp_editor_class_init (CompEditorClass *class)
 
 	widget_class = GTK_WIDGET_CLASS (class);
 	widget_class->map = comp_editor_map;
+	widget_class->delete_event = comp_editor_delete_event;
+	widget_class->key_press_event = comp_editor_key_press_event;
+	widget_class->drag_motion = comp_editor_drag_motion;
+	widget_class->drag_data_received = comp_editor_drag_data_received;
 
 	class->help_section = "usage-calendar";
 	class->edit_comp = real_edit_comp;
@@ -1777,19 +1509,18 @@ comp_editor_class_init (CompEditorClass *class)
 }
 
 static void
-classification_changed_cb (GtkRadioAction *action, GtkRadioAction *current, CompEditor *editor)
-{
-	g_return_if_fail (IS_COMP_EDITOR (editor));
-
-	comp_editor_set_changed (editor, TRUE);
-}
-
-static void
 comp_editor_init (CompEditor *editor)
 {
 	CompEditorPrivate *priv;
+	EAttachmentView *view;
+	GdkDragAction drag_actions;
+	GtkTargetList *target_list;
+	GtkTargetEntry *targets;
 	GtkActionGroup *action_group;
 	GtkAction *action;
+	GtkWidget *container;
+	GtkWidget *widget;
+	gint n_targets;
 	GError *error = NULL;
 
 	editor->priv = priv = COMP_EDITOR_GET_PRIVATE (editor);
@@ -1798,17 +1529,18 @@ comp_editor_init (CompEditor *editor)
 	priv->changed = FALSE;
 	priv->needs_send = FALSE;
 	priv->mod = CALOBJ_MOD_ALL;
- 	priv->existing_org = FALSE;
- 	priv->user_org = FALSE;
- 	priv->warned = FALSE;
+	priv->existing_org = FALSE;
+	priv->user_org = FALSE;
+	priv->warned = FALSE;
 	priv->is_group_item = FALSE;
 
-	priv->attachment_bar = e_attachment_bar_new (NULL);
 	priv->manager = gtk_ui_manager_new ();
 
-        gtk_window_add_accel_group (
-                GTK_WINDOW (editor),
-                gtk_ui_manager_get_accel_group (priv->manager));
+	gtk_window_add_accel_group (
+		GTK_WINDOW (editor),
+		gtk_ui_manager_get_accel_group (priv->manager));
+
+	/* Setup Action Groups */
 
 	action_group = gtk_action_group_new ("core");
 	gtk_action_group_set_translation_domain (
@@ -1833,11 +1565,7 @@ comp_editor_init (CompEditor *editor)
 		action_group, classification_radio_entries,
 		G_N_ELEMENTS (classification_radio_entries),
 		E_CAL_COMPONENT_CLASS_PUBLIC,
-		G_CALLBACK (classification_changed_cb), editor);
-	action = e_attachment_bar_recent_action_new (
-		E_ATTACHMENT_BAR (priv->attachment_bar),
-		"attach-recent", _("Recent _Documents"));
-	gtk_action_group_add_action (action_group, action);
+		G_CALLBACK (action_classification_cb), editor);
 	gtk_ui_manager_insert_action_group (
 		priv->manager, action_group, 0);
 	g_object_unref (action_group);
@@ -1867,14 +1595,57 @@ comp_editor_init (CompEditor *editor)
 		g_error_free (error);
 	}
 
-	setup_widgets (editor);
+	/* Setup Widgets */
+
+	container = GTK_WIDGET (editor);
+
+	widget = gtk_vbox_new (FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = comp_editor_get_managed_widget (editor, "/main-menu");
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	gtk_widget_show (widget);
+
+	widget = comp_editor_get_managed_widget (editor, "/main-toolbar");
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	gtk_widget_show (widget);
+
+	widget = e_attachment_paned_new ();
+	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	priv->attachment_view = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	container = e_attachment_paned_get_content_area (
+		E_ATTACHMENT_PANED (priv->attachment_view));
+
+	widget = gtk_notebook_new ();
+	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	priv->notebook = GTK_NOTEBOOK (widget);
+	gtk_widget_show (widget);
+
+	comp_editor_setup_recent_menu (editor);
 
-	/* DND support */
-	gtk_drag_dest_set (GTK_WIDGET (editor), GTK_DEST_DEFAULT_ALL,  drop_types, num_drop_types, GDK_ACTION_COPY|GDK_ACTION_ASK|GDK_ACTION_MOVE);
-	g_signal_connect(editor, "drag_data_received", G_CALLBACK (drag_data_received), NULL);
-	g_signal_connect(editor, "drag-motion", G_CALLBACK(drag_motion), editor);
+	/* Drag-and-Drop Support */
 
-	gtk_window_set_type_hint (GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_NORMAL);
+	view = E_ATTACHMENT_VIEW (priv->attachment_view);
+	target_list = e_attachment_view_get_target_list (view);
+	drag_actions = e_attachment_view_get_drag_actions (view);
+
+	targets = gtk_target_table_new_from_list (target_list, &n_targets);
+
+	gtk_drag_dest_set (
+		GTK_WIDGET (editor), GTK_DEST_DEFAULT_ALL,
+		targets, n_targets, drag_actions);
+
+	gtk_target_table_free (targets, n_targets);
+
+	gtk_window_set_type_hint (
+		GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_NORMAL);
 }
 
 static gboolean
@@ -1927,402 +1698,17 @@ prompt_and_save_changes (CompEditor *editor, gboolean send)
 	}
 }
 
-static int
-delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
-{
-	CompEditor *editor = COMP_EDITOR (data);
-
-	commit_all_fields (editor);
-
-	if (prompt_and_save_changes (editor, TRUE))
-		close_dialog (editor);
-
-	return TRUE;
-}
-
 static void
-attachment_bar_changed_cb (EAttachmentBar *bar,
-			   void *data)
+attachment_store_changed_cb (CompEditor *editor)
 {
-	CompEditor *editor = COMP_EDITOR (data);
-
-	guint attachment_num = e_attachment_bar_get_num_attachments (
-		E_ATTACHMENT_BAR (editor->priv->attachment_bar));
-	if (attachment_num) {
-		gchar *num_text = g_strdup_printf (
-			ngettext ("<b>%d</b> Attachment", "<b>%d</b> Attachments", attachment_num),
-			attachment_num);
-		gtk_label_set_markup (GTK_LABEL (editor->priv->attachment_expander_num),
-				      num_text);
-		g_free (num_text);
-
-		gtk_widget_show (editor->priv->attachment_expander_icon);
-		e_expander_set_expanded(E_EXPANDER(editor->priv->attachment_expander),TRUE);
-
-	} else {
-		gtk_label_set_text (GTK_LABEL (editor->priv->attachment_expander_num), "");
-		gtk_widget_hide (editor->priv->attachment_expander_icon);
-		e_expander_set_expanded(E_EXPANDER(editor->priv->attachment_expander),FALSE);
-	}
-
-
 	/* Mark the editor as changed so it prompts about unsaved
            changes on close */
 	comp_editor_set_changed (editor, TRUE);
-
-}
-
-static void
-attachment_expander_activate_cb (EExpander *expander,
-				 void *data)
-{
-	CompEditor *editor = COMP_EDITOR (data);
-	gboolean show = e_expander_get_expanded (expander);
-
-	/* Update the expander label */
-	if (show)
-		gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label),
-					          _("Hide Attachment _Bar"));
-	else
-		gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label),
-						  _("Show Attachment _Bar"));
-}
-
-static gboolean
-open_attachment (EAttachmentBar *bar, CompEditor *editor)
-{
-	GnomeIconList *icon_list;
-	GList *p;
-	int num;
-	char *attach_file_url;
-
-	if (E_IS_ATTACHMENT_BAR (bar)) {
-		icon_list = GNOME_ICON_LIST (bar);
-		p = gnome_icon_list_get_selection (icon_list);
-		if (p) {
-			EAttachment *attachment;
-			GSList *list;
-			const char *comp_uid = NULL;
-			char *filename = NULL;
-			const char *local_store = e_cal_get_local_attachment_store (editor->priv->client);
-
-			e_cal_component_get_uid (editor->priv->comp, &comp_uid);
-			num = GPOINTER_TO_INT (p->data);
-			list = e_attachment_bar_get_attachment (bar, num);
-			attachment = list->data;
-			g_slist_free (list);
-
-			filename = g_strdup_printf ("%s-%s",
-						    comp_uid,
-						    camel_mime_part_get_filename(attachment->body));
-
-			attach_file_url = g_build_path ("/", local_store, filename, NULL);
-
-			/* launch the url now */
-			e_show_uri (GTK_WINDOW (editor), attach_file_url);
-
-			g_free (filename);
-			g_free (attach_file_url); }
-		return TRUE;
-	} else
-		return FALSE;
-}
-
-static	gboolean
-attachment_bar_icon_clicked_cb (EAttachmentBar *bar, GdkEvent *event, CompEditor *editor)
-{
-	if (E_IS_ATTACHMENT_BAR (bar) && event->type == GDK_2BUTTON_PRESS)
-		if (open_attachment (bar, editor))
-				return TRUE;
-	return FALSE;
-}
-
-/* Callbacks.  */
-
-static void
-cab_open(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachmentBar *bar = data;
-	CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
-
-	if (!open_attachment (bar, editor))
-		g_message ("\n Open failed");
-}
-
-static void
-cab_add(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachmentBar *bar = data;
-        CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
-	GPtrArray *file_list;
-	gboolean is_inline = FALSE;
-	int i;
-
-	file_list = comp_editor_select_file_attachments (editor, &is_inline);
-	/*TODO add a good implementation here */
-	if (!file_list)
-		return;
-	for (i = 0; i < file_list->len; i++) {
-		CamelURL *url;
-
-		url = camel_url_new (file_list->pdata[i], NULL);
-		if (url == NULL)
-			continue;
-
-		if (!g_ascii_strcasecmp (url->protocol, "file"))
-			 e_attachment_bar_attach (bar, url->path, is_inline ? "inline" : "attachment");
-		else
-			 e_attachment_bar_attach_remote_file (bar, file_list->pdata[i], is_inline ? "inline" : "attachment");
-		g_free (file_list->pdata[i]);
-		camel_url_free (url);
-	}
-
-	g_ptr_array_free (file_list, TRUE);
-}
-
-static void
-cab_properties(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachmentBar *bar = data;
-
-	e_attachment_bar_edit_selected(bar);
-}
-
-static void
-cab_remove(EPopup *ep, EPopupItem *item, void *data)
-{
-	EAttachmentBar *bar = data;
-
-	e_attachment_bar_remove_selected(bar);
-}
-
-/* Popup menu handling.  */
-static EPopupItem cab_popups[] = {
-	{ E_POPUP_ITEM, "10.attach", N_("_Open"), cab_open, NULL, GTK_STOCK_OPEN, E_CAL_POPUP_ATTACHMENTS_ONE},
-	{ E_POPUP_ITEM, "20.attach", N_("_Remove"), cab_remove, NULL, GTK_STOCK_REMOVE, E_CAL_POPUP_ATTACHMENTS_MANY | E_CAL_POPUP_ATTACHMENTS_MODIFY },
-	{ E_POPUP_ITEM, "30.attach", N_("_Properties"), cab_properties, NULL, GTK_STOCK_PROPERTIES, E_CAL_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_BAR, "40.attach.00", NULL, NULL, NULL, NULL, E_CAL_POPUP_ATTACHMENTS_MANY|E_CAL_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_ITEM, "40.attach.01", N_("_Add attachment..."), cab_add, NULL, GTK_STOCK_ADD, E_CAL_POPUP_ATTACHMENTS_MODIFY},
-};
-
-static void
-cab_popup_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
-{
-	EAttachmentBar *bar = user_data;
-	GnomeIconList *icon_list = user_data;
-	GList *selection;
-	GnomeCanvasPixbuf *image;
-
-	gdk_window_get_origin (((GtkWidget*) bar)->window, x, y);
-
-	selection = gnome_icon_list_get_selection (icon_list);
-	if (selection == NULL)
-		return;
-
-	image = gnome_icon_list_get_icon_pixbuf_item (icon_list, GPOINTER_TO_INT(selection->data));
-	if (image == NULL)
-		return;
-
-	/* Put menu to the center of icon. */
-	*x += (int)(image->item.x1 + image->item.x2) / 2;
-	*y += (int)(image->item.y1 + image->item.y2) / 2;
-}
-
-static void
-cab_popups_free(EPopup *ep, GSList *l, void *data)
-{
-	g_slist_free(l);
-}
-
-/* if id != -1, then use it as an index for target of the popup */
-static void
-cab_popup(EAttachmentBar *bar, GdkEventButton *event, int id)
-{
-	GSList *attachments = NULL, *menus = NULL;
-	int i;
-	ECalPopup *ecp;
-	ECalPopupTargetAttachments *t;
-	GtkMenu *menu;
-	CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
-
-        attachments = e_attachment_bar_get_attachment(bar, id);
-
-	for (i=0;i<sizeof(cab_popups)/sizeof(cab_popups[0]);i++)
-		menus = g_slist_prepend(menus, &cab_popups[i]);
-
-	/** @HookPoint-ECalPopup: Calendar Attachment Bar Context Menu
-	 * @Id: org.gnome.evolution.calendar.attachmentbar.popup
-	 * @Class: org.gnome.evolution.mail.popup:1.0
-	 * @Target: ECalPopupTargetAttachments
-	 *
-	 * This is the context menu on the calendar attachment bar.
-	 */
-	ecp = e_cal_popup_new("org.gnome.evolution.calendar.attachmentbar.popup");
-	e_popup_add_items((EPopup *)ecp, menus, NULL, cab_popups_free, bar);
-	t = e_cal_popup_target_new_attachments(ecp, editor, attachments);
-	t->target.widget = (GtkWidget *)bar;
-	menu = e_popup_create_menu_once((EPopup *)ecp, (EPopupTarget *)t, 0);
-
-	if (event == NULL)
-		gtk_menu_popup(menu, NULL, NULL, cab_popup_position, bar, 0, gtk_get_current_event_time());
-	else
-		gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
-}
-
-/* GtkWidget methods.  */
-
-static gboolean
-popup_menu_event (EAttachmentBar *bar)
-{
-	cab_popup (bar, NULL, -1);
-
-	return TRUE;
-}
-
-
-static int
-button_press_event (EAttachmentBar *bar,
-                    GdkEventButton *event)
-{
-	GnomeIconList *icon_list = GNOME_ICON_LIST (bar);
-	int icon_number = -1;
-
-	if (event->button != 3)
-		return FALSE;
-
-	if (!gnome_icon_list_get_selection (icon_list)) {
-		icon_number = gnome_icon_list_get_icon_at (icon_list, event->x, event->y);
-		if (icon_number >= 0) {
-			gnome_icon_list_unselect_all(icon_list);
-			gnome_icon_list_select_icon (icon_list, icon_number);
-		}
-	}
-
-	cab_popup(bar, event, icon_number);
-
-	return TRUE;
-}
-
-static gint
-key_press_event (EAttachmentBar *bar,
-                 GdkEventKey *event)
-{
-	if (event->keyval == GDK_Delete) {
-                e_attachment_bar_remove_selected (bar);
-                return TRUE;
-        }
-
-        return FALSE;
-}
-
-static gint
-editor_key_press_event (CompEditor *editor,
-                        GdkEventKey *event)
-{
-        if (event->keyval == GDK_Escape) {
-		commit_all_fields (editor);
-
-		if (prompt_and_save_changes (editor, TRUE))
-			close_dialog (editor);
-
-                return TRUE;
-        }
-
-        return FALSE;
 }
 
 /* Menu callbacks */
 
 static void
-setup_widgets (CompEditor *editor)
-{
-	CompEditorPrivate *priv;
-	GtkWidget *expander_hbox;
-	GtkWidget *widget;
-	GtkWidget *vbox;
-
-	priv = editor->priv;
-
-	/* Useful vbox */
-	vbox = gtk_vbox_new (FALSE, 0);
-	gtk_container_add (GTK_CONTAINER (editor), vbox);
-	gtk_widget_show (vbox);
-
-	/* Main Menu */
-	widget = comp_editor_get_managed_widget (editor, "/main-menu");
-	gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
-	gtk_widget_show (widget);
-
-	/* Main Toolbar */
-	widget = comp_editor_get_managed_widget (editor, "/main-toolbar");
-	gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
-	gtk_widget_show (widget);
-
-	/* Notebook */
-	widget = gtk_notebook_new ();
-	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
-	gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
-	gtk_widget_show (widget);
-	priv->notebook = GTK_NOTEBOOK (widget);
-
-	g_signal_connect (editor, "delete_event", G_CALLBACK (delete_event_cb), editor);
-	g_signal_connect (editor, "key_press_event", G_CALLBACK (editor_key_press_event), editor);
-
-	/*Attachments */
-	priv->attachment_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
-					     GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
-					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
-	g_signal_connect (priv->attachment_bar, "button_press_event", G_CALLBACK (button_press_event), NULL);
-        g_signal_connect (priv->attachment_bar, "key_press_event", G_CALLBACK (key_press_event), NULL);
-        g_signal_connect (priv->attachment_bar, "popup-menu", G_CALLBACK (popup_menu_event), NULL);
-
-	GTK_WIDGET_SET_FLAGS (priv->attachment_bar, GTK_CAN_FOCUS);
-	gtk_container_add (GTK_CONTAINER (priv->attachment_scrolled_window),
-			   priv->attachment_bar);
-	gtk_widget_show (priv->attachment_bar);
-	g_signal_connect (priv->attachment_bar, "changed",
-			  G_CALLBACK (attachment_bar_changed_cb), editor);
-	g_signal_connect (GNOME_ICON_LIST (priv->attachment_bar), "event",
-			  G_CALLBACK (attachment_bar_icon_clicked_cb), editor);
-	priv->attachment_expander_label =
-		gtk_label_new_with_mnemonic (_("Show Attachment _Bar"));
-	priv->attachment_expander_num = gtk_label_new ("");
-	gtk_label_set_use_markup (GTK_LABEL (priv->attachment_expander_num), TRUE);
-	gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_label), 0.0, 0.5);
-	gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_num), 1.0, 0.5);
-	expander_hbox = gtk_hbox_new (FALSE, 0);
-
-	priv->attachment_expander_icon = gtk_image_new_from_icon_name ("mail-attachment", GTK_ICON_SIZE_MENU);
-	gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_icon), 1, 0.5);
-	gtk_widget_set_size_request (priv->attachment_expander_icon, 100, -1);
-
-	gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_label,
-			    TRUE, TRUE, 0);
-	gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_icon,
-			    TRUE, TRUE, 0);
-	gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_num,
-			    TRUE, TRUE, 0);
-	gtk_widget_show_all (expander_hbox);
-	gtk_widget_hide (priv->attachment_expander_icon);
-
-	priv->attachment_expander = e_expander_new ("");
-	e_expander_set_label_widget (E_EXPANDER (priv->attachment_expander), expander_hbox);
-	atk_object_set_name (gtk_widget_get_accessible (priv->attachment_expander), _("Show Attachments"));
-	atk_object_set_description (gtk_widget_get_accessible (priv->attachment_expander), _("Press space key to toggle attachment bar"));
-	gtk_container_add (GTK_CONTAINER (priv->attachment_expander), priv->attachment_scrolled_window);
-
-	gtk_box_pack_start (GTK_BOX (vbox), priv->attachment_expander, FALSE, FALSE, 4);
-	gtk_widget_show (priv->attachment_expander);
-	e_expander_set_expanded (E_EXPANDER (priv->attachment_expander), FALSE);
-	g_signal_connect_after (priv->attachment_expander, "activate",
-				G_CALLBACK (attachment_expander_activate_cb), editor);
-}
-
-
-static void
 comp_editor_show_help (CompEditor *editor)
 {
 	CompEditorClass *class;
@@ -2861,12 +2247,14 @@ comp_editor_get_client (CompEditor *editor)
 static void
 set_attachment_list (CompEditor *editor, GSList *attach_list)
 {
-	GSList *p = NULL;
-	const char *comp_uid= NULL;
+	EAttachmentStore *store;
+	EAttachmentView *view;
+	GSList *iter = NULL;
 
-	e_cal_component_get_uid (editor->priv->comp, &comp_uid);
+	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
+	store = e_attachment_view_get_store (view);
 
-	if (e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar))) {
+	if (e_attachment_store_get_num_attachments (store) > 0) {
 		/* To prevent repopulating the
 		 * bar due to redraw functions in fill_widget.
 		 * Assumes it can be set only once.
@@ -2874,112 +2262,55 @@ set_attachment_list (CompEditor *editor, GSList *attach_list)
 		return;
 	}
 
-	for (p = attach_list; p != NULL; p = p->next) {
-		char *attach_filename;
-		CamelMimePart *part;
-		CamelDataWrapper *wrapper;
-		CamelStream *stream;
-		struct stat statbuf;
-		char *mime_type, *file_name;
-		char *ptr;
-
-		attach_filename = (char *) p->data;
-		/* should we assert if g_str_has_prefix (attach_filename, "file://"))
-		 * here
-		*/
-		/* get url sans protocol and add it to the bar.
-		 * how to set the filename properly */
-		file_name = g_filename_from_uri (attach_filename, NULL, NULL);
-		if (!file_name)
-			continue;
-
-		if (g_stat (file_name, &statbuf) < 0) {
-			g_warning ("Cannot attach file %s: %s", file_name, g_strerror (errno));
-			g_free (file_name);
-			continue;
-		}
-
-		/* return if it's not a regular file */
-		if (!S_ISREG (statbuf.st_mode)) {
-			g_warning ("Cannot attach file %s: not a regular file", file_name);
-			g_free (file_name);
-			return;
-		}
-
-		stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0);
-		if (!stream) {
-			g_warning ("Cannot attach file %s: %s", file_name, g_strerror (errno));
-			g_free (file_name);
-			return;
-		}
-
-		mime_type = e_util_guess_mime_type (file_name, TRUE);
-		if (mime_type) {
-			if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
-				wrapper = (CamelDataWrapper *) camel_mime_message_new ();
-			} else {
-				wrapper = camel_data_wrapper_new ();
-			}
-
-			camel_data_wrapper_construct_from_stream (wrapper, stream);
-			camel_data_wrapper_set_mime_type (wrapper, mime_type);
-			g_free (mime_type);
-		} else {
-			wrapper = camel_data_wrapper_new ();
-			camel_data_wrapper_construct_from_stream (wrapper, stream);
-			camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
-		}
-
-		camel_object_unref (stream);
-
-		part = camel_mime_part_new ();
-		camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
-		camel_object_unref (wrapper);
+	for (iter = attach_list; iter != NULL; iter = iter->next) {
+		EAttachment *attachment;
+		const gchar *uri = iter->data;
 
-		camel_mime_part_set_disposition (part, "attachment");
-
-		ptr = strstr (file_name, comp_uid);
-		if (ptr) {
-			ptr += strlen(comp_uid);
-			if (*ptr++ == '-')
-				camel_mime_part_set_filename (part, ptr);
-		}
-		g_free (file_name);
-
-		e_attachment_bar_attach_mime_part ((EAttachmentBar *) editor->priv->attachment_bar, part);
-		e_expander_set_expanded (E_EXPANDER (editor->priv->attachment_expander), TRUE);
-
-		camel_object_unref (part);
+		attachment = e_attachment_new_for_uri (uri);
+		e_attachment_store_add_attachment (store, attachment);
+		e_attachment_load_async (
+			attachment, (GAsyncReadyCallback)
+			e_attachment_load_handle_error, editor);
+		g_object_unref (attachment);
 	}
 }
 
 static void
 fill_widgets (CompEditor *editor)
 {
+	EAttachmentStore *store;
+	EAttachmentView *view;
 	CompEditorPrivate *priv;
 	GList *l;
 	GtkAction *action;
 
+	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
+	store = e_attachment_view_get_store (view);
+
 	priv = editor->priv;
 
 	/*Check if attachments are available here and set them*/
 	if (e_cal_component_has_attachments (priv->comp)) {
 		GSList *attachment_list = NULL;
 		e_cal_component_get_attachment_list (priv->comp, &attachment_list);
-		g_signal_handlers_block_by_func(priv->attachment_bar, G_CALLBACK (attachment_bar_changed_cb), editor);
+		g_signal_handlers_block_by_func (
+			store, G_CALLBACK (attachment_store_changed_cb),
+			editor);
 		set_attachment_list (editor, attachment_list);
-		g_signal_handlers_unblock_by_func(priv->attachment_bar, G_CALLBACK (attachment_bar_changed_cb), editor);
+		g_signal_handlers_unblock_by_func (
+			store, G_CALLBACK (attachment_store_changed_cb),
+			editor);
 		g_slist_foreach (attachment_list, (GFunc)g_free, NULL);
 		g_slist_free (attachment_list);
 	}
 
 	action = comp_editor_get_action (editor, "classify-public");
-	g_signal_handlers_block_by_func (action, G_CALLBACK (classification_changed_cb), editor);
+	g_signal_handlers_block_by_func (action, G_CALLBACK (action_classification_cb), editor);
 
 	for (l = priv->pages; l != NULL; l = l->next)
 		comp_editor_page_fill_widgets (l->data, priv->comp);
 
-	g_signal_handlers_unblock_by_func (action, G_CALLBACK (classification_changed_cb), editor);
+	g_signal_handlers_unblock_by_func (action, G_CALLBACK (action_classification_cb), editor);
 }
 
 static void
@@ -3303,20 +2634,41 @@ comp_editor_close (CompEditor *editor)
 GSList *
 comp_editor_get_mime_attach_list (CompEditor *editor)
 {
+	EAttachmentStore *store;
+	EAttachmentView *view;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
 	struct CalMimeAttach *cal_mime_attach;
-	GSList *attach_list = NULL, *l, *parts;
+	GSList *attach_list = NULL;
+	gboolean valid;
+
+	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
+	store = e_attachment_view_get_store (view);
 
-	/* TODO assert sanity of bar */
-	parts = e_attachment_bar_get_parts (E_ATTACHMENT_BAR (editor->priv->attachment_bar));
-	for (l = parts; l ; l = l->next) {
+	model = GTK_TREE_MODEL (store);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
 
+	while (valid) {
+		EAttachment *attachment;
 		CamelDataWrapper *wrapper;
+		CamelMimePart *mime_part;
 		CamelStreamMem *mstream;
 		unsigned char *buffer = NULL;
 		const char *desc, *disp;
+		gint column_id;
+
+		column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
+		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
+		mime_part = e_attachment_get_mime_part (attachment);
+		g_object_unref (attachment);
+
+		valid = gtk_tree_model_iter_next (model, &iter);
+
+		if (mime_part == NULL)
+			continue;
 
 		cal_mime_attach = g_malloc0 (sizeof (struct CalMimeAttach));
-		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (l->data));
+		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
 		mstream = (CamelStreamMem *) camel_stream_mem_new ();
 
 		camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
@@ -3324,15 +2676,14 @@ comp_editor_get_mime_attach_list (CompEditor *editor)
 
 		cal_mime_attach->encoded_data = (char *)buffer;
 		cal_mime_attach->length = mstream->buffer->len;
-		cal_mime_attach->filename = g_strdup (camel_mime_part_get_filename
-			((CamelMimePart *) l->data));
-		desc = camel_mime_part_get_description ((CamelMimePart *) l->data);
+		cal_mime_attach->filename = g_strdup (camel_mime_part_get_filename (mime_part));
+		desc = camel_mime_part_get_description (mime_part);
 		if (!desc || *desc == '\0')
 			desc = _("attachment");
 		cal_mime_attach->description = g_strdup (desc);
 		cal_mime_attach->content_type = g_strdup (camel_data_wrapper_get_mime_type (wrapper));
 
-		disp = camel_mime_part_get_disposition ((CamelMimePart *)l->data);
+		disp = camel_mime_part_get_disposition (mime_part);
 		if (disp && !g_ascii_strcasecmp(disp, "inline"))
 			cal_mime_attach->disposition = TRUE;
 
@@ -3342,8 +2693,6 @@ comp_editor_get_mime_attach_list (CompEditor *editor)
 
 	}
 
-	g_slist_free (parts);
-
 	return attach_list;
 }
 
diff --git a/calendar/gui/dialogs/event-editor.c b/calendar/gui/dialogs/event-editor.c
index a579d77..f32f245 100644
--- a/calendar/gui/dialogs/event-editor.c
+++ b/calendar/gui/dialogs/event-editor.c
@@ -512,8 +512,6 @@ event_editor_init (EventEditor *ee)
 	g_signal_connect_swapped (
 		ee->priv->model, "row_deleted",
 		G_CALLBACK (event_editor_model_changed_cb), ee);
-
-	gtk_window_set_default_size (GTK_WINDOW (ee), 300, 225);
 }
 
 static void
diff --git a/calendar/gui/e-cal-popup.c b/calendar/gui/e-cal-popup.c
index b9f0d5f..0292f16 100644
--- a/calendar/gui/e-cal-popup.c
+++ b/calendar/gui/e-cal-popup.c
@@ -86,378 +86,11 @@ ecalp_target_free(EPopup *ep, EPopupTarget *t)
 
 /* Standard menu code */
 
-static char *
-temp_save_part(CamelMimePart *part, char *path, gboolean file)
-{
-	const char *filename;
-	char *tmpdir, *utf8_mfilename = NULL, *mfilename = NULL, *usepath;
-	CamelStream *stream;
-	CamelDataWrapper *wrapper;
-
-	if (!path) {
-		tmpdir = e_mkdtemp("evolution-tmp-XXXXXX");
-		if (tmpdir == NULL) {
-			return NULL;
-		}
-
-		filename = camel_mime_part_get_filename (part);
-		if (filename == NULL) {
-			/* This is the default filename used for temporary file creation */
-			filename = _("Unknown");
-		} else {
-			utf8_mfilename = g_strdup (filename);
-			e_filename_make_safe (utf8_mfilename);
-			mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL);
-			g_free (utf8_mfilename);
-			filename = (const char *) mfilename;
-		}
-
-		path = g_build_filename(tmpdir, filename, NULL);
-		g_free(tmpdir);
-		g_free(mfilename);
-	} else if (!file) {
-		tmpdir = path;
-		filename = camel_mime_part_get_filename (part);
-		if (filename == NULL) {
-			/* This is the default filename used for temporary file creation */
-			filename = _("Unknown");
-		} else {
-			utf8_mfilename = g_strdup (filename);
-			e_filename_make_safe (utf8_mfilename);
-			mfilename = g_filename_from_utf8 ((const char *)utf8_mfilename, -1, NULL, NULL, NULL);
-			g_free (utf8_mfilename);
-			filename = (const char *) mfilename;
-		}
-
-		path = g_build_filename(tmpdir, filename, NULL);
-		g_free(mfilename);
-	}
-
-	if (strstr (path, "://"))
-		usepath = path;
-	else
-		usepath = g_strjoin (NULL, "file://", path, NULL);
-
-	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
-	stream = camel_stream_vfs_new_with_uri (usepath, CAMEL_STREAM_VFS_CREATE);
-
-	if (usepath != path)
-		g_free (usepath);
-
-	if (!stream) {
-		/* TODO handle error conditions */
-		g_message ("DEBUG: could not open the file to write\n");
-		return NULL;
-	}
-
-	if (camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) stream) == -1) {
-		camel_stream_close (stream);
-		camel_object_unref (stream);
-		g_message ("DEBUG: could not write to file\n");
-		return NULL;
-	}
-
-	camel_stream_close(stream);
-	camel_object_unref(stream);
-
-	return path;
-}
-
-static void
-ecalp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	CamelMimePart *part = NULL;
-	char *file, *mfilename = NULL;
-	const char *filename;
-
-	part = ((EAttachment *) ((ECalPopupTargetAttachments *) t)->attachments->data)->body;
-	filename = camel_mime_part_get_filename (part);
-	if (filename == NULL) {
-		/* This is the default filename used for temporary file creation */
-		filename = _("Unknown");
-	} else {
-		mfilename = g_strdup(filename);
-		e_filename_make_safe(mfilename);
-		filename = mfilename;
-	}
-	file = e_file_dialog_save (_("Save As..."), filename);
-
-	if (file)
-		temp_save_part (part, file, TRUE);
-
-	g_free (file);
-	g_free (mfilename);
-}
-
-static void
-ecalp_part_popup_save_selected(EPopup *ep, EPopupItem *item, void *data)
-{
-	GSList *parts;
-	EPopupTarget *t = ep->target;
-	char *dir, *path;
-
-	dir = e_file_dialog_save_folder (_("Select folder to save selected attachments..."));
-	parts = ((ECalPopupTargetAttachments *) t)->attachments;
-
-	for (;parts; parts=parts->next) {
-		path = temp_save_part (((EAttachment *)parts->data)->body, dir, FALSE);
-		/* Probably we 'll do some reporting in next release, like listing the saved files and locations */
-		g_free (path);
-	}
-}
-
-static void
-ecalp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	GConfClient *gconf;
-	char *str, *filename, *path, *extension;
-	unsigned int i=1;
-	CamelMimePart *part = NULL;
-
-	part = ((EAttachment *) ((ECalPopupTargetAttachments *) t)->attachments->data)->body;
-
-	if (!part)
-		return;
-
-	filename = g_strdup(camel_mime_part_get_filename(part));
-
-	/* if filename is blank, create a default filename based on MIME type */
-	if (!filename || !filename[0]) {
-		CamelContentType *ct;
-
-		ct = camel_mime_part_get_content_type(part);
-		g_free (filename);
-		filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype);
-	}
-
-	e_filename_make_safe(filename);
-
-	path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", filename, NULL);
-
-	extension = strrchr(filename, '.');
-	if (extension)
-		*extension++ = 0;
-
-	/* if file exists, stick a (number) on the end */
-	while (g_file_test(path, G_FILE_TEST_EXISTS)) {
-		char *name;
-		name = g_strdup_printf(extension?"%s (%d).%s":"%s (%d)", filename, i++, extension);
-		g_free(path);
-		path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", name, NULL);
-		g_free(name);
-	}
-
-	g_free(filename);
-
-	if (temp_save_part(part, path, TRUE)) {
-		gconf = gconf_client_get_default();
-
-		/* if the filename hasn't changed, blank the filename before
-		*  setting it so that gconf detects a change and updates it */
-		if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_filename", NULL)) != NULL
-		     && strcmp (str, path) == 0) {
-			gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", "", NULL);
-		}
-
-		g_free (str);
-		gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", path, NULL);
-
-		/* if GNOME currently doesn't display a picture, set to "wallpaper"
-		 * display mode, otherwise leave it alone */
-		if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_options", NULL)) == NULL
-		     || strcmp(str, "none") == 0) {
-			gconf_client_set_string(gconf, "/desktop/gnome/background/picture_options", "wallpaper", NULL);
-		}
-
-		gconf_client_suggest_sync(gconf, NULL);
-
-		g_free(str);
-		g_object_unref(gconf);
-	}
-
-	g_free(path);
-}
-
-static const EPopupItem ecalp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" };
-
-static ECalPopupItem ecalp_attachment_object_popups[] = {
-	{ E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), ecalp_part_popup_saveas, NULL, "document-save-as", E_CAL_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), ecalp_part_popup_set_background, NULL, NULL, E_CAL_POPUP_ATTACHMENTS_IMAGE },
-	{ E_POPUP_ITEM, "00.attach.20", N_("_Save Selected"), ecalp_part_popup_save_selected, NULL, "document-save-as", E_CAL_POPUP_ATTACHMENTS_MULTIPLE },
-	{ E_POPUP_BAR, "05.attach", },
-};
-
-static void
-ecalp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
-{
-	char *path;
-	EPopupTarget *target = ep->target;
-	CamelMimePart *part;
-
-	part = ((EAttachment *) ((ECalPopupTargetAttachments *) target)->attachments->data)->body;
-
-	path = temp_save_part(part, NULL, FALSE);
-	if (path) {
-		GAppInfo *app = item->user_data;
-		GList *uris = NULL;
-		GError *error = NULL;
-
-		if (g_app_info_supports_files (app)) {
-			GFile *file = g_file_new_for_path (path);
-
-			uris = g_list_append (uris, file);
-			g_app_info_launch (app, uris, NULL, &error);
-			g_object_unref (file);
-		} else {
-			char *uri;
-
-			uri = e_util_filename_to_uri (path);
-			uris = g_list_append (uris, uri);
-
-			g_app_info_launch_uris (app, uris, NULL, &error);
-			g_free (uri);
-		}
-
-		if (error) {
-			g_warning ("%s", error->message);
-			g_error_free (error);
-		}
-
-		g_list_free (uris);
-		g_free (path);
-	}
-}
-
-static void
-ecalp_apps_popup_free(EPopup *ep, GSList *free_list, void *data)
-{
-	while (free_list) {
-		GSList *n = free_list->next;
-		EPopupItem *item = free_list->data;
-
-		if (item->user_data && item->activate == ecalp_apps_open_in)
-			g_object_unref (item->user_data);
-
-		g_free(item->path);
-		g_free(item->label);
-		g_free(item);
-		g_slist_free_1(free_list);
-
-		free_list = n;
-	}
-}
-
-static void
-ecalp_standard_items_free(EPopup *ep, GSList *items, void *data)
-{
-	g_slist_free(items);
-}
-
-static void
-ecalp_standard_menu_factory (EPopup *ecalp, void *data)
-{
-	int i, len;
-	EPopupItem *items;
-	GSList *menus = NULL;
-	GList *apps = NULL;
-	char *mime_type = NULL;
-	const char *filename = NULL;
-
-	switch (ecalp->target->type) {
-	case E_CAL_POPUP_TARGET_ATTACHMENTS: {
-		ECalPopupTargetAttachments *t = (ECalPopupTargetAttachments *)ecalp->target;
-		GSList *list = t->attachments;
-		EAttachment *attachment;
-
-		items = ecalp_attachment_object_popups;
-		len = G_N_ELEMENTS(ecalp_attachment_object_popups);
-
-		if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) {
-			break;
-		}
-
-		/* Only one attachment selected */
-		attachment = list->data;
-		mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)attachment->body);
-		filename = camel_mime_part_get_filename(attachment->body);
-
-
-		break; }
-	default:
-		items = NULL;
-		len = 0;
-	}
-
-	if (mime_type) {
-                gchar *cp;
-
-                /* does gvfs expect lowercase MIME types? */
-                for (cp = mime_type; *cp != '\0'; cp++)
-                        *cp = g_ascii_tolower (*cp);
-
-		cp = g_content_type_from_mime_type (mime_type);
-		apps = g_app_info_get_all_for_type (cp ? cp : mime_type);
-		g_free (cp);
-
-		if (apps == NULL || strcmp(mime_type, "application/octet-stream") == 0) {
-			if (filename) {
-				gchar *name_type;
-
-				name_type = e_util_guess_mime_type (filename, FALSE);
-				cp = g_content_type_from_mime_type (name_type);
-				/* show alternative apps first */
-				apps = g_list_concat (g_app_info_get_all_for_type (cp ? cp : name_type), apps);
-				g_free (cp);
-				g_free (name_type);
-			}
-		}
-		g_free (mime_type);
-
-		if (apps) {
-			GSList *open_menus = NULL;
-			GList *l;
-
-			menus = g_slist_prepend(menus, (void *)&ecalp_standard_part_apps_bar);
-
-			for (l = apps, i = 0; l; l = l->next, i++) {
-				GAppInfo *app = l->data;
-				EPopupItem *item;
-
-				item = g_malloc0(sizeof(*item));
-				item->type = E_POPUP_ITEM;
-				item->path = g_strdup_printf("99.object.%02d", i);
-				item->label = g_strdup_printf(_("Open in %s..."), g_app_info_get_name (app));
-				item->activate = ecalp_apps_open_in;
-				item->user_data = app;
-
-				open_menus = g_slist_prepend(open_menus, item);
-			}
-
-			if (open_menus)
-				e_popup_add_items(ecalp, open_menus, NULL, ecalp_apps_popup_free, NULL);
-
-			g_list_free (apps);
-		}
-	}
-
-	for (i=0;i<len;i++) {
-		if ((items[i].visible & ecalp->target->mask) == 0)
-			menus = g_slist_prepend(menus, &items[i]);
-	}
-
-	if (menus)
-		e_popup_add_items(ecalp, menus, NULL, ecalp_standard_items_free, NULL);
-}
-
 static void
 ecalp_class_init(GObjectClass *klass)
 {
 	klass->finalize = ecalp_finalise;
 	((EPopupClass *)klass)->target_free = ecalp_target_free;
-
-	e_popup_class_add_factory((EPopupClass *)klass, NULL, ecalp_standard_menu_factory, NULL);
 }
 
 GType
@@ -750,56 +383,6 @@ e_cal_popup_target_new_source(ECalPopup *eabp, ESourceSelector *selector)
 	return t;
 }
 
-/**
- * e_cal_popup_target_new_attachments:
- * @ecp:
- * @attachments: A list of CalAttachment objects, reffed for
- * the list.  Will be unreff'd once finished with.
- *
- * Owns the list @attachments and their items after they're passed in.
- *
- * Return value:
- **/
-ECalPopupTargetAttachments *
-e_cal_popup_target_new_attachments(ECalPopup *ecp, CompEditor *editor, GSList *attachments)
-{
-	ECalPopupTargetAttachments *t = e_popup_target_new(&ecp->popup, E_CAL_POPUP_TARGET_ATTACHMENTS, sizeof(*t));
-	guint32 mask = ~0;
-	int len = g_slist_length(attachments);
-	ECal *client = comp_editor_get_client (editor);
-	CompEditorFlags flags = comp_editor_get_flags (editor);
-	gboolean read_only = FALSE;
-	GError *error = NULL;
-
-	if (!e_cal_is_read_only (client, &read_only, &error)) {
-		if (error->code != E_CALENDAR_STATUS_BUSY)
-			read_only = TRUE;
-		g_error_free (error);
-	}
-
-	if (!read_only && (!(flags & COMP_EDITOR_MEETING) ||
-				(flags & COMP_EDITOR_NEW_ITEM) ||
-				(flags & COMP_EDITOR_USER_ORG)))
-		mask &= ~ E_CAL_POPUP_ATTACHMENTS_MODIFY;
-
-	t->attachments = attachments;
-	if (len > 0)
-		mask &= ~ E_CAL_POPUP_ATTACHMENTS_MANY;
-
-	if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) {
-		if (camel_content_type_is(((CamelDataWrapper *) ((EAttachment *) attachments->data)->body)->mime_type, "image", "*"))
-			mask &= ~ E_CAL_POPUP_ATTACHMENTS_IMAGE;
-		mask &= ~ E_CAL_POPUP_ATTACHMENTS_ONE;
-	}
-
-	if (len > 1)
-		mask &= ~ E_CAL_POPUP_ATTACHMENTS_MULTIPLE;
-
-	t->target.mask = mask;
-
-	return t;
-}
-
 /* ********************************************************************** */
 /* Popup menu plugin handler */
 
diff --git a/calendar/gui/e-cal-popup.h b/calendar/gui/e-cal-popup.h
index fb899c3..34874ef 100644
--- a/calendar/gui/e-cal-popup.h
+++ b/calendar/gui/e-cal-popup.h
@@ -195,8 +195,6 @@ ECalPopup *e_cal_popup_new(const char *menuid);
 
 ECalPopupTargetSelect *e_cal_popup_target_new_select(ECalPopup *eabp, struct _ECalModel *model, GPtrArray *events);
 ECalPopupTargetSource *e_cal_popup_target_new_source(ECalPopup *eabp, struct _ESourceSelector *selector);
-ECalPopupTargetAttachments * e_cal_popup_target_new_attachments (ECalPopup *ecp,
-								CompEditor *editor, GSList *attachments);
 
 /* ********************************************************************** */
 
diff --git a/composer/e-composer-actions.c b/composer/e-composer-actions.c
index 61ad1e9..e46aba4 100644
--- a/composer/e-composer-actions.c
+++ b/composer/e-composer-actions.c
@@ -31,69 +31,13 @@ static void
 action_attach_cb (GtkAction *action,
                   EMsgComposer *composer)
 {
-	EAttachmentBar *bar;
-	GtkWidget *dialog;
-	GtkWidget *option;
-	GSList *uris, *iter;
-	const gchar *disposition;
-	gboolean active;
-	gint response;
-
-	bar = E_ATTACHMENT_BAR (composer->priv->attachment_bar);
-
-	dialog = gtk_file_chooser_dialog_new (
-		_("Insert Attachment"),
-		GTK_WINDOW (composer),
-		GTK_FILE_CHOOSER_ACTION_OPEN,
-		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-		_("A_ttach"), GTK_RESPONSE_OK,
-		NULL);
-
-	gtk_dialog_set_default_response (
-		GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-	gtk_file_chooser_set_local_only (
-		GTK_FILE_CHOOSER (dialog), FALSE);
-	gtk_file_chooser_set_select_multiple (
-		GTK_FILE_CHOOSER (dialog), TRUE);
-	gtk_window_set_icon_name (
-		GTK_WINDOW (dialog), "mail-message-new");
+	EAttachmentView *view;
+	EAttachmentStore *store;
 
-	option = gtk_check_button_new_with_mnemonic (
-		_("_Suggest automatic display of attachment"));
-	gtk_widget_show (option);
-	gtk_file_chooser_set_extra_widget (
-		GTK_FILE_CHOOSER (dialog), option);
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 
-	response = gtkhtml_editor_file_chooser_dialog_run (
-		GTKHTML_EDITOR (composer), dialog);
-
-	if (response != GTK_RESPONSE_OK)
-		goto exit;
-
-	uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
-	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
-	disposition = active ? "inline" : "attachment";
-
-	for (iter = uris; iter != NULL; iter = iter->next) {
-		CamelURL *url;
-
-		url = camel_url_new (iter->data, NULL);
-		if (url == NULL)
-			continue;
-
-		if (!g_ascii_strcasecmp (url->protocol, "file"))
-			e_attachment_bar_attach (bar, url->path, disposition);
-		else
-			e_attachment_bar_attach_remote_file (bar, iter->data, disposition);
-
-		camel_url_free (url);
-	}
-
-	g_slist_foreach (uris, (GFunc) g_free, NULL);
-	g_slist_free (uris);
-
-exit:
-	gtk_widget_destroy (dialog);
+	e_attachment_store_run_load_dialog (store, GTK_WINDOW (composer));
 }
 
 static void
diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c
index d47a372..ab1e092 100644
--- a/composer/e-composer-private.c
+++ b/composer/e-composer-private.c
@@ -49,27 +49,29 @@ composer_setup_charset_menu (EMsgComposer *composer)
 static void
 composer_setup_recent_menu (EMsgComposer *composer)
 {
+	EAttachmentView *view;
 	GtkUIManager *manager;
-	GtkAction *action = NULL;
-	const gchar *path, *action_name;
+	GtkAction *action;
+	const gchar *action_name;
+	const gchar *path;
 	guint merge_id;
 
+	view = e_msg_composer_get_attachment_view (composer);
 	manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer));
-	action_name = "recent-menu";
 	path = "/main-menu/insert-menu/insert-menu-top/recent-placeholder";
 	merge_id = gtk_ui_manager_new_merge_id (manager);
+	action_name = "recent-menu";
 
-	action = e_attachment_bar_recent_action_new (
-			e_msg_composer_get_attachment_bar (composer), 
-			action_name, _("Recent _Documents"));
+	action = e_attachment_view_recent_action_new (
+		view, action_name, _("Recent _Documents"));
 
 	if (action != NULL) {
-		gtk_action_group_add_action (composer->priv->composer_actions, action);
+		gtk_action_group_add_action (
+			composer->priv->composer_actions, action);
 
-		gtk_ui_manager_add_ui ( 
+		gtk_ui_manager_add_ui (
 			manager, merge_id, path,
-			action_name, 
-			action_name, 
+			action_name, action_name,
 			GTK_UI_MANAGER_AUTO, FALSE);
 	}
 
@@ -84,7 +86,6 @@ e_composer_private_init (EMsgComposer *composer)
 	GtkhtmlEditor *editor;
 	GtkUIManager *manager;
 	GtkWidget *widget;
-	GtkWidget *expander;
 	GtkWidget *container;
 	GtkWidget *send_widget;
 	const gchar *path;
@@ -136,6 +137,8 @@ e_composer_private_init (EMsgComposer *composer)
 
 	/* Construct the header table. */
 
+	container = editor->vbox;
+
 	widget = e_composer_header_table_new ();
 	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
 	gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
@@ -143,59 +146,23 @@ e_composer_private_init (EMsgComposer *composer)
 	priv->header_table = g_object_ref (widget);
 	gtk_widget_show (widget);
 
-	/* Construct attachment widgets.
-	 * XXX Move this stuff into a new custom widget. */
-
-	widget = gtk_expander_new (NULL);
-	gtk_expander_set_expanded (GTK_EXPANDER (widget), FALSE);
-	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
-	gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
-	priv->attachment_expander = g_object_ref (widget);
-	gtk_widget_show (widget);
-	expander = widget;
-
-	widget = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_policy (
-		GTK_SCROLLED_WINDOW (widget),
-		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (
-		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
-	gtk_container_add (GTK_CONTAINER (expander), widget);
-	priv->attachment_scrolled_window = g_object_ref (widget);
-	gtk_widget_show (widget);
-	container = widget;
-
-	widget = e_attachment_bar_new (NULL);
-	GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
-	gtk_container_add (GTK_CONTAINER (container), widget);
-	priv->attachment_bar = g_object_ref (widget);
-	gtk_widget_show (widget);
+	/* Construct the attachment paned. */
 
-	widget = gtk_hbox_new (FALSE, 0);
-	gtk_expander_set_label_widget (GTK_EXPANDER (expander), widget);
+	widget = e_attachment_paned_new ();
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	priv->attachment_paned = g_object_ref (widget);
 	gtk_widget_show (widget);
-	container = widget;
 
-	widget = gtk_label_new_with_mnemonic (_("Show _Attachment Bar"));
-	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
-	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 6);
-	priv->attachment_expander_label = g_object_ref (widget);
-	gtk_widget_show (widget);
+	/* Reparent the scrolled window containing the GtkHTML widget
+	 * into the content area of the top attachment pane. */
 
-	widget = gtk_image_new_from_icon_name (
-		"mail-attachment", GTK_ICON_SIZE_MENU);
-	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
-	gtk_widget_set_size_request (widget, 100, -1);
-	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
-	priv->attachment_expander_icon = g_object_ref (widget);
-	gtk_widget_hide (widget);
-
-	widget = gtk_label_new (NULL);
-	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
-	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
-	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 6);
-	priv->attachment_expander_num = g_object_ref (widget);
-	gtk_widget_show (widget);
+	widget = GTK_WIDGET (gtkhtml_editor_get_html (editor));
+	widget = gtk_widget_get_parent (widget);
+	container = e_attachment_paned_get_content_area (
+		E_ATTACHMENT_PANED (priv->attachment_paned));
+	gtk_widget_reparent (widget, container);
+	gtk_box_set_child_packing (
+		GTK_BOX (container), widget, TRUE, TRUE, 0, GTK_PACK_START);
 
 	composer_setup_recent_menu (composer);
 }
diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h
index ec6626e..669af31 100644
--- a/composer/e-composer-private.h
+++ b/composer/e-composer-private.h
@@ -25,11 +25,12 @@
 
 #include <camel/camel-iconv.h>
 
-#include "e-attachment-bar.h"
 #include "e-composer-actions.h"
 #include "e-composer-autosave.h"
 #include "e-composer-header-table.h"
 #include "e-util/gconf-bridge.h"
+#include "widgets/misc/e-attachment-paned.h"
+#include "widgets/misc/e-attachment-store.h"
 
 #define E_MSG_COMPOSER_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -94,6 +95,8 @@ struct _EMsgComposerPrivate {
 
 	GtkWidget *html_editor;
 	GtkWidget *header_table;
+	GtkWidget *attachment_paned;
+
 	GtkActionGroup *charset_actions;
 	GtkActionGroup *composer_actions;
 
@@ -102,13 +105,6 @@ struct _EMsgComposerPrivate {
 
 	GtkWidget *focused_entry;
 
-	GtkWidget *attachment_bar;
-	GtkWidget *attachment_scrolled_window;
-	GtkWidget *attachment_expander;
-	GtkWidget *attachment_expander_label;
-	GtkWidget *attachment_expander_icon;
-	GtkWidget *attachment_expander_num;
-
 	GtkWidget *address_dialog;
 
 	GHashTable *inline_images;
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index d39a212..a277729 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -60,7 +60,6 @@
 
 #include "e-util/e-dialog-utils.h"
 #include "misc/e-charset-picker.h"
-#include "misc/e-expander.h"
 #include "e-util/e-error.h"
 #include "e-util/e-plugin-ui.h"
 #include "e-util/e-util-private.h"
@@ -98,7 +97,6 @@
 
 #include "e-msg-composer.h"
 #include "e-attachment.h"
-#include "e-attachment-bar.h"
 #include "e-composer-autosave.h"
 #include "e-composer-private.h"
 #include "e-composer-header-table.h"
@@ -152,39 +150,6 @@ enum {
 	LAST_SIGNAL
 };
 
-enum {
-	DND_TYPE_MESSAGE_RFC822,
-	DND_TYPE_X_UID_LIST,
-	DND_TYPE_TEXT_URI_LIST,
-	DND_TYPE_NETSCAPE_URL,
-	DND_TYPE_TEXT_VCARD,
-	DND_TYPE_TEXT_CALENDAR
-};
-
-static GtkTargetEntry drop_types[] = {
-	{ "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 },
-	{ "x-uid-list",     0, DND_TYPE_X_UID_LIST },
-	{ "text/uri-list",  0, DND_TYPE_TEXT_URI_LIST },
-	{ "_NETSCAPE_URL",  0, DND_TYPE_NETSCAPE_URL },
-	{ "text/x-vcard",   0, DND_TYPE_TEXT_VCARD },
-	{ "text/calendar",  0, DND_TYPE_TEXT_CALENDAR }
-};
-
-static struct {
-	gchar *target;
-	GdkAtom atom;
-	guint32 actions;
-} drag_info[] = {
-	{ "message/rfc822", NULL, GDK_ACTION_COPY },
-	{ "x-uid-list",     NULL, GDK_ACTION_ASK |
-                                  GDK_ACTION_MOVE |
-                                  GDK_ACTION_COPY },
-	{ "text/uri-list",  NULL, GDK_ACTION_COPY },
-	{ "_NETSCAPE_URL",  NULL, GDK_ACTION_COPY },
-	{ "text/x-vcard",   NULL, GDK_ACTION_COPY },
-	{ "text/calendar",  NULL, GDK_ACTION_COPY }
-};
-
 static gpointer parent_class;
 static guint signals[LAST_SIGNAL];
 
@@ -195,7 +160,6 @@ static GSList *all_composers = NULL;
 static GList *add_recipients (GList *list, const gchar *recips);
 
 static void handle_mailto (EMsgComposer *composer, const gchar *mailto);
-static void handle_uri    (EMsgComposer *composer, const gchar *uri, gboolean html_dnd);
 
 /* used by e_msg_composer_add_message_attachments () */
 static void add_attachments_from_multipart (EMsgComposer *composer, CamelMultipart *multipart,
@@ -527,7 +491,8 @@ build_message (EMsgComposer *composer,
 	GtkhtmlEditor *editor;
 	EMsgComposerPrivate *p = composer->priv;
 
-	EAttachmentBar *attachment_bar;
+	EAttachmentView *view;
+	EAttachmentStore *store;
 	EComposerHeaderTable *table;
 	GtkToggleAction *action;
 	CamelDataWrapper *plain, *html, *current;
@@ -554,7 +519,8 @@ build_message (EMsgComposer *composer,
 	editor = GTKHTML_EDITOR (composer);
 	table = e_msg_composer_get_header_table (composer);
 	account = e_composer_header_table_get_account (table);
-	attachment_bar = E_ATTACHMENT_BAR (p->attachment_bar);
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 
 	/* evil kludgy hack for Redirect */
 	if (p->redirect) {
@@ -714,7 +680,7 @@ build_message (EMsgComposer *composer,
 	} else
 		current = plain;
 
-	if (e_attachment_bar_get_num_attachments (attachment_bar)) {
+	if (e_attachment_store_get_num_attachments (store) > 0) {
 		CamelMultipart *multipart = camel_multipart_new ();
 
 		if (p->is_alternative) {
@@ -733,7 +699,8 @@ build_message (EMsgComposer *composer,
 		camel_multipart_add_part (multipart, part);
 		camel_object_unref (part);
 
-		e_attachment_bar_to_multipart (attachment_bar, multipart, p->charset);
+		e_attachment_store_add_to_multipart (
+			store, multipart, p->charset);
 
 		if (p->is_alternative) {
 			for (i = camel_multipart_get_number (multipart); i > 1; i--) {
@@ -976,107 +943,6 @@ skip_content:
 	return NULL;
 }
 
-/* Attachment Bar */
-
-static void
-emcab_add (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	GtkWidget *widget = data;
-	GtkWidget *composer;
-
-	composer = gtk_widget_get_toplevel (widget);
-	gtk_action_activate (ACTION (ATTACH));
-}
-
-static void
-emcab_properties (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	EAttachmentBar *attachment_bar = data;
-
-	e_attachment_bar_edit_selected (attachment_bar);
-}
-
-static void
-emcab_remove (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	EAttachmentBar *attachment_bar = data;
-
-	e_attachment_bar_remove_selected (attachment_bar);
-}
-
-static void
-emcab_popup_position (GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
-{
-	GtkWidget *widget = user_data;
-	GnomeIconList *icon_list = user_data;
-	GList *selection;
-	GnomeCanvasPixbuf *image;
-
-	gdk_window_get_origin (widget->window, x, y);
-
-	selection = gnome_icon_list_get_selection (icon_list);
-	if (selection == NULL)
-		return;
-
-	image = gnome_icon_list_get_icon_pixbuf_item (
-		icon_list, GPOINTER_TO_INT(selection->data));
-	if (image == NULL)
-		return;
-
-	/* Put menu to the center of icon. */
-	*x += (int)(image->item.x1 + image->item.x2) / 2;
-	*y += (int)(image->item.y1 + image->item.y2) / 2;
-}
-
-static void
-emcab_popups_free (EPopup *ep, GSList *list, gpointer data)
-{
-	g_slist_free (list);
-}
-
-/* Popup menu handling.  */
-static EPopupItem emcab_popups[] = {
-	{ E_POPUP_ITEM, "10.attach", N_("_Remove"), emcab_remove, NULL, GTK_STOCK_REMOVE, EM_POPUP_ATTACHMENTS_MANY },
-	{ E_POPUP_ITEM, "20.attach", N_("_Properties"), emcab_properties, NULL, GTK_STOCK_PROPERTIES, EM_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_BAR, "30.attach.00", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MANY|EM_POPUP_ATTACHMENTS_ONE },
-	{ E_POPUP_ITEM, "30.attach.01", N_("_Add attachment..."), emcab_add, NULL, GTK_STOCK_ADD, 0 },
-};
-
-/* if id != -1, then use it as an index for target of the popup */
-
-static void
-emcab_popup (EAttachmentBar *bar, GdkEventButton *event, int id)
-{
-	GSList *attachments = NULL, *menus = NULL;
-	int i;
-	EMPopup *emp;
-	EMPopupTargetAttachments *t;
-	GtkMenu *menu;
-
-	attachments = e_attachment_bar_get_attachment (bar, id);
-
-	for (i=0;i<sizeof (emcab_popups)/sizeof (emcab_popups[0]);i++)
-		menus = g_slist_prepend (menus, &emcab_popups[i]);
-
-	/** @HookPoint-EMPopup: Composer Attachment Bar Context Menu
-	 * @Id: org.gnome.evolution.mail.composer.attachmentbar.popup
-	 * @Class: org.gnome.evolution.mail.popup:1.0
-	 * @Target: EMPopupTargetAttachments
-	 *
-	 * This is the context menu on the composer attachment bar.
-	 */
-	emp = em_popup_new ("org.gnome.evolution.mail.composer.attachmentbar.popup");
-	e_popup_add_items ((EPopup *)emp, menus, NULL, emcab_popups_free, bar);
-	t = em_popup_target_new_attachments (emp, attachments);
-	t->target.widget = (GtkWidget *)bar;
-	menu = e_popup_create_menu_once ((EPopup *)emp, (EPopupTarget *)t, 0);
-
-	if (event == NULL)
-		gtk_menu_popup (menu, NULL, NULL, emcab_popup_position, bar, 0, gtk_get_current_event_time ());
-	else
-		gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time);
-}
-
 /* Signatures */
 
 static gchar *
@@ -1467,108 +1333,17 @@ autosave_load_draft (const gchar *filename)
 
 /* Miscellaneous callbacks.  */
 
-static gint
-attachment_bar_button_press_event_cb (EAttachmentBar *attachment_bar,
-                                      GdkEventButton *event)
-{
-	GnomeIconList *icon_list;
-	gint icon_number;
-
-	if (event->button != 3)
-		return FALSE;
-
-	icon_list = GNOME_ICON_LIST (attachment_bar);
-	icon_number = gnome_icon_list_get_icon_at (
-		icon_list, event->x, event->y);
-	if (icon_number >= 0) {
-		gnome_icon_list_unselect_all (icon_list);
-		gnome_icon_list_select_icon (icon_list, icon_number);
-	}
-
-	emcab_popup (attachment_bar, event, icon_number);
-
-	return TRUE;
-}
-
 static void
-attachment_bar_changed_cb (EAttachmentBar *attachment_bar,
-                           EMsgComposer *composer)
+attachment_store_changed_cb (EMsgComposer *composer)
 {
 	GtkhtmlEditor *editor;
-	GtkWidget *widget;
-	guint attachment_num;
-
-	editor = GTKHTML_EDITOR (composer);
-	attachment_num = e_attachment_bar_get_num_attachments (attachment_bar);
-
-	if (attachment_num > 0) {
-		gchar *markup;
-
-		markup = g_strdup_printf (
-			"<b>%d</b> %s", attachment_num, ngettext (
-			"Attachment", "Attachments", attachment_num));
-		widget = composer->priv->attachment_expander_num;
-		gtk_label_set_markup (GTK_LABEL (widget), markup);
-		g_free (markup);
-
-		gtk_widget_show (composer->priv->attachment_expander_icon);
-
-		widget = composer->priv->attachment_expander;
-		gtk_expander_set_expanded (GTK_EXPANDER (widget), TRUE);
-	} else {
-		widget = composer->priv->attachment_expander_num;
-		gtk_label_set_text (GTK_LABEL (widget), "");
-
-		gtk_widget_hide (composer->priv->attachment_expander_icon);
-
-		widget = composer->priv->attachment_expander;
-		gtk_expander_set_expanded (GTK_EXPANDER (widget), FALSE);
-	}
 
 	/* Mark the editor as changed so it prompts about unsaved
-	   changes on close. */
+	 * changes on close. */
+	editor = GTKHTML_EDITOR (composer);
 	gtkhtml_editor_set_changed (editor, TRUE);
 }
 
-static gint
-attachment_bar_key_press_event_cb (EAttachmentBar *attachment_bar,
-                                   GdkEventKey *event)
-{
-	if (event->keyval == GDK_Delete) {
-		e_attachment_bar_remove_selected (attachment_bar);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-static gboolean
-attachment_bar_popup_menu_cb (EAttachmentBar *attachment_bar)
-{
-	emcab_popup (attachment_bar, NULL, -1);
-
-	return TRUE;
-}
-
-static void
-attachment_expander_notify_cb (GtkExpander *expander,
-                               GParamSpec *pspec,
-                               EMsgComposer *composer)
-{
-	GtkLabel *label;
-	const gchar *text;
-
-	label = GTK_LABEL (composer->priv->attachment_expander_label);
-
-	/* Update the expander label */
-	if (gtk_expander_get_expanded (expander))
-		text = _("Hide _Attachment Bar");
-	else
-		text = _("Show _Attachment Bar");
-
-	gtk_label_set_text_with_mnemonic (label, text);
-}
-
 static void
 msg_composer_subject_changed_cb (EMsgComposer *composer)
 {
@@ -1765,35 +1540,6 @@ msg_composer_account_list_changed_cb (EMsgComposer *composer)
 }
 
 static void
-msg_composer_attach_message (EMsgComposer *composer,
-                             CamelMimeMessage *msg)
-{
-	CamelMimePart *mime_part;
-	GString *description;
-	const gchar *subject;
-	EMsgComposerPrivate *p = composer->priv;
-
-	mime_part = camel_mime_part_new ();
-	camel_mime_part_set_disposition (mime_part, "inline");
-	subject = camel_mime_message_get_subject (msg);
-
-	description = g_string_new (_("Attached message"));
-	if (subject != NULL)
-		g_string_append_printf (description, " - %s", subject);
-	camel_mime_part_set_description (mime_part, description->str);
-	g_string_free (description, TRUE);
-
-	camel_medium_set_content_object (
-		(CamelMedium *) mime_part, (CamelDataWrapper *) msg);
-	camel_mime_part_set_content_type (mime_part, "message/rfc822");
-
-	e_attachment_bar_attach_mime_part (
-		E_ATTACHMENT_BAR (p->attachment_bar), mime_part);
-
-	camel_object_unref (mime_part);
-}
-
-static void
 msg_composer_update_preferences (GConfClient *client,
                                  guint cnxn_id,
                                  GConfEntry *entry,
@@ -1849,17 +1595,7 @@ struct _drop_data {
 	unsigned int aborted:1;
 };
 
-int
-e_msg_composer_get_remote_download_count (EMsgComposer *composer)
-{
-	EAttachmentBar *attachment_bar;
-
-	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), 0);
-
-	attachment_bar = E_ATTACHMENT_BAR (composer->priv->attachment_bar);
-	return e_attachment_bar_get_download_count (attachment_bar);
-}
-
+#if 0  /* FIXME */
 static void
 drop_action (EMsgComposer *composer,
              GdkDragContext *context,
@@ -2033,55 +1769,7 @@ drop_action (EMsgComposer *composer,
 
 	gtk_drag_finish (context, success, delete, time);
 }
-
-static void
-drop_popup_copy (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	struct _drop_data *m = data;
-
-	drop_action (
-		m->composer, m->context, GDK_ACTION_COPY,
-		m->selection, m->info, m->time, FALSE);
-}
-
-static void
-drop_popup_move (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	struct _drop_data *m = data;
-
-	drop_action (
-		m->composer, m->context, GDK_ACTION_MOVE,
-		m->selection, m->info, m->time, FALSE);
-}
-
-static void
-drop_popup_cancel (EPopup *ep, EPopupItem *item, gpointer data)
-{
-	struct _drop_data *m = data;
-
-	gtk_drag_finish (m->context, FALSE, FALSE, m->time);
-}
-
-static EPopupItem drop_popup_menu[] = {
-	{ E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "mail-copy", 0 },
-	{ E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "mail-move", 0 },
-	{ E_POPUP_BAR, "10.emc" },
-	{ E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
-};
-
-static void
-drop_popup_free (EPopup *ep, GSList *items, gpointer data)
-{
-	struct _drop_data *m = data;
-
-	g_slist_free (items);
-
-	g_object_unref (m->context);
-	g_object_unref (m->composer);
-	g_free (m->selection->data);
-	g_free (m->selection);
-	g_free (m);
-}
+#endif
 
 static void
 msg_composer_notify_header_cb (EMsgComposer *composer)
@@ -2341,33 +2029,14 @@ msg_composer_drag_motion (GtkWidget *widget,
                           gint y,
                           guint time)
 {
-	GList *targets;
-	GdkDragAction actions = 0;
-	GdkDragAction chosen_action;
-
-	targets = context->targets;
-	while (targets != NULL) {
-		gint ii;
-
-		for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++)
-			if (targets->data == (gpointer) drag_info[ii].atom)
-				actions |= drag_info[ii].actions;
-
-		targets = g_list_next (targets);
-	}
-
-	actions &= context->actions;
-	chosen_action = context->suggested_action;
-
-	/* we default to copy */
-	if (chosen_action == GDK_ACTION_ASK &&
-		(actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) !=
-		(GDK_ACTION_MOVE|GDK_ACTION_COPY))
-		chosen_action = GDK_ACTION_COPY;
+	EMsgComposer *composer;
+	EAttachmentView *view;
 
-	gdk_drag_status (context, chosen_action, time);
+	/* Widget may be EMsgComposer or GtkHTML. */
+	composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
+	view = e_msg_composer_get_attachment_view (composer);
 
-	return (chosen_action != 0);
+	return e_attachment_view_drag_motion (view, context, x, y, time);
 }
 
 static void
@@ -2380,46 +2049,19 @@ msg_composer_drag_data_received (GtkWidget *widget,
                                  guint time)
 {
 	EMsgComposer *composer;
+	EAttachmentView *view;
 
 	/* Widget may be EMsgComposer or GtkHTML. */
 	composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
-
-	if (selection->data == NULL)
-		return;
-
-	if (selection->length == -1)
-		return;
-
-	if (context->action == GDK_ACTION_ASK) {
-		EMPopup *emp;
-		GSList *menus = NULL;
-		GtkMenu *menu;
-		gint ii;
-		struct _drop_data *m;
-
-		m = g_malloc0(sizeof (*m));
-		m->context = g_object_ref (context);
-		m->composer = g_object_ref (composer);
-		m->action = context->action;
-		m->info = info;
-		m->time = time;
-		m->selection = g_malloc0(sizeof (*m->selection));
-		m->selection->data = g_malloc (selection->length);
-		memcpy (m->selection->data, selection->data, selection->length);
-		m->selection->length = selection->length;
-
-		emp = em_popup_new ("org.gnome.evolution.mail.composer.popup.drop");
-		for (ii = 0; ii < G_N_ELEMENTS (drop_popup_menu); ii++)
-			menus = g_slist_append (menus, &drop_popup_menu[ii]);
-
-		e_popup_add_items ((EPopup *)emp, menus, NULL, drop_popup_free, m);
-		menu = e_popup_create_menu_once ((EPopup *)emp, NULL, 0);
-		gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, time);
-	} else {
-		drop_action (
-			composer, context, context->action, selection,
-			info, time, !GTK_WIDGET_TOPLEVEL (widget));
-	}
+	view = e_msg_composer_get_attachment_view (composer);
+
+	/* Forward the data to the attachment view.  Note that calling
+	 * e_attachment_view_drag_data_received() will not work because
+	 * that function only handles the case where all the other drag
+	 * handlers have failed. */
+	e_attachment_paned_drag_data_received (
+		E_ATTACHMENT_PANED (view),
+		context, x, y, selection, info, time);
 }
 
 static void
@@ -2466,11 +2108,20 @@ static void
 msg_composer_paste_clipboard (GtkhtmlEditor *editor)
 {
 	EMsgComposer *composer;
+	EAttachmentView *view;
+	EAttachmentStore *store;
+	GtkClipboard *clipboard;
+	GdkPixbuf *pixbuf;
 	GtkWidget *parent;
 	GtkWidget *widget;
-	GtkClipboard *clipboard;
+	gchar *filename;
+	gchar *uri;
+	GError *error = NULL;
 
 	composer = E_MSG_COMPOSER (editor);
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
+
 	widget = gtk_window_get_focus (GTK_WINDOW (editor));
 	parent = gtk_widget_get_parent (widget);
 
@@ -2480,36 +2131,63 @@ msg_composer_paste_clipboard (GtkhtmlEditor *editor)
 	}
 
 	clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
-	if (clipboard && gtk_clipboard_wait_is_image_available (clipboard)) {
-		GdkPixbuf *pixbuf;
-
-		pixbuf = gtk_clipboard_wait_for_image (clipboard);
-		if (pixbuf) {
-			char *tmpl = g_strconcat (_("Image"), "-XXXXXX", NULL);
-			char *filename = e_mktemp (tmpl);
-
-			g_free (tmpl);
-
-			if (filename && gdk_pixbuf_save (pixbuf, filename, "png", NULL, NULL)) {
-				if (gtkhtml_editor_get_html_mode (editor)) {
-					char *uri = g_strconcat ("file://", filename, NULL);
-					/* this loads image async, thus cannot remove file from this */
-					gtkhtml_editor_insert_image (editor, uri);
-					g_free (uri);
-				} else {
-					/* this loads image immediately, remove file from cache to free up disk space */
-					e_attachment_bar_attach (E_ATTACHMENT_BAR (composer->priv->attachment_bar), filename, "image/png");
-					g_remove (filename);
-				}
-			}
 
-			g_free (filename);
-			g_object_unref (pixbuf);
-		}
-	} else {
-		/* Chain up to parent's paste_clipboard() method. */
-		GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor);
+	/* Assume the clipboard has an image.  The return
+	 * value will be NULL we we assumed wrong. */
+	pixbuf = gtk_clipboard_wait_for_image (clipboard);
+	if (!GDK_IS_PIXBUF (pixbuf))
+		goto chainup;
+
+	/* Reserve a temporary file. */
+	filename = e_mktemp (NULL);
+	if (filename == NULL) {
+		g_warning ("%s", g_strerror (errno));
+		g_object_unref (pixbuf);
+		g_error_free (error);
+		return;
+	}
+
+	/* Save the pixbuf as a temporary file in image/png format. */
+	if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL)) {
+		g_warning ("%s", error->message);
+		g_object_unref (pixbuf);
+		g_error_free (error);
+		g_free (filename);
+		return;
+	}
+
+	/* Convert the filename to a URI. */
+	uri = g_filename_to_uri (filename, NULL, &error);
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_object_unref (pixbuf);
+		g_error_free (error);
+		g_free (filename);
+		return;
 	}
+
+	if (gtkhtml_editor_get_html_mode (editor))
+		gtkhtml_editor_insert_image (editor, uri);
+	else {
+		EAttachment *attachment;
+
+		attachment = e_attachment_new_for_uri (uri);
+		e_attachment_store_add_attachment (store, attachment);
+		e_attachment_load_async (
+			attachment, (GAsyncReadyCallback)
+			e_attachment_load_handle_error, composer);
+		g_object_unref (attachment);
+	}
+
+	g_object_unref (pixbuf);
+	g_free (filename);
+	g_free (uri);
+
+	return;
+
+chainup:
+	/* Chain up to parent's paste_clipboard() method. */
+	GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor);
 }
 
 static void
@@ -2733,11 +2411,6 @@ msg_composer_class_init (EMsgComposerClass *class)
 	GtkObjectClass *gtk_object_class;
 	GtkWidgetClass *widget_class;
 	GtkhtmlEditorClass *editor_class;
-	gint ii;
-
-	for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++)
-		drag_info[ii].atom =
-			gdk_atom_intern (drag_info[ii].target, FALSE);
 
 	parent_class = g_type_class_peek_parent (class);
 	g_type_class_add_private (class, sizeof (EMsgComposerPrivate));
@@ -2789,10 +2462,16 @@ msg_composer_class_init (EMsgComposerClass *class)
 static void
 msg_composer_init (EMsgComposer *composer)
 {
+	EAttachmentView *view;
+	EAttachmentStore *store;
 	EComposerHeaderTable *table;
+	GdkDragAction drag_actions;
+	GtkTargetList *target_list;
+	GtkTargetEntry *targets;
 	GtkUIManager *manager;
 	GtkhtmlEditor *editor;
 	GtkHTML *html;
+	gint n_targets;
 
 	composer->priv = E_MSG_COMPOSER_GET_PRIVATE (composer);
 
@@ -2801,6 +2480,7 @@ msg_composer_init (EMsgComposer *composer)
 	editor = GTKHTML_EDITOR (composer);
 	html = gtkhtml_editor_get_html (editor);
 	manager = gtkhtml_editor_get_ui_manager (editor);
+	view = e_msg_composer_get_attachment_view (composer);
 	all_composers = g_slist_prepend (all_composers, composer);
 	table = E_COMPOSER_HEADER_TABLE (composer->priv->header_table);
 
@@ -2809,36 +2489,21 @@ msg_composer_init (EMsgComposer *composer)
 
 	/* Drag-and-Drop Support */
 
-	gtk_drag_dest_set (
-		GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL,
-		drop_types, G_N_ELEMENTS (drop_types),
-		GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE);
+	target_list = e_attachment_view_get_target_list (view);
+	drag_actions = e_attachment_view_get_drag_actions (view);
 
-	/* XXX I'm not sure why we have to explicitly configure the
-	 *     attachment bar as a drag destination when CompEditor
-	 *     doesn't and previous Evolution releases (2.22 and
-	 *     prior) don't, but this is the only way I could figure
-	 *     out how to get drag-and-drop to the attachment bar
-	 *     working again.  I'm probably overlooking something
-	 *     simple... */
+	targets = gtk_target_table_new_from_list (target_list, &n_targets);
 
 	gtk_drag_dest_set (
-		composer->priv->attachment_bar, GTK_DEST_DEFAULT_ALL,
-		drop_types, G_N_ELEMENTS (drop_types),
-		GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE);
-
-	g_signal_connect (
-		composer->priv->attachment_bar, "drag-motion",
-		G_CALLBACK (msg_composer_drag_motion), NULL);
-
-	g_signal_connect (
-		composer->priv->attachment_bar, "drag-data-received",
-		G_CALLBACK (msg_composer_drag_data_received), NULL);
+		GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL,
+		targets, n_targets, drag_actions);
 
 	g_signal_connect (
 		html, "drag-data-received",
 		G_CALLBACK (msg_composer_drag_data_received), NULL);
 
+	gtk_target_table_free (targets, n_targets);
+
 	/* Configure Headers */
 
 	e_composer_header_table_set_account_list (
@@ -2877,23 +2542,17 @@ msg_composer_init (EMsgComposer *composer)
 	msg_composer_account_changed_cb (composer);
 	msg_composer_account_list_changed_cb (composer);
 
-	/* Attachment Bar */
+	/* Attachments */
 
-	g_signal_connect (
-		composer->priv->attachment_bar, "button_press_event",
-		G_CALLBACK (attachment_bar_button_press_event_cb), NULL);
-	g_signal_connect (
-		composer->priv->attachment_bar, "key_press_event",
-		G_CALLBACK (attachment_bar_key_press_event_cb), NULL);
-	g_signal_connect (
-		composer->priv->attachment_bar, "popup-menu",
-		G_CALLBACK (attachment_bar_popup_menu_cb), NULL);
-	g_signal_connect (
-		composer->priv->attachment_bar, "changed",
-		G_CALLBACK (attachment_bar_changed_cb), composer);
-	g_signal_connect_after (
-		composer->priv->attachment_expander, "notify::expanded",
-		G_CALLBACK (attachment_expander_notify_cb), composer);
+	store = e_attachment_view_get_store (view);
+
+	g_signal_connect_swapped (
+		store, "row-deleted",
+		G_CALLBACK (attachment_store_changed_cb), composer);
+
+	g_signal_connect_swapped (
+		store, "row-inserted",
+		G_CALLBACK (attachment_store_changed_cb), composer);
 
 	e_composer_autosave_register (composer);
 
@@ -3738,7 +3397,7 @@ disable_editor (EMsgComposer *composer)
 	action = GTKHTML_EDITOR_ACTION_INSERT_MENU (composer);
 	gtk_action_set_sensitive (action, FALSE);
 
-	gtk_widget_set_sensitive (composer->priv->attachment_bar, FALSE);
+	gtk_widget_set_sensitive (composer->priv->attachment_paned, FALSE);
 }
 
 /**
@@ -3837,7 +3496,8 @@ add_recipients (GList *list, const gchar *recips)
 static void
 handle_mailto (EMsgComposer *composer, const gchar *mailto)
 {
-	EMsgComposerPrivate *priv = composer->priv;
+	EAttachmentView *view;
+	EAttachmentStore *store;
 	EComposerHeaderTable *table;
 	GList *to = NULL, *cc = NULL, *bcc = NULL;
 	EDestination **tov, **ccv, **bccv;
@@ -3846,9 +3506,10 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto)
 	gsize nread, nwritten;
 	const gchar *p;
 	gint len, clen;
-	CamelURL *url;
 
 	table = e_msg_composer_get_header_table (composer);
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 
 	buf = g_strdup (mailto);
 
@@ -3920,20 +3581,18 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto)
 				}
 			} else if (!g_ascii_strcasecmp (header, "attach") ||
 				   !g_ascii_strcasecmp (header, "attachment")) {
-				/* Change file url to absolute path */
-				if (!g_ascii_strncasecmp (content, "file:", 5)) {
-					url = camel_url_new (content, NULL);
-					e_attachment_bar_attach (E_ATTACHMENT_BAR (priv->attachment_bar),
-							 	 url->path,
-								 "attachment");
-					camel_url_free (url);
-				} else {
-					e_attachment_bar_attach (E_ATTACHMENT_BAR (priv->attachment_bar),
-								 content,
-								 "attachment");
-				}
-				gtk_widget_show (priv->attachment_expander);
-				gtk_widget_show (priv->attachment_scrolled_window);
+				EAttachment *attachment;
+
+				camel_url_decode (content);
+				if (g_ascii_strncasecmp (content, "file:", 5) == 0)
+					attachment = e_attachment_new_for_uri (content);
+				else
+					attachment = e_attachment_new_for_path (content);
+				e_attachment_store_add_attachment (store, attachment);
+				e_attachment_load_async (
+					attachment, (GAsyncReadyCallback)
+					e_attachment_load_handle_error, composer);
+				g_object_unref (attachment);
 			} else if (!g_ascii_strcasecmp (header, "from")) {
 				/* Ignore */
 			} else if (!g_ascii_strcasecmp (header, "reply-to")) {
@@ -3985,45 +3644,6 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto)
 	}
 }
 
-static void
-handle_uri (EMsgComposer *composer,
-            const gchar *uri,
-            gboolean html_dnd)
-{
-	EMsgComposerPrivate *p = composer->priv;
-	GtkhtmlEditor *editor;
-	gboolean html_content;
-
-	editor = GTKHTML_EDITOR (composer);
-	html_content = gtkhtml_editor_get_html_mode (editor);
-
-	if (!g_ascii_strncasecmp (uri, "mailto:";, 7)) {
-		handle_mailto (composer, uri);
-	} else {
-		CamelURL *url = camel_url_new (uri, NULL);
-		gchar *type;
-
-		if (!url)
-			return;
-
-		if (!g_ascii_strcasecmp (url->protocol, "file")) {
-			type = e_util_guess_mime_type (uri + strlen ("file://"), TRUE);
-			if (!type)
-				return;
-
-			if (strncmp (type, "image", 5) || !html_dnd || (!html_content && !strncmp (type, "image", 5))) {
-				e_attachment_bar_attach (E_ATTACHMENT_BAR (p->attachment_bar),
-						url->path, "attachment");
-			}
-			g_free (type);
-		} else	{
-			e_attachment_bar_attach_remote_file (E_ATTACHMENT_BAR (p->attachment_bar),
-					uri, "attachment");
-		}
-		camel_url_free (url);
-	}
-}
-
 /**
  * e_msg_composer_new_from_url:
  * @url: a mailto URL
@@ -4187,21 +3807,31 @@ e_msg_composer_remove_header (EMsgComposer *composer,
 /**
  * e_msg_composer_attach:
  * @composer: a composer object
- * @attachment: the CamelMimePart to attach
+ * @mime_part: the #CamelMimePart to attach
  *
  * Attaches @attachment to the message being composed in the composer.
  **/
 void
-e_msg_composer_attach (EMsgComposer *composer, CamelMimePart *attachment)
+e_msg_composer_attach (EMsgComposer *composer,
+                       CamelMimePart *mime_part)
 {
-	EAttachmentBar *bar;
-	EMsgComposerPrivate *p = composer->priv;
+	EAttachmentView *view;
+	EAttachmentStore *store;
+	EAttachment *attachment;
 
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
-	g_return_if_fail (CAMEL_IS_MIME_PART (attachment));
-
-	bar = E_ATTACHMENT_BAR (p->attachment_bar);
-	e_attachment_bar_attach_mime_part (bar, attachment);
+	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
+
+	attachment = e_attachment_new ();
+	e_attachment_set_mime_part (attachment, mime_part);
+	e_attachment_store_add_attachment (store, attachment);
+	e_attachment_load_async (
+		attachment, (GAsyncReadyCallback)
+		e_attachment_load_handle_error, composer);
+	g_object_unref (attachment);
 }
 
 /**
@@ -4315,12 +3945,17 @@ CamelMimeMessage *
 e_msg_composer_get_message (EMsgComposer *composer,
                             gboolean save_html_object_data)
 {
+	EAttachmentView *view;
+	EAttachmentStore *store;
 	GtkhtmlEditor *editor;
 	gboolean html_content;
 
 	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
 
-	if (e_msg_composer_get_remote_download_count (composer) != 0) {
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
+
+	if (e_attachment_store_get_num_loading (store) > 0) {
 		if (!em_utils_prompt_user (GTK_WINDOW (composer), NULL,
 			"mail-composer:ask-send-message-pending-download", NULL)) {
 			return NULL;
@@ -4623,14 +4258,6 @@ e_msg_composer_get_raw_message_text (EMsgComposer *composer)
 	return array;
 }
 
-EAttachmentBar *
-e_msg_composer_get_attachment_bar (EMsgComposer *composer)
-{
-	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
-
-	return E_ATTACHMENT_BAR (composer->priv->attachment_bar);
-}
-
 void
 e_msg_composer_set_enable_autosave (EMsgComposer *composer,
                                     gboolean enabled)
@@ -4794,6 +4421,14 @@ e_msg_composer_get_header_table (EMsgComposer *composer)
 	return E_COMPOSER_HEADER_TABLE (composer->priv->header_table);
 }
 
+EAttachmentView *
+e_msg_composer_get_attachment_view (EMsgComposer *composer)
+{
+	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
+
+	return E_ATTACHMENT_VIEW (composer->priv->attachment_paned);
+}
+
 void
 e_msg_composer_set_send_options (EMsgComposer *composer,
                                  gboolean send_enable)
diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h
index f6b2ca7..54520ec 100644
--- a/composer/e-msg-composer.h
+++ b/composer/e-msg-composer.h
@@ -28,6 +28,7 @@
 #include <libedataserver/e-account.h>
 #include <libebook/e-destination.h>
 #include <gtkhtml-editor.h>
+#include <widgets/misc/e-attachment-view.h>
 
 #include "e-composer-header-table.h"
 
@@ -100,7 +101,7 @@ void		e_msg_composer_modify_header	(EMsgComposer *composer,
 void		e_msg_composer_remove_header	(EMsgComposer *composer,
 						 const gchar *name);
 void		e_msg_composer_attach		(EMsgComposer *composer,
-						 CamelMimePart *attachment);
+						 CamelMimePart *mime_part);
 CamelMimePart *	e_msg_composer_add_inline_image_from_file
 						(EMsgComposer *composer,
 						 const gchar *filename);
@@ -139,22 +140,19 @@ void		e_msg_composer_add_message_attachments
 gboolean	e_msg_composer_request_close_all(void);
 EMsgComposer *	e_msg_composer_load_from_file	(const gchar *filename);
 void		e_msg_composer_check_autosave	(GtkWindow *parent);
-gint		e_msg_composer_get_remote_download_count
-						(EMsgComposer *composer);
 
 void		e_msg_composer_reply_indent	(EMsgComposer *composer);
 
 EComposerHeaderTable *
 		e_msg_composer_get_header_table	(EMsgComposer *composer);
+EAttachmentView *
+		e_msg_composer_get_attachment_view
+						(EMsgComposer *composer);
 void		e_msg_composer_set_send_options	(EMsgComposer *composer,
 						 gboolean send_enable);
 GByteArray *	e_msg_composer_get_raw_message_text
 						(EMsgComposer *composer);
 
-struct _EAttachmentBar *
-		e_msg_composer_get_attachment_bar
-						(EMsgComposer *composer);
-
 gboolean	e_msg_composer_is_exiting	(EMsgComposer *composer);
 
 GList *		e_load_spell_languages		(void);
diff --git a/configure.in b/configure.in
index 462a4e7..2595606 100644
--- a/configure.in
+++ b/configure.in
@@ -1775,12 +1775,12 @@ plugins_base_always="calendar-file calendar-http $CALENDAR_WEATHER itip-formatte
 plugins_base="$plugins_base_always $SA_JUNK_PLUGIN $BF_JUNK_PLUGIN $EXCHANGE_PLUGIN $MONO_PLUGIN " 
 all_plugins_base="$plugins_base_always sa-junk-plugin bogo-junk-plugin exchange-operations mono"
 
-plugins_standard_always="bbdb subject-thread save-calendar select-one-source copy-tool mail-to-task audio-inline mailing-list-actions default-mailer import-ics-attachments prefer-plain mail-notification attachment-reminder face backup-restore email-custom-header templates pst-import" 
+plugins_standard_always="bbdb subject-thread save-calendar select-one-source copy-tool mail-to-task audio-inline mailing-list-actions default-mailer prefer-plain mail-notification attachment-reminder face backup-restore email-custom-header templates pst-import" 
 
 plugins_standard="$plugins_standard_always"
 all_plugins_standard="$plugins_standard"
 
-plugins_experimental_always="folder-unsubscribe save-attachments external-editor hula-account-setup"
+plugins_experimental_always="folder-unsubscribe external-editor hula-account-setup"
 plugins_experimental="$plugins_experimental_always $IPOD_SYNC $TNEF_ATTACHMENTS $PYTHON_PLUGIN"
 all_plugins_experimental="$plugins_experimental_always ipod-sync tnef-attachments"
 
@@ -2080,7 +2080,6 @@ plugins/mail-notification/Makefile
 plugins/mail-to-task/Makefile
 plugins/mono/Makefile
 plugins/subject-thread/Makefile
-plugins/save-attachments/Makefile
 plugins/save-calendar/Makefile
 plugins/select-one-source/Makefile
 plugins/prefer-plain/Makefile
@@ -2105,7 +2104,6 @@ plugins/sa-junk-plugin/Makefile
 plugins/bogo-junk-plugin/Makefile
 plugins/ipod-sync/Makefile
 plugins/publish-calendar/Makefile
-plugins/import-ics-attachments/Makefile
 plugins/imap-features/Makefile
 plugins/tnef-attachments/Makefile
 plugins/templates/Makefile
diff --git a/e-util/e-util.c b/e-util/e-util.c
index 0b28404..c012b26 100644
--- a/e-util/e-util.c
+++ b/e-util/e-util.c
@@ -186,6 +186,183 @@ exit:
 }
 
 /**
+ * e_lookup_action:
+ * @ui_manager: a #GtkUIManager
+ * @action_name: the name of an action
+ *
+ * Returns the first #GtkAction named @action_name by traversing the
+ * list of action groups in @ui_manager.  If no such action exists, the
+ * function emits a critical warning before returning %NULL, since this
+ * probably indicates a programming error and most code is not prepared
+ * to deal with lookup failures.
+ *
+ * Returns: the first #GtkAction named @action_name
+ **/
+GtkAction *
+e_lookup_action (GtkUIManager *ui_manager,
+                 const gchar *action_name)
+{
+	GtkAction *action = NULL;
+	GList *iter;
+
+	g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL);
+	g_return_val_if_fail (action_name != NULL, NULL);
+
+	iter = gtk_ui_manager_get_action_groups (ui_manager);
+
+	while (iter != NULL) {
+		GtkActionGroup *action_group = iter->data;
+
+		action = gtk_action_group_get_action (
+			action_group, action_name);
+		if (action != NULL)
+			return action;
+
+		iter = g_list_next (iter);
+	}
+
+	g_critical ("%s: action `%s' not found", G_STRFUNC, action_name);
+
+	return NULL;
+}
+
+/**
+ * e_lookup_action_group:
+ * @ui_manager: a #GtkUIManager
+ * @group_name: the name of an action group
+ *
+ * Returns the #GtkActionGroup in @ui_manager named @group_name.  If no
+ * such action group exists, the function emits a critical warnings before
+ * returning %NULL, since this probably indicates a programming error and
+ * most code is not prepared to deal with lookup failures.
+ *
+ * Returns: the #GtkActionGroup named @group_name
+ **/
+GtkActionGroup *
+e_lookup_action_group (GtkUIManager *ui_manager,
+                       const gchar *group_name)
+{
+	GList *iter;
+
+	g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL);
+	g_return_val_if_fail (group_name != NULL, NULL);
+
+	iter = gtk_ui_manager_get_action_groups (ui_manager);
+
+	while (iter != NULL) {
+		GtkActionGroup *action_group = iter->data;
+		const gchar *name;
+
+		name = gtk_action_group_get_name (action_group);
+		if (strcmp (name, group_name) == 0)
+			return action_group;
+
+		iter = g_list_next (iter);
+	}
+
+	g_critical ("%s: action group `%s' not found", G_STRFUNC, group_name);
+
+	return NULL;
+}
+
+/**
+ * e_load_ui_definition:
+ * @ui_manager: a #GtkUIManager
+ * @basename: basename of the UI definition file
+ *
+ * Loads a UI definition into @ui_manager from Evolution's UI directory.
+ * Failure here is fatal, since the application can't function without
+ * its UI definitions.
+ *
+ * Returns: The merge ID for the merged UI.  The merge ID can be used to
+ *          unmerge the UI with gtk_ui_manager_remove_ui().
+ **/
+guint
+e_load_ui_definition (GtkUIManager *ui_manager,
+                      const gchar *basename)
+{
+	gchar *filename;
+	guint merge_id;
+	GError *error = NULL;
+
+	g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), 0);
+	g_return_val_if_fail (basename != NULL, 0);
+
+	filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL);
+	merge_id = gtk_ui_manager_add_ui_from_file (
+		ui_manager, filename, &error);
+	g_free (filename);
+
+	if (error != NULL) {
+		g_error ("%s: %s", basename, error->message);
+		g_assert_not_reached ();
+	}
+
+	return merge_id;
+}
+
+/**
+ * e_action_compare_by_label:
+ * @action1: a #GtkAction
+ * @action2: a #GtkAction
+ *
+ * Compares the labels for @action1 and @action2 using g_utf8_collate().
+ *
+ * Returns: &lt; 0 if @action1 compares before @action2, 0 if they
+ *          compare equal, &gt; 0 if @action1 compares after @action2
+ **/
+gint
+e_action_compare_by_label (GtkAction *action1,
+                           GtkAction *action2)
+{
+	gchar *label1;
+	gchar *label2;
+	gint result;
+
+	/* XXX This is horribly inefficient but will generally only be
+	 *     used on short lists of actions during UI construction. */
+
+	if (action1 == action2)
+		return 0;
+
+	g_object_get (action1, "label", &label1, NULL);
+	g_object_get (action2, "label", &label2, NULL);
+
+	result = g_utf8_collate (label1, label2);
+
+	g_free (label1);
+	g_free (label2);
+
+	return result;
+}
+
+/**
+ * e_action_group_remove_all_actions:
+ * @action_group: a #GtkActionGroup
+ *
+ * Removes all actions from the action group.
+ **/
+void
+e_action_group_remove_all_actions (GtkActionGroup *action_group)
+{
+	GList *list, *iter;
+
+	/* XXX I've proposed this function for inclusion in GTK+.
+         *     GtkActionGroup stores actions in an internal hash
+         *     table and can do this more efficiently by calling
+         *     g_hash_table_remove_all().
+         *
+         *     http://bugzilla.gnome.org/show_bug.cgi?id=550485 */
+
+	g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
+
+	list = gtk_action_group_list_actions (action_group);
+	for (iter = list; iter != NULL; iter = iter->next)
+		gtk_action_group_remove_action (action_group, iter->data);
+	g_list_free (list);
+}
+
+/**
  * e_str_without_underscores:
  * @s: the string to strip underscores from.
  *
@@ -1321,3 +1498,33 @@ e_util_get_category_filter_options (void)
 
 	return g_slist_reverse (res);
 }
+
+static gpointer
+e_camel_object_copy (gpointer camel_object)
+{
+	if (CAMEL_IS_OBJECT (camel_object))
+		camel_object_ref (camel_object);
+
+	return camel_object;
+}
+
+static void
+e_camel_object_free (gpointer camel_object)
+{
+	if (CAMEL_IS_OBJECT (camel_object))
+		camel_object_unref (camel_object);
+}
+
+GType
+e_camel_object_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0))
+		type = g_boxed_type_register_static (
+			"ECamelObject",
+			(GBoxedCopyFunc) e_camel_object_copy,
+			(GBoxedFreeFunc) e_camel_object_free);
+
+	return type;
+}
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 021e328..480da24 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -27,6 +27,7 @@
 #include <gtk/gtk.h>
 #include <limits.h>
 #include <gconf/gconf-client.h>
+#include <camel/camel-object.h>
 #include <cairo.h>
 
 #include <e-util/e-marshal.h>
@@ -46,6 +47,16 @@ void		e_show_uri			(GtkWindow *parent,
 						 const gchar *uri);
 void		e_display_help			(GtkWindow *parent,
 						 const gchar *link_id);
+GtkAction *	e_lookup_action			(GtkUIManager *ui_manager,
+						 const gchar *action_name);
+GtkActionGroup *e_lookup_action_group		(GtkUIManager *ui_manager,
+						 const gchar *group_name);
+guint		e_load_ui_definition		(GtkUIManager *ui_manager,
+						 const gchar *basename);
+gint		e_action_compare_by_label	(GtkAction *action1,
+						 GtkAction *action2);
+void		e_action_group_remove_all_actions
+						(GtkActionGroup *action_group);
 
 char *		e_str_without_underscores	(const char *s);
 gint		e_str_compare			(gconstpointer x,
@@ -130,6 +141,11 @@ gboolean	e_util_read_file		(const gchar *filename,
 
 GSList *e_util_get_category_filter_options      (void);
 
+/* Camel uses its own object system, so we have to box
+ * CamelObjects to safely use them as GObject properties. */
+#define E_TYPE_CAMEL_OBJECT (e_camel_object_get_type ())
+GType		e_camel_object_get_type		(void);
+
 G_END_DECLS
 
 #endif /* _E_UTIL_H_ */
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 23778d5..2a567ec 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -54,6 +54,7 @@ idl_DATA = $(MAIL_IDL)
 # plugin mail api
 mailinclude_HEADERS =				\
 	$(MAIL_IDL_GENERATED_H)			\
+	e-mail-attachment-bar.h			\
 	em-composer-utils.h			\
 	em-config.h				\
 	em-event.h				\
@@ -93,6 +94,9 @@ mailinclude_HEADERS =				\
 libevolution_mail_la_SOURCES =			\
 	$(MAIL_IDL_GENERATED)			\
 	$(mailinclude_HEADERS)			\
+	e-attachment-handler-mail.c		\
+	e-attachment-handler-mail.h		\
+	e-mail-attachment-bar.c			\
 	e-searching-tokenizer.c			\
 	e-searching-tokenizer.h			\
 	em-account-editor.c			\
diff --git a/mail/em-filter-i18n.h b/mail/em-filter-i18n.h
index 8b8d0c3..c0b2925 100644
--- a/mail/em-filter-i18n.h
+++ b/mail/em-filter-i18n.h
@@ -26,6 +26,7 @@ char *s = N_("Exist");
 char *s = N_("exists");
 char *s = N_("Expression");
 char *s = N_("Follow Up");
+char *s = N_("Forward to");
 char *s = N_("Important");
 char *s = N_("is");
 char *s = N_("is after");
@@ -46,6 +47,7 @@ char *s = N_("Message Body");
 char *s = N_("Message Header");
 char *s = N_("Message is Junk");
 char *s = N_("Message is not Junk");
+char *s = N_("Message Location");
 char *s = N_("Move to Folder");
 char *s = N_("Pipe to Program");
 char *s = N_("Play Sound");
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index ad72ee8..7897058 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -80,14 +80,15 @@
 
 #include "mail-config.h"
 
+#include "e-mail-attachment-bar.h"
 #include "em-format-html-display.h"
 #include "e-searching-tokenizer.h"
 #include "em-icon-stream.h"
 #include "em-utils.h"
 #include "em-popup.h"
-#include "e-attachment.h"
-#include "e-attachment-bar.h"
 #include "e-icon-entry.h"
+#include "widgets/misc/e-attachment-button.h"
+#include "widgets/misc/e-attachment-view.h"
 
 #ifdef G_OS_WIN32
 /* Undefine the similar macro from <pthread.h>,it doesn't check if
@@ -113,18 +114,7 @@ struct _EMFormatHTMLDisplayPrivate {
 	int search_wrap;	/* are we doing a wrap search */
 	gboolean search_active; /* if the search is active */
 
-	/* for Attachment bar */
-	GtkWidget *attachment_bar;
-	GtkWidget *attachment_box;
-	GtkWidget *label;
-	GtkWidget *save_txt;
-	GtkWidget *arrow;
-	GtkWidget *forward;
-	GtkWidget *down;
-	GtkWidget *attachment_area;
-	gboolean  show_bar;
-	GHashTable *files;
-	gboolean updated;
+	GtkWidget *attachment_view;  /* weak reference */
 };
 
 static int efhd_html_button_press_event (GtkWidget *widget, GdkEventButton *event, EMFormatHTMLDisplay *efh);
@@ -134,8 +124,6 @@ static void efhd_html_on_url (GtkHTML *html, const char *url, EMFormatHTMLDispla
 static void efhd_attachment_frame(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri);
 static gboolean efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject);
 static void efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
-static void efhd_message_update_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
-static void efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd);
 
 struct _attach_puri {
 	EMFormatPURI puri;
@@ -186,7 +174,6 @@ static void efhd_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, c
 static void efhd_format_optional(EMFormat *, CamelStream *, CamelMimePart *, CamelStream *);
 static void efhd_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid);
 static void efhd_complete(EMFormat *);
-gboolean efhd_mnemonic_show_bar (GtkWidget *widget, gboolean focus, GtkWidget *efhd);
 
 static gboolean efhd_bonobo_object(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject); 	 
 static gboolean efhd_use_component(const char *mime_type);
@@ -279,9 +266,6 @@ efhd_init(GObject *o)
 #undef efh
 
 	efhd->nobar = getenv("EVOLUTION_NO_BAR") != NULL;
-
-	efhd->priv->show_bar = FALSE;
-	efhd->priv->files = NULL;
 }
 
 static void
@@ -291,9 +275,6 @@ efhd_finalise(GObject *o)
 
 	/* check pending stuff */
 
-	if (efhd->priv->files)
-		g_hash_table_destroy(efhd->priv->files);
-
 	g_free(efhd->priv->search_text);
 	g_free(efhd->priv);
 
@@ -431,12 +412,6 @@ void em_format_html_display_set_caret_mode(EMFormatHTMLDisplay *efhd, gboolean s
 	gtk_html_set_caret_mode(((EMFormatHTML *)efhd)->html, state);
 }
 
-EAttachmentBar *
-em_format_html_display_get_bar (EMFormatHTMLDisplay *efhd)
-{
-	return E_ATTACHMENT_BAR (efhd->priv->attachment_bar);
-}
-
 void
 em_format_html_display_set_search(EMFormatHTMLDisplay *efhd, int type, GSList *strings)
 {
@@ -933,11 +908,6 @@ efhd_complete(EMFormat *emf)
 
 	if (efhd->priv->search_dialog && efhd->priv->search_active)
 		efhd_update_matches(efhd);
-
-	if (efhd->priv->files) {
-		g_hash_table_destroy (efhd->priv->files);
-		efhd->priv->files = NULL;
-	}
 }
 
 /* ********************************************************************** */
@@ -1293,9 +1263,7 @@ static EMFormatHandler type_builtin_table[] = {
 	{ "image/pjpeg", (EMFormatFunc)efhd_image },
 
 	{ "x-evolution/message/prefix", (EMFormatFunc)efhd_message_prefix },
-	{ "x-evolution/message/post-header", (EMFormatFunc)efhd_message_add_bar },
-	{ "x-evolution/message/post-header-closure", (EMFormatFunc)efhd_message_update_bar },
-
+	{ "x-evolution/message/post-header", (EMFormatFunc)efhd_message_add_bar }
 };
 
 static void
@@ -1343,15 +1311,8 @@ static const EMFormatHandler *efhd_find_handler(EMFormat *emf, const char *mime_
 
 static void efhd_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *src)
 {
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf;
-
-	if (emf != src) {
-		if (src)
-			efhd->priv->show_bar = ((EMFormatHTMLDisplay *)src)->priv->show_bar;
-		else
-			efhd->priv->show_bar = FALSE;
+	if (emf != src)
 		((EMFormatHTML *) emf)->header_wrap_flags = 0;
-	}
 
 	((EMFormatClass *)efhd_parent)->format_clone(emf, folder, uid, msg, src);
 }
@@ -1467,12 +1428,14 @@ efhd_attachment_show(EPopup *ep, EPopupItem *item, void *data)
 }
 
 static void
-efhd_attachment_button_show(GtkWidget *w, void *data)
+efhd_attachment_button_expanded (GtkWidget *widget,
+                                 GParamSpec *pspec,
+                                 struct _attach_puri *info)
 {
-	if (!efhd_can_process_attachment (w))
+	if (!efhd_can_process_attachment (widget))
 		return;
 
-	efhd_attachment_show(NULL, NULL, data);
+	efhd_attachment_show (NULL, NULL, info);
 }
 
 static void
@@ -1811,16 +1774,12 @@ static gboolean
 efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
 {
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh;
-	EAttachment *new;
 	struct _attach_puri *info;
-	GtkWidget *hbox, *w, *button, *mainbox;
-	char *simple_type, *tmp, *new_file = NULL;
-	const char *file;
-	GtkTargetEntry drag_types[] = {
-		{ NULL, 0, 0 },
-		{ "text/uri-list", 0, 1 },
-	};
-	AtkObject *a11y;
+	EAttachmentView *view;
+	EAttachmentStore *store;
+	EAttachment *attachment;
+	GtkWidget *widget;
+	gpointer parent;
 
 	/* FIXME: handle default shown case */
 	d(printf("adding attachment button/content\n"));
@@ -1832,139 +1791,36 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
 		return TRUE;
 	}
 
-	if (efhd->priv->attachment_bar) {
-		file = camel_mime_part_get_filename(info->puri.part);
-
-		new = info->attachment;
-
-		if (!file) {
-			file = "attachment.dat";
-			new->file_name = g_strdup(file);
-		}
-
-		tmp = g_hash_table_lookup (efhd->priv->files, file);
-		if (tmp) {
-			guint count = GPOINTER_TO_UINT(tmp);
-			char *ext;
-			char *tmp_file = g_strdup (file);
-
-			if ((ext = strrchr(tmp_file, '.'))) {
-				ext[0] = 0;
-				new_file = g_strdup_printf("%s(%d).%s", tmp_file, count++, ext+1);
-			} else {
-				new_file = g_strdup_printf("%s(%d)", tmp_file, count++);
-			}
-
-			g_free (tmp_file);
-			g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(count));
-			g_free (new->file_name);
-			new->file_name = new_file;
-		} else {
-			g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(1));
-		}
-
-		/* Store the status of encryption / signature on the attachment for emblem display
-		 * FIXME: May not work well always
-		 */
-		new->sign = info->sign;
-		new->encrypt = info->encrypt;
-
-		/* Add the attachment to the bar.*/
-		e_attachment_bar_add_attachment_silent (E_ATTACHMENT_BAR(efhd->priv->attachment_bar), new);
-		efhd_attachment_bar_refresh(efhd);
-	}
-
-	mainbox = gtk_hbox_new(FALSE, 0);
-
-	button = gtk_button_new();
-
-	if (info->handle) {
-		g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_button_show), info);
-		g_object_set_data (G_OBJECT (button), "efh", efh);
-	} else {
-		gtk_widget_set_sensitive(button, FALSE);
-		GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);
-	}
-
-	hbox = gtk_hbox_new(FALSE, 2);
-	info->forward = gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON);
-	gtk_box_pack_start((GtkBox *)hbox, info->forward, TRUE, TRUE, 0);
-	if (info->handle) {
-		info->down = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
-		gtk_box_pack_start((GtkBox *)hbox, info->down, TRUE, TRUE, 0);
-	}
-
-	w = gtk_image_new();
-	gtk_widget_set_size_request(w, 24, 24);
-	gtk_box_pack_start((GtkBox *)hbox, w, TRUE, TRUE, 0);
-	gtk_container_add((GtkContainer *)button, hbox);
-	gtk_box_pack_start((GtkBox *)mainbox, button, TRUE, TRUE, 0);
-
-	/* Check for snooped type to get the right icon/processing */
-	if (info->snoop_mime_type)
-		simple_type = g_strdup(info->snoop_mime_type);
-	else
-		simple_type = camel_content_type_simple (((CamelDataWrapper *)pobject->part)->mime_type);
-	camel_strdown(simple_type);
-
-	/* FIXME: offline parts, just get icon */
-	if (camel_content_type_is(((CamelDataWrapper *)pobject->part)->mime_type, "image", "*")) {
-		EMFormatHTMLJob *job;
-		GdkPixbuf *mini;
-		char *key;
-
-		key = pobject->classid;
-		mini = em_icon_stream_get_image(key, 24, 24);
-		if (mini) {
-			d(printf("got image from cache '%s'\n", key));
-			gtk_image_set_from_pixbuf((GtkImage *)w, mini);
-			g_object_unref(mini);
-		} else {
-			d(printf("need to create icon image '%s'\n", key));
-			job = em_format_html_job_new(efh, efhd_write_icon_job, pobject);
-			job->stream = (CamelStream *)em_icon_stream_new((GtkImage *)w, key, 24, 24, FALSE);
-			em_format_html_job_queue(efh, job);
-		}
-	} else {
-		GdkPixbuf *pixbuf, *mini;
-
-		if ((pixbuf = e_icon_for_mime_type (simple_type, 24))) {
-			if ((mini = e_icon_factory_pixbuf_scale (pixbuf, 24, 24))) {
-				gtk_image_set_from_pixbuf ((GtkImage *) w, mini);
-				g_object_unref (mini);
-			}
-			g_object_unref (pixbuf);
-		}
-	}
-
-	drag_types[0].target = simple_type;
-	gtk_drag_source_set(button, GDK_BUTTON1_MASK, drag_types, sizeof(drag_types)/sizeof(drag_types[0]), GDK_ACTION_COPY);
-	g_signal_connect(button, "drag-data-get", G_CALLBACK(efhd_drag_data_get), pobject);
-	g_signal_connect (button, "drag-data-delete", G_CALLBACK(efhd_drag_data_delete), pobject);
-	g_free(simple_type);
+	attachment = info->attachment;
+	e_attachment_set_shown (attachment, info->shown);
+	e_attachment_set_signed (attachment, info->sign);
+	e_attachment_set_encrypted (attachment, info->encrypt);
+	e_attachment_set_can_show (attachment, info->handle != NULL);
 
-	button = gtk_button_new();
-	/*GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);*/
-	gtk_container_add((GtkContainer *)button, gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE));
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (efh->html));
+	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 
-	a11y = gtk_widget_get_accessible (button);
-	atk_object_set_name (a11y, _("Attachment"));
+	view = E_ATTACHMENT_VIEW (efhd->priv->attachment_view);
+	gtk_widget_show (efhd->priv->attachment_view);
 
-	g_signal_connect(button, "button_press_event", G_CALLBACK(efhd_attachment_popup), info);
-	g_signal_connect(button, "popup_menu", G_CALLBACK(efhd_attachment_popup_menu), info);
-	g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_popup_menu), info);
-	gtk_box_pack_start((GtkBox *)mainbox, button, TRUE, TRUE, 0);
+	store = e_attachment_view_get_store (view);
+	e_attachment_store_add_attachment (store, info->attachment);
 
-	g_object_set_data (G_OBJECT (button), "efh", efh);
+	e_attachment_load_async (
+		info->attachment, (GAsyncReadyCallback)
+		e_attachment_load_handle_error, parent);
 
-	gtk_widget_show_all(mainbox);
+	widget = e_attachment_button_new (view);
+	e_attachment_button_set_attachment (
+		E_ATTACHMENT_BUTTON (widget), attachment);
+	gtk_container_add (GTK_CONTAINER (eb), widget);
+	gtk_widget_show (widget);
 
-	if (info->shown)
-		gtk_widget_hide(info->forward);
-	else if (info->down)
-		gtk_widget_hide(info->down);
+	g_object_set_data (G_OBJECT (widget), "efh", efh);
 
-	gtk_container_add((GtkContainer *)eb, mainbox);
+	g_signal_connect (
+		widget, "notify::expanded",
+		G_CALLBACK (efhd_attachment_button_expanded), info);
 
 	return TRUE;
 }
@@ -2138,330 +1994,57 @@ type_ok:
 }
 
 static void
-attachment_bar_arrow_clicked(GtkWidget *w, EMFormatHTMLDisplay *efhd)
+efhd_bar_resize (EMFormatHTML *efh,
+                 GtkAllocation *event)
 {
+	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh;
+	GtkWidget *widget;
+	gint width;
 
-	efhd->priv->show_bar = !efhd->priv->show_bar;
+	widget = GTK_WIDGET (efh->html);
+	width = widget->allocation.width - 12;
 
-	if (efhd->priv->show_bar) {
-		gtk_widget_show(efhd->priv->attachment_box);
-		gtk_widget_show(efhd->priv->down);
-		gtk_widget_hide(efhd->priv->forward);
-	} else {
-		gtk_widget_hide(efhd->priv->attachment_box);
-		gtk_widget_show(efhd->priv->forward);
-		gtk_widget_hide(efhd->priv->down);
+	if (width > 0) {
+		widget = efhd->priv->attachment_view;
+		gtk_widget_set_size_request (widget, width, -1);
 	}
 }
 
-static void
-attachments_save_all_clicked (GtkWidget *widget, EMFormatHTMLDisplay *efhd)
-{
-	GSList *attachment_parts;
-	guint n_attachment_parts;
-
-	attachment_parts = e_attachment_bar_get_parts (
-		E_ATTACHMENT_BAR (efhd->priv->attachment_bar));
-	n_attachment_parts = g_slist_length (attachment_parts);
-	g_return_if_fail (n_attachment_parts > 0);
-
-	if (n_attachment_parts == 1)
-		em_utils_save_part (
-			widget, _("Save attachment as"),
-			attachment_parts->data);
-	else
-		em_utils_save_parts (
-			widget, _("Select folder to save all attachments"),
-			attachment_parts);
-
-        g_slist_free (attachment_parts);
-}
-
-static void
-efhd_bar_popup_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
-{
-	EAttachmentBar *bar = user_data;
-	GnomeIconList *icon_list = user_data;
-	GList *selection;
-	GnomeCanvasPixbuf *image;
-
-	gdk_window_get_origin (((GtkWidget*) bar)->window, x, y);
-
-	selection = gnome_icon_list_get_selection (icon_list);
-	if (selection == NULL)
-		return;
-
-	image = gnome_icon_list_get_icon_pixbuf_item (icon_list, GPOINTER_TO_INT(selection->data));
-	if (image == NULL)
-		return;
-
-	/* Put menu to the center of icon. */
-	*x += (int)(image->item.x1 + image->item.x2) / 2;
-	*y += (int)(image->item.y1 + image->item.y2) / 2;
-}
-
-static void
-efhd_bar_save_selected(EPopup *ep, EPopupItem *item, void *data)
-{
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)data;
-	GSList *attachment_parts, *tmp;
-	GSList *parts = NULL;
-
-	attachment_parts = e_attachment_bar_get_selected(E_ATTACHMENT_BAR(efhd->priv->attachment_bar));
-
-	for (tmp = attachment_parts; tmp; tmp=tmp->next)
-		parts = g_slist_prepend(parts, ((EAttachment *)tmp->data)->body);
-
-	parts = g_slist_reverse(parts);
-	em_utils_save_parts(efhd->priv->attachment_bar, _("Select folder to save selected attachments..."), parts);
-        g_slist_free (parts);
-
-	g_slist_foreach(attachment_parts, (GFunc)g_object_unref, NULL);
-	g_slist_free (attachment_parts);
-}
-
-static EPopupItem efhd_bar_menu_items[] = {
-	{ E_POPUP_BAR, "05.display", },
-	{ E_POPUP_ITEM, "05.display.01", N_("_Save Selected..."), efhd_bar_save_selected, NULL, NULL, EM_POPUP_ATTACHMENTS_MULTIPLE},
-};
-
-static gboolean
-efhd_bar_button_press_event(EAttachmentBar *bar, GdkEventButton *event, EMFormat *emf)
-{
-	GtkMenu *menu;
-	GSList *list=NULL;
-	EPopupTarget *target;
-	EMPopup *emp;
-	GSList *menus = NULL;
-	int i;
-
-	if (event && event->button != 3)
-		return FALSE;
-
-	/** @HookPoint-EMPopup: Attachment Bar Context Menu
-	 * @Id: org.gnome.evolution.mail.attachments.popup
-	 * @Class: org.gnome.evolution.mail.popup:1.0
-	 * @Target: EMPopupTargetPart
-	 *
-	 * This is the drop-down menu shown when a user clicks on the attachment bar
-	 * when attachments are selected.
-	 */
-	emp = em_popup_new("org.gnome.evolution.mail.attachments.popup");
-
-	/* Add something like save-selected, foward selected attachments in a mail etc....*/
-	list = e_attachment_bar_get_selected(bar);
-
-	/* Lets not propagate any more the r-click which is intended to us*/
-	if ( g_slist_length (list) == 0)
-		return TRUE;
-
-	target = (EPopupTarget *)em_popup_target_new_attachments(emp, list);
-	for (i=0; i<2; i++)
-		menus = g_slist_prepend(menus, &efhd_bar_menu_items[i]);
-	e_popup_add_items((EPopup *)emp, menus, NULL, efhd_menu_items_free, emf);
-
-	((EMPopupTargetPart *)target)->target.widget = (GtkWidget *)bar;
-	menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, 0);
-	if (event)
-		gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
-	else
-		gtk_menu_popup(menu, NULL, NULL, (GtkMenuPositionFunc)efhd_bar_popup_position, bar, 0, gtk_get_current_event_time());
-
-	return TRUE;
-}
-
 static gboolean
-efhd_bar_popup_menu_event (EAttachmentBar *bar, EMFormat *emf)
-{
-	return efhd_bar_button_press_event(bar, NULL, emf);
-}
-
-static void
-efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd)
-{
-	int nattachments;
-
-	if (!efhd->priv->attachment_bar)
-		return;
-
-	nattachments = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR(efhd->priv->attachment_bar));
-	if (nattachments) {
-		char *txt;
-
-		/* Cant i put in the number of attachments here ?*/
-		txt = g_strdup_printf(ngettext("%d at_tachment", "%d at_tachments", nattachments), nattachments);
-		gtk_label_set_text_with_mnemonic ((GtkLabel *)efhd->priv->label, txt);
-		g_free (txt);
-
-		/* Show the bar even when the first attachment is added */
-		if (nattachments == 1) {
-			gtk_widget_show_all (efhd->priv->attachment_area);
-			gtk_label_set_text_with_mnemonic ((GtkLabel *)efhd->priv->save_txt, _("S_ave"));
-
-			if (efhd->priv->show_bar) {
-				gtk_widget_show(efhd->priv->down);
-				gtk_widget_hide(efhd->priv->forward);
-			} else {
-				gtk_widget_show(efhd->priv->forward);
-				gtk_widget_hide(efhd->priv->down);
-				gtk_widget_hide(efhd->priv->attachment_box);
-			}
-		} else if (nattachments > 1) {
-			gtk_label_set_text_with_mnemonic ((GtkLabel *)efhd->priv->save_txt, _("S_ave All"));
-		}
-	}
-}
-
-static void
-efhd_bar_resize(GtkWidget *w, GtkAllocation *event, EMFormatHTML *efh)
+efhd_add_bar (EMFormatHTML *efh,
+              GtkHTMLEmbedded *eb,
+              EMFormatHTMLPObject *pobject)
 {
-	int width;
-	GtkRequisition req;
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh;
+	GtkWidget *widget;
 
-	gtk_widget_size_request (efhd->priv->attachment_bar, &req);
-	width = ((GtkWidget *) efh->html)->allocation.width - 16;
-
-	/* Update the width of the bar when the width is greater than 1*/
-	if (width > 0)
-		e_attachment_bar_set_width(E_ATTACHMENT_BAR(efhd->priv->attachment_bar), width);
-}
-
-static gboolean
-efhd_bar_scroll_event(GtkWidget *w, GdkEventScroll *event, EMFormatHTMLDisplay *efhd)
-{
-	gboolean ret;
-
-	/* Emulate the scroll over the attachment bar, as if it is scrolled in the window.
-	*  It doesnt go automatically since the GnomeIconList is a layout by itself
-	*/
-	g_signal_emit_by_name (gtk_widget_get_parent((GtkWidget *)efhd->formathtml.html), "scroll_event", event, &ret);
-
-	return TRUE;
-}
-
-gboolean
-efhd_mnemonic_show_bar (GtkWidget *widget, gboolean focus, GtkWidget *efhd)
-{
-	attachment_bar_arrow_clicked (NULL, (EMFormatHTMLDisplay *)efhd);
-
-	return TRUE;
-}
-
-static gboolean
-efhd_update_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
-{
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh;
-	struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv;
-
-	if (priv->attachment_bar)
-		e_attachment_bar_refresh (E_ATTACHMENT_BAR (priv->attachment_bar));
-
-	return TRUE;
-}
-
-static gboolean
-efhd_add_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
-{
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh;
-	struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv;
-	GtkWidget *hbox1, *hbox2, *hbox3, *vbox, *txt, *image, *save, *scroll;
-	int width, height, bar_width;
-
-	priv->attachment_bar = e_attachment_bar_new(NULL);
-	scroll = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	((EAttachmentBar *)priv->attachment_bar)->expand = TRUE;
-
-	priv->forward = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
-	priv->down = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
-	hbox3 = gtk_hbox_new (FALSE, 0);
-	gtk_box_pack_start ((GtkBox *)hbox3, priv->forward, FALSE, FALSE, 0);
-	gtk_box_pack_start ((GtkBox *)hbox3, priv->down, FALSE, FALSE, 0);
-	priv->arrow = (GtkWidget *)gtk_tool_button_new(hbox3, NULL);
-	g_signal_connect (priv->arrow, "mnemonic_activate", G_CALLBACK (efhd_mnemonic_show_bar), efh);
-	atk_object_set_name (gtk_widget_get_accessible (priv->arrow), _("Show Attachments"));
-
-	priv->label = gtk_label_new(_("No Attachment"));
-	gtk_label_set_mnemonic_widget (GTK_LABEL (priv->label), priv->arrow);
-	save = gtk_button_new();
-	image = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_BUTTON);
-	txt = gtk_label_new_with_mnemonic(_("S_ave"));
-	priv->save_txt = txt;
-	hbox1 = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start((GtkBox *)hbox1, image, FALSE, FALSE, 2);
-	gtk_box_pack_start((GtkBox *)hbox1, txt, FALSE, FALSE, 0);
-
-	gtk_container_add((GtkContainer *)save, hbox1);
-
-	hbox2 = gtk_hbox_new (FALSE, 0);
-	gtk_box_pack_start ((GtkBox *)hbox2, priv->arrow, FALSE, FALSE, 0);
-	gtk_box_pack_start ((GtkBox *)hbox2, priv->label, FALSE, FALSE, 2);
-	gtk_box_pack_start ((GtkBox *)hbox2, save, FALSE, FALSE, 2);
-
-	priv->attachment_box = scroll;
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
-	gtk_container_add ((GtkContainer *)priv->attachment_box, priv->attachment_bar);
-
-	gtk_widget_get_size_request(priv->attachment_bar, &width, &height);
-
-	/* FIXME: What if the text is more?. Should we reduce the text with appending ...?
-	 * or resize the bar? How to figure out that, it needs more space? */
-	bar_width = ((GtkWidget *)efh->html)->parent->allocation.width - /* FIXME */16;
-	gtk_widget_set_size_request (priv->attachment_bar,
-				     bar_width > 0 ? bar_width : 0,
-				     84 /* FIXME: Default show only one row, Dont hardcode size*/);
-
-	vbox = gtk_vbox_new (FALSE, 0);
-	gtk_box_pack_start ((GtkBox *)vbox, hbox2, FALSE, FALSE, 2);
-	gtk_box_pack_start ((GtkBox *)vbox, priv->attachment_box, TRUE, TRUE, 2);
-
-	gtk_container_add ((GtkContainer *)eb, vbox);
-	gtk_widget_show ((GtkWidget *)eb);
-
-	/* Lets hide it by default and show only when there are attachments */
-	priv->attachment_area = vbox;
-	gtk_widget_hide_all (priv->attachment_area);
+	widget = e_mail_attachment_bar_new ();
+	gtk_container_add (GTK_CONTAINER (eb), widget);
+	efhd->priv->attachment_view = widget;
+	gtk_widget_hide (widget);
 
-	g_signal_connect (priv->arrow, "clicked", G_CALLBACK(attachment_bar_arrow_clicked), efh);
-	g_signal_connect (priv->attachment_bar, "button_press_event", G_CALLBACK(efhd_bar_button_press_event), efhd);
-	g_signal_connect (priv->attachment_bar, "popup-menu", G_CALLBACK(efhd_bar_popup_menu_event), efhd);
-	g_signal_connect (save, "clicked", G_CALLBACK(attachments_save_all_clicked), efh);
-	g_signal_connect (eb, "size_allocate", G_CALLBACK (efhd_bar_resize), efh);
-	g_signal_connect (priv->attachment_bar, "scroll_event", G_CALLBACK(efhd_bar_scroll_event), efhd);
+	g_signal_connect_swapped (
+		eb, "size-allocate",
+		G_CALLBACK (efhd_bar_resize), efh);
 
 	return TRUE;
 }
-static void
-efhd_message_update_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
-{
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf;
-	const char *classid = "attachment-bar-refresh";
-
-	if (efhd->nobar || efhd->priv->updated)
-		return;
-
-	efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-	efhd->priv->updated = TRUE;
-	em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_update_bar);
-	camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td>", classid);
-
-}
 
 static void
-efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+efhd_message_add_bar (EMFormat *emf,
+                      CamelStream *stream,
+                      CamelMimePart *part,
+                      const EMFormatHandler *info)
 {
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf;
 	const char *classid = "attachment-bar";
 
-	if (efhd->nobar || efhd->priv->files)
-		return;
+	em_format_html_add_pobject (
+		(EMFormatHTML *) emf,
+		sizeof (EMFormatHTMLPObject),
+		classid, part, efhd_add_bar);
 
-	efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-	efhd->priv->updated = FALSE;
-
-	em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_add_bar);
-	camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td>", classid);
+	camel_stream_printf (
+		stream, "<td><object classid=\"%s\"></object></td>", classid);
 }
 
 static void
@@ -2470,43 +2053,50 @@ efhd_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part,
 	char *classid, *text, *html;
 	struct _attach_puri *info;
 
-	classid = g_strdup_printf("attachment%s", emf->part_id->str);
-	info = (struct _attach_puri *)em_format_add_puri(emf, sizeof(*info), classid, part, efhd_attachment_frame);
-	em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_attachment_button);
+	classid = g_strdup_printf ("attachment%s", emf->part_id->str);
+	info = (struct _attach_puri *)em_format_add_puri (
+		emf, sizeof (*info), classid, part, efhd_attachment_frame);
+	em_format_html_add_pobject (
+		(EMFormatHTML *) emf, sizeof (EMFormatHTMLPObject),
+		classid, part, efhd_attachment_button);
 	info->handle = handle;
-	info->shown = em_format_is_inline(emf, info->puri.part_id, info->puri.part, handle);
+	info->shown = em_format_is_inline (
+		emf, info->puri.part_id, info->puri.part, handle);
 	info->snoop_mime_type = emf->snoop_mime_type;
-	info->attachment = e_attachment_new_from_mime_part (info->puri.part);
-	e_attachment_bar_create_attachment_cache (info->attachment);
+	info->attachment = e_attachment_new ();
+	e_attachment_set_mime_part (info->attachment, info->puri.part);
 
 	if (emf->valid) {
 		info->sign = emf->valid->sign.status;
 		info->encrypt = emf->valid->encrypt.status;
 	}
 
-	camel_stream_write_string(stream,
-				  EM_FORMAT_HTML_VPAD
-				  "<table cellspacing=0 cellpadding=0><tr><td>"
-				  "<table width=10 cellspacing=0 cellpadding=0>"
-				  "<tr><td></td></tr></table></td>");
+	camel_stream_write_string (
+		stream, EM_FORMAT_HTML_VPAD
+		"<table cellspacing=0 cellpadding=0><tr><td>"
+		"<table width=10 cellspacing=0 cellpadding=0>"
+		"<tr><td></td></tr></table></td>");
 
-	camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td>", classid);
+	camel_stream_printf (
+		stream, "<td><object classid=\"%s\"></object></td>", classid);
 
-	camel_stream_write_string(stream,
-				  "<td><table width=3 cellspacing=0 cellpadding=0>"
-				  "<tr><td></td></tr></table></td><td><font size=-1>");
+	camel_stream_write_string (
+		stream, "<td><table width=3 cellspacing=0 cellpadding=0>"
+		"<tr><td></td></tr></table></td><td><font size=-1>");
 
 	/* output some info about it */
 	/* FIXME: should we look up mime_type from object again? */
-	text = em_format_describe_part(part, mime_type);
-	html = camel_text_to_html(text, ((EMFormatHTML *)emf)->text_html_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
-	camel_stream_write_string(stream, html);
-	g_free(html);
-	g_free(text);
-
-	camel_stream_write_string(stream,
-				  "</font></td></tr><tr></table>\n"
-				  EM_FORMAT_HTML_VPAD);
+	text = em_format_describe_part (part, mime_type);
+	html = camel_text_to_html (
+		text, ((EMFormatHTML *)emf)->text_html_flags &
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+	camel_stream_write_string (stream, html);
+	g_free (html);
+	g_free (text);
+
+	camel_stream_write_string (
+		stream, "</font></td></tr><tr></table>\n"
+		EM_FORMAT_HTML_VPAD);
 
 	if (handle) {
 		if (info->shown)
@@ -2653,7 +2243,8 @@ efhd_format_optional(EMFormat *emf, CamelStream *fstream, CamelMimePart *part, C
 	info->handle = em_format_find_handler(emf, "text/plain");
 	info->shown = FALSE;
 	info->snoop_mime_type = "text/plain";
-	info->attachment = e_attachment_new_from_mime_part (info->puri.part);
+	info->attachment = e_attachment_new ();
+	e_attachment_set_mime_part (info->attachment, info->puri.part);
 	info->mstream = (CamelStreamMem *)mstream;
 	if (emf->valid) {
 		info->sign = emf->valid->sign.status;
diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h
index 651b981..4e2e7c1 100644
--- a/mail/em-format-html-display.h
+++ b/mail/em-format-html-display.h
@@ -26,7 +26,6 @@
 #define _EM_FORMAT_HTML_DISPLAY_H
 
 #include "mail/em-format-html.h"
-#include "widgets/misc/e-attachment-bar.h"
 
 typedef struct _EMFormatHTMLDisplay EMFormatHTMLDisplay;
 typedef struct _EMFormatHTMLDisplayClass EMFormatHTMLDisplayClass;
@@ -82,7 +81,6 @@ void em_format_html_display_paste (EMFormatHTMLDisplay *efhd);
 void em_format_html_display_zoom_in (EMFormatHTMLDisplay *efhd);
 void em_format_html_display_zoom_out (EMFormatHTMLDisplay *efhd);
 void em_format_html_display_zoom_reset (EMFormatHTMLDisplay *efhd);
-EAttachmentBar *em_format_html_display_get_bar (EMFormatHTMLDisplay *efhd);
 
 gboolean em_format_html_display_popup_menu (EMFormatHTMLDisplay *efhd);
 
diff --git a/mail/em-popup.c b/mail/em-popup.c
index 91e6ed6..debad8c 100644
--- a/mail/em-popup.c
+++ b/mail/em-popup.c
@@ -100,12 +100,6 @@ emp_target_free(EPopup *ep, EPopupTarget *t)
 
 		g_free(s->uri);
 		break; }
-	case EM_POPUP_TARGET_ATTACHMENTS: {
-		EMPopupTargetAttachments *s = (EMPopupTargetAttachments *)t;
-
-		g_slist_foreach(s->attachments, (GFunc)g_object_unref, NULL);
-		g_slist_free(s->attachments);
-		break; }
 	}
 
 	((EPopupClass *)emp_parent)->target_free(ep, t);
@@ -361,42 +355,6 @@ done:
 	return t;
 }
 
-/**
- * em_popup_target_new_attachments:
- * @emp:
- * @attachments: A list of EMsgComposerAttachment objects, reffed for
- * the list.  Will be unreff'd once finished with.
- *
- * Owns the list @attachments and their items after they're passed in.
- *
- * Return value:
- **/
-EMPopupTargetAttachments *
-em_popup_target_new_attachments(EMPopup *emp, GSList *attachments)
-{
-	EMPopupTargetAttachments *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_ATTACHMENTS, sizeof(*t));
-	guint32 mask = ~0;
-	int len = g_slist_length(attachments);
-
-	t->attachments = attachments;
-	if (len > 0)
-		mask &= ~ EM_POPUP_ATTACHMENTS_MANY;
-	if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) {
-
-		if (camel_content_type_is(((CamelDataWrapper *) ((EAttachment *) attachments->data)->body)->mime_type, "image", "*"))
-			mask &= ~ EM_POPUP_ATTACHMENTS_IMAGE;
-		if (CAMEL_IS_MIME_MESSAGE(camel_medium_get_content_object((CamelMedium *) ((EAttachment *) attachments->data)->body)))
-			mask &= ~EM_POPUP_ATTACHMENTS_MESSAGE;
-
-		mask &= ~ EM_POPUP_ATTACHMENTS_ONE;
-	}
-	if (len > 1)
-		mask &= ~ EM_POPUP_ATTACHMENTS_MULTIPLE;
-	t->target.mask = mask;
-
-	return t;
-}
-
 /* ********************************************************************** */
 
 static void
@@ -405,11 +363,7 @@ emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
 	EPopupTarget *t = ep->target;
 	CamelMimePart *part = NULL;
 
-	/* If it is of type EM_POPUP_TARGET_ATTACHMENTS, we can assume the length is one. */
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) t)->part;
+	part = ((EMPopupTargetPart *) t)->part;
 
 	em_utils_save_part(ep->target->widget, _("Save As..."), part);
 }
@@ -423,10 +377,7 @@ emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
 	unsigned int i=1;
 	CamelMimePart *part = NULL;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) t)->part;
+	part = ((EMPopupTargetPart *) t)->part;
 
 	if (!part)
 		return;
@@ -497,10 +448,7 @@ emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data)
 	CamelMimeMessage *message;
 	CamelMimePart *part;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) t)->part;
+	part = ((EMPopupTargetPart *) t)->part;
 
 	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
 	em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_SENDER, NULL);
@@ -513,10 +461,7 @@ emp_part_popup_reply_list (EPopup *ep, EPopupItem *item, void *data)
 	CamelMimeMessage *message;
 	CamelMimePart *part;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) t)->part;
+	part = ((EMPopupTargetPart *) t)->part;
 
 	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
 	em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_LIST, NULL);
@@ -529,10 +474,7 @@ emp_part_popup_reply_all (EPopup *ep, EPopupItem *item, void *data)
 	CamelMimeMessage *message;
 	CamelMimePart *part;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) t)->part;
+	part = ((EMPopupTargetPart *) t)->part;
 
 	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
 	em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_ALL, NULL);
@@ -545,10 +487,7 @@ emp_part_popup_forward (EPopup *ep, EPopupItem *item, void *data)
 	CamelMimeMessage *message;
 	CamelMimePart *part;
 
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) t)->part;
+	part = ((EMPopupTargetPart *) t)->part;
 
 	/* TODO: have a emfv specific override so we can get the parent folder uri */
 	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *) part);
@@ -566,17 +505,6 @@ static EMPopupItem emp_standard_object_popups[] = {
 	{ E_POPUP_ITEM, "20.part.00", N_("_Forward"), emp_part_popup_forward, NULL, "mail-forward", EM_POPUP_PART_MESSAGE },
 };
 
-static EMPopupItem emp_attachment_object_popups[] = {
-	{ E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "document-save-as", 0 },
-	{ E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_ATTACHMENTS_IMAGE },
-	{ E_POPUP_BAR, "05.attach", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE },
-	{ E_POPUP_ITEM, "05.attach.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "mail-reply-sender" , EM_POPUP_ATTACHMENTS_MESSAGE },
-	{ E_POPUP_ITEM, "05.attach.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE},
-	{ E_POPUP_ITEM, "05.attach.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "mail-reply-all", EM_POPUP_ATTACHMENTS_MESSAGE},
-	{ E_POPUP_BAR, "05.attach.10", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE },
-	{ E_POPUP_ITEM, "05.attach.15", N_("_Forward"), emp_part_popup_forward, NULL, "mail-forward", EM_POPUP_ATTACHMENTS_MESSAGE },
-};
-
 static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" };
 
 /* ********************************************************************** */
@@ -634,10 +562,7 @@ emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
 	EPopupTarget *target = ep->target;
 	CamelMimePart *part;
 
-	if (target->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) target)->part;
+	part = ((EMPopupTargetPart *) target)->part;
 
 	path = em_utils_temp_save_part(target->widget, part, TRUE);
 	if (path) {
@@ -705,10 +630,7 @@ emp_add_vcard (EPopup *ep, EPopupItem *item, void *data)
 	CamelStreamMem *mem;
 	
 
-	if (target->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) target)->part;
+	part = ((EMPopupTargetPart *) target)->part;
 
 	if (!part)
 		return;
@@ -762,25 +684,6 @@ emp_standard_menu_factory(EPopup *emp, void *data)
 		items = emp_standard_object_popups;
 		len = LEN(emp_standard_object_popups);
 		break; }
-	case EM_POPUP_TARGET_ATTACHMENTS: {
-		EMPopupTargetAttachments *t = (EMPopupTargetAttachments *)emp->target;
-		GSList *list = t->attachments;
-		EAttachment *attachment;
-
-		if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) {
-			items = NULL;
-			len = 0;
-			break;
-		}
-
-		/* Only one attachment selected */
-		attachment = list->data;
-		mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)attachment->body);
-		filename = camel_mime_part_get_filename(attachment->body);
-
-		items = emp_attachment_object_popups;
-		len = LEN(emp_attachment_object_popups);
-		break; }
 	default:
 		items = NULL;
 		len = 0;
@@ -942,21 +845,11 @@ static const EPopupHookTargetMask emph_folder_masks[] = {
 	{ NULL }
 };
 
-static const EPopupHookTargetMask emph_attachments_masks[] = {
-	{ "one", EM_POPUP_ATTACHMENTS_ONE },
-	{ "many", EM_POPUP_ATTACHMENTS_MANY },
-	{ "multiple", EM_POPUP_ATTACHMENTS_MULTIPLE },
-	{ "image", EM_POPUP_ATTACHMENTS_IMAGE },
-	{ "message", EM_POPUP_ATTACHMENTS_MESSAGE },
-	{ NULL }
-};
-
 static const EPopupHookTargetMap emph_targets[] = {
 	{ "select", EM_POPUP_TARGET_SELECT, emph_select_masks },
 	{ "uri", EM_POPUP_TARGET_URI, emph_uri_masks },
 	{ "part", EM_POPUP_TARGET_PART, emph_part_masks },
 	{ "folder", EM_POPUP_TARGET_FOLDER, emph_folder_masks },
-	{ "attachments", EM_POPUP_TARGET_ATTACHMENTS, emph_attachments_masks },
 	{ NULL }
 };
 
diff --git a/mail/em-popup.h b/mail/em-popup.h
index fbe41a3..77f80e5 100644
--- a/mail/em-popup.h
+++ b/mail/em-popup.h
@@ -43,7 +43,6 @@ typedef struct _EMPopupClass EMPopupClass;
  * @EM_POPUP_TARGET_URI: A URI.
  * @EM_POPUP_TARGET_PART: A CamelMimePart message part.
  * @EM_POPUP_TARGET_FOLDER: A folder URI.
- * @EM_POPUP_TARGET_ATTACHMENTS: A list of attachments.
  *
  * Defines the value of the targetid for all EMPopup target types.
  **/
@@ -51,8 +50,7 @@ enum _em_popup_target_t {
 	EM_POPUP_TARGET_SELECT,
 	EM_POPUP_TARGET_URI,
 	EM_POPUP_TARGET_PART,
-	EM_POPUP_TARGET_FOLDER,
-	EM_POPUP_TARGET_ATTACHMENTS,
+	EM_POPUP_TARGET_FOLDER
 };
 
 /**
@@ -158,26 +156,10 @@ enum _em_popup_target_folder_t {
 	EM_POPUP_FOLDER_NONSTATIC = 1<<6, /* Except static folders like Outbox.*/
 };
 
-/**
- * enum _em_popup_target_attachments_t - EMPopupTargetAttachments qualifiers.
- *
- * @EM_POPUP_ATTACHMENTS_ONE: There is one and only one attachment selected.
- * @EM_POPUP_ATTACHMENTS_MANY: There is one or more attachments selected.
- *
- **/
-enum _em_popup_target_attachments_t {
-	EM_POPUP_ATTACHMENTS_ONE = 1<<0, /* only 1 selected */
-	EM_POPUP_ATTACHMENTS_MANY = 1<<1, /* one or more selected */
-	EM_POPUP_ATTACHMENTS_MULTIPLE = 1<<2, /* More than 1 selected */
-	EM_POPUP_ATTACHMENTS_IMAGE = 1<<3, /* Image selected */
-	EM_POPUP_ATTACHMENTS_MESSAGE = 1<<4 /* Message selected */
-};
-
 typedef struct _EMPopupTargetSelect EMPopupTargetSelect;
 typedef struct _EMPopupTargetURI EMPopupTargetURI;
 typedef struct _EMPopupTargetPart EMPopupTargetPart;
 typedef struct _EMPopupTargetFolder EMPopupTargetFolder;
-typedef struct _EMPopupTargetAttachments EMPopupTargetAttachments;
 
 /**
  * struct _EMPopupTargetURI - An inline URI.
@@ -241,20 +223,6 @@ struct _EMPopupTargetFolder {
 	char *uri;
 };
 
-/**
- * struct _EMPopupTargetAttachments - A list of composer attachments.
- *
- * @target: Superclass.
- * @attachments: A GSList list of EMsgComposer attachments.
- *
- * This target is used to represent a selected list of attachments in
- * the message composer attachment area.
- **/
-struct _EMPopupTargetAttachments {
-	EPopupTarget target;
-	GSList *attachments;
-};
-
 typedef struct _EPopupItem EMPopupItem;
 
 /* The object */
@@ -276,7 +244,6 @@ EMPopupTargetURI *em_popup_target_new_uri(EMPopup *emp, const char *uri);
 EMPopupTargetSelect *em_popup_target_new_select(EMPopup *emp, struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids);
 EMPopupTargetPart *em_popup_target_new_part(EMPopup *emp, struct _CamelMimePart *part, const char *mime_type);
 EMPopupTargetFolder *em_popup_target_new_folder(EMPopup *emp, const char *uri, guint32 info_flags, guint32 popup_flags);
-EMPopupTargetAttachments *em_popup_target_new_attachments(EMPopup *emp, GSList *attachments);
 
 /* ********************************************************************** */
 
diff --git a/mail/mail-component.c b/mail/mail-component.c
index 3b67c43..556715d 100644
--- a/mail/mail-component.c
+++ b/mail/mail-component.c
@@ -92,6 +92,8 @@
 
 #include "e-util/e-non-intrusive-error-dialog.h"
 
+#include "e-attachment-handler-mail.h"
+
 #define MAILER_ERROR_LEVEL_KEY "/apps/evolution/mail/display/error_level"
 #define MAILER_ERROR_TIME_OUT_KEY "/apps/evolution/mail/display/error_timeout"
 
@@ -1259,6 +1261,9 @@ mail_component_class_init (MailComponentClass *class)
 	epv->setLineStatus	     = impl_setLineStatus;
 
 	mepv->test = impl_mail_test;
+
+	/* Register attachment handler types. */
+	e_attachment_handler_mail_get_type ();
 }
 
 static void
diff --git a/plugins/attachment-reminder/attachment-reminder.c b/plugins/attachment-reminder/attachment-reminder.c
index 15bac58..8634ce4 100644
--- a/plugins/attachment-reminder/attachment-reminder.c
+++ b/plugins/attachment-reminder/attachment-reminder.c
@@ -24,6 +24,7 @@
 #include <glib/gi18n.h>
 #include <string.h>
 
+#include <glade/glade-xml.h>
 #include <gconf/gconf-client.h>
 
 #include <e-util/e-config.h>
@@ -43,9 +44,10 @@
 
 #include <mail/em-utils.h>
 
-#include "widgets/misc/e-attachment-bar.h"
 #include "composer/e-msg-composer.h"
 #include "composer/e-composer-actions.h"
+#include "widgets/misc/e-attachment-view.h"
+#include "widgets/misc/e-attachment-store.h"
 
 #define GCONF_KEY_ATTACH_REMINDER_CLUES "/apps/evolution/mail/attachment_reminder_clues"
 #define SIGNATURE "-- "
@@ -182,12 +184,13 @@ check_for_attachment_clues (gchar *msg)
 static gboolean
 check_for_attachment (EMsgComposer *composer)
 {
-	EAttachmentBar* bar = (EAttachmentBar*)e_msg_composer_get_attachment_bar (composer);
+	EAttachmentView *view;
+	EAttachmentStore *store;
 
-	if (e_attachment_bar_get_num_attachments (bar))
-		return TRUE;
+	view = e_msg_composer_get_attachment_view (composer);
+	store = e_attachment_view_get_store (view);
 
-	return FALSE;
+	return (e_attachment_store_get_num_attachments (store) > 0);
 }
 
 static gchar*
diff --git a/plugins/import-ics-attachments/ChangeLog b/plugins/import-ics-attachments/ChangeLog
deleted file mode 100644
index 21a9408..0000000
--- a/plugins/import-ics-attachments/ChangeLog
+++ /dev/null
@@ -1,109 +0,0 @@
-2009-01-21  Milan Crha  <mcrha redhat com>
-
-	* Makefile.am: Use also EVOLUTION_CALENDAR_CFLAGS.
-
-2008-09-02  Sankar P  <psankar novell com>
-
-License Changes
-
-	* icsimporter.c:
-
-2008-08-12  Bharath Acharya  <abharath novell com>
-
-	* Makefile.am: Added necessary libraries to link to. Build break while 
-	compiling on Windows.
-
-2008-08-11  Matthew Barnes  <mbarnes redhat com>
-
-	** Fixes part of bug #546892
-
-	* icsimporter.c:
-	Prefer gtk_image_new_from_icon_name() over e_icon_factory_get_image().
-
-2008-04-17  Milan Crha  <mcrha redhat com>
-
-	** Part of fix for bug #526739
-
-	* icsimporter.c: Do not include gnome-vfs.
-
-2007-02-20  Paul Bolle  <pebolle tiscali nl>
-
-	** Fix for bug #517082
-
-	* icsimporter.c: (init_widgets): Fix small leak.
-
-2008-02-06  Milan Crha  <mcrha redhat com>
-
-	** Fix for bug #514622
-
-	* icsimporter.c: (dialog_close_cb): Drop this function.
-	* icsimporter.c: (init_widgets), (dialog_response_cb),
-	(ical_import_done): Do not call "close" on already closed dialog.
-
-2007-10-01  Milan Crha  <mcrha redhat com>
-
-	* icsimporter.c: (prepare_events), (prepare_tasks):
-	Really go through every component when removing one.
-
-2007-06-03  Srinivasa Ragavan  <sragavan novell com>
-
-	** Fix for version removal from Installed files from Gilles Dartiguelongue 
-
-	* Makefile.am:
-
-2007-05-12  Matthew Barnes  <mbarnes redhat com>
-
-	** Fixes part of bug #337616
-
-	* Makefile.am: Add "eplug" file to CLEANFILES.
-
-2007-03-27  Matthew Barnes  <mbarnes redhat com>
-
-	* icsimporter.c: Don't mix declarations and code (#405495).
-
-2007-03-20  Matthew Barnes  <mbarnes redhat com>
-
-	** Fixes part of bug #419524
-
-	* Include <glib/gi18n.h> instead of <libgnome/gnome-i18n.h>.
-
-2006-11-28  Parthasarathi Susarla <ajaysusarla gmail com>
-	
-	** Fix bug #348679
-
-	* icsimporter.c: (org_gnome_evolution_import_ics_attachment):
-	Do not access structure elements directly. Use the methods of the
-	class in the CamelDataWrapper Class
-	  
-2006-08-28  Kjartan Maraas  <kmaraas gnome org>
-
-	* org-gnome-evolution-mail-attachments-import-ics.eplug.xml: Mark
-	name and description for translation.
-
-2006-08-23  Srinivasa Ragavan  <sragavan novell com>
-
-	** Fix for bug #347248
-	
-	* icsimporter.c: (get_menu_type), (import_ics): Update the
-	em_utils_temp_save_part to use readwrite mode.
-
-2006-02-21  Chenthill Palanisamy  <pchenthill novell com>
-
-	reviewed by Veerapuram Varadhan	 <vvaradhan novell com>
-
-	Fixes a crash
-	* icsimporter.c: (org_gnome_evolution_import_ics_attachments):
-	If the number of attachments selected is not equal to one, just return;
-	
-
-2006-01-22  Harish Krishnaswamy  <kharish novell com>
-
-	* icsimporter.c (get_menu_type), (dialog_response_cb),
-	 (dialog_close_cb), (get_icalcomponent_from_file):
-	Fix twenty odd compiler warnings and style oddness.
-
-2006-01-17  Harish Krishnaswamy  <kharish novell com>
-
-	* import-ics-attachments : Initial commits. Plugin written and submitted by
-	Johnny Jacob <johnnyjacob gmail com>
-
diff --git a/plugins/import-ics-attachments/Makefile.am b/plugins/import-ics-attachments/Makefile.am
deleted file mode 100644
index baded42..0000000
--- a/plugins/import-ics-attachments/Makefile.am
+++ /dev/null
@@ -1,35 +0,0 @@
-INCLUDES =						\
-	-I$(top_srcdir)\
-	-I$(top_srcdir)/camel                           \
-	-I$(top_srcdir)/widgets/misc			\
-	$(EVOLUTION_MAIL_CFLAGS)			\
-	$(EVOLUTION_CALENDAR_CFLAGS)			\
-	-DEVOLUTION_DATADIR=\""$(datadir)"\"		\
-	-DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\"	\
-	-DEVOLUTION_ICONSDIR=\""$(imagesdir)"\"		\
-	-DEVOLUTION_IMAGES=\""$(imagesdir)"\"		\
-	-DEVOLUTION_BUTTONSDIR=\""$(buttonsdir)"\"	\
-	-DEVOLUTION_LOCALEDIR=\""$(localedir)"\"	\
-	-DEVOLUTION_UIDIR=\""$(evolutionuidir)"\"	\
-	-DCAMEL_PROVIDERDIR=\""$(camel_providerdir)"\"	\
-	-DPLUGINDIR=\""$(plugindir)"\"			\
-	-DPREFIX=\""$(prefix)"\"			
-
- EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-evolution-mail-attachments-import-ics.eplug
-plugin_LTLIBRARIES = liborg-gnome-evolution-mail-attachments-import-ics.la
-
-liborg_gnome_evolution_mail_attachments_import_ics_la_SOURCES = icsimporter.c
-liborg_gnome_evolution_mail_attachments_import_ics_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED)
-liborg_gnome_evolution_mail_attachments_import_ics_la_LIBADD = 			\
-	$(top_builddir)/e-util/libeutil.la		\
-	$(top_builddir)/mail/libevolution-mail.la	\
-	$(top_builddir)/calendar/common/libevolution-calendarprivate.la	\
-	$(EVOLUTION_CALENDAR_LIBS)	\
-	$(EVOLUTION_MAIL_LIBS)
-
-EXTRA_DIST = org-gnome-evolution-mail-attachments-import-ics.eplug.xml
-
-BUILT_SOURCES = $(plugin_DATA)
-CLEANFILES = $(BUILT_SOURCES)
diff --git a/plugins/import-ics-attachments/icsimporter.c b/plugins/import-ics-attachments/icsimporter.c
deleted file mode 100644
index fbd5e46..0000000
--- a/plugins/import-ics-attachments/icsimporter.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * 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/>  
- *
- *
- * Authors:
- *		Johnny Jacob <johnnyjacob gmail com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-#include <e-util/e-config.h>
-#include <e-util/e-popup.h>
-#include <mail/em-popup.h>
-#include <mail/em-menu.h>
-#include <mail/mail-ops.h>
-#include <mail/mail-mt.h>
-#include <mail/em-folder-view.h>
-#include <mail/em-format-html-display.h>
-#include <mail/em-utils.h>
-#include "e-attachment-bar.h"
-#include <camel/camel-vee-folder.h>
-#include "e-util/e-error.h"
-#include <libedataserverui/e-source-selector.h>
-#include <libecal/e-cal.h>
-#include <libical/icalvcal.h>
-#include <calendar/common/authentication.h>
-
-typedef struct {
-	ECal *client;
-	int source_type;
-	icalcomponent *icalcomp;
-	GtkWidget *window;
-	GtkWidget *selector;
-} ICalImporterData;
-
-
-static void import_ics (EPlugin *ep, EPopupTarget *t, void *data);
-static icalcomponent* get_icalcomponent_from_file(char *filename);
-static void prepare_events (icalcomponent *icalcomp, GList **vtodos);
-static void prepare_tasks (icalcomponent *icalcomp, GList *vtodos);
-static void import_items(ICalImporterData *icidata);
-static gboolean update_objects (ECal *client, icalcomponent *icalcomp);
-static void dialog_response_cb (GtkDialog *dialog, gint response_id, ICalImporterData *icidata);
-static void ical_import_done(ICalImporterData *icidata);
-static void init_widgets (char *path);
-static icalcomponent_kind get_menu_type (void *data);
-
-void org_gnome_evolution_import_ics_attachments (EPlugin *ep, EMPopupTargetAttachments *t);
-void org_gnome_evolution_import_ics_part (EPlugin *ep, EMPopupTargetPart *t);
-
-static void
-popup_free (EPopup *ep, GSList *items, void *data)
-{
-	g_slist_free (items);
-}
-
-static EPopupItem popup_calendar_items[] = {
-	{ E_POPUP_BAR, "25.display.00"},
-	{ E_POPUP_ITEM, "25.display.01", N_("_Import to Calendar"), (EPopupActivateFunc)import_ics, NULL, "stock_mail-import"}
-};
-
-static EPopupItem popup_tasks_items[] = {
-	{ E_POPUP_BAR, "25.display.00"},
-	{ E_POPUP_ITEM, "25.display.01", N_("_Import to Tasks"), (EPopupActivateFunc)import_ics, NULL, "stock_mail-import"}
-};
-
-
-void org_gnome_evolution_import_ics_attachments (EPlugin *ep, EMPopupTargetAttachments *t)
-{
-	GSList *menus = NULL;
-	icalcomponent_kind kind;
-	int len = 0;
-	int i = 0;
-	CamelContentType *type;
-
-	len = g_slist_length(t->attachments);
-
-	if (len != 1)
-		return;
-
-	type = camel_data_wrapper_get_mime_type_field (((CamelDataWrapper *) ((EAttachment *) t->attachments->data)->body));
-	if (type && camel_content_type_is(type, "text", "calendar")) {
-
-		kind = get_menu_type (t);
-
-		if (kind == ICAL_VTODO_COMPONENT ) {
-			for (i = 0; i < sizeof (popup_tasks_items) / sizeof (popup_tasks_items[0]); i++)
-				menus = g_slist_prepend (menus, &popup_tasks_items[i]);
-		} else if ( kind == ICAL_VEVENT_COMPONENT) {
-			for (i = 0; i < sizeof (popup_calendar_items) / sizeof (popup_calendar_items[0]); i++)
-				menus = g_slist_prepend (menus, &popup_calendar_items[i]);
-		}
-
-		e_popup_add_items (t->target.popup, menus, NULL, popup_free, t);
-	}
-}
-
-void org_gnome_evolution_import_ics_part (EPlugin*ep, EMPopupTargetPart *t)
-{
-	GSList *menus = NULL;
-	icalcomponent_kind kind;
-	int i = 0;
-
-	if (!camel_content_type_is(((CamelDataWrapper *) t->part)->mime_type, "text", "calendar"))
-		return;
-
-	kind = get_menu_type (t);
-
-	if (kind == ICAL_VTODO_COMPONENT ) {
-		for (i = 0; i < sizeof (popup_tasks_items) / sizeof (popup_tasks_items[0]); i++)
-			menus = g_slist_prepend (menus, &popup_tasks_items[i]);
-	} else if ( kind == ICAL_VEVENT_COMPONENT) {
-		for (i = 0; i < sizeof (popup_calendar_items) / sizeof (popup_calendar_items[0]); i++)
-			menus = g_slist_prepend (menus, &popup_calendar_items[i]);
-	}
-
-	e_popup_add_items (t->target.popup, menus, NULL, popup_free, t);
-}
-
-static icalcomponent_kind
-get_menu_type (void *data)
-{
-	CamelMimePart *part;
-	char *path;
-	icalcomponent *icalcomp, *subcomp;
-	icalcomponent_kind kind;
-	EPopupTarget *target = (EPopupTarget *) data;
-
-	if (target->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) target)->part;
-
-	path = em_utils_temp_save_part (NULL, part, FALSE);
-
-	icalcomp = get_icalcomponent_from_file (path);
-
-	subcomp = icalcomponent_get_inner(icalcomp);
-	kind = icalcomponent_isa (subcomp);
-
-	if (kind == ICAL_VTODO_COMPONENT ) {
-		return ICAL_VTODO_COMPONENT;
-	} else if ( kind == ICAL_VEVENT_COMPONENT) {
-		return ICAL_VEVENT_COMPONENT;
-	}
-	return ICAL_NO_COMPONENT;
-}
-
-static void
-import_ics (EPlugin *ep, EPopupTarget *t, void *data)
-{
-	CamelMimePart *part;
-	char *path;
-	EPopupTarget *target = (EPopupTarget *) data;
-
-	if (target->type == EM_POPUP_TARGET_ATTACHMENTS)
-		part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body;
-	else
-		part = ((EMPopupTargetPart *) target)->part;
-
-	path = em_utils_temp_save_part (NULL, part, FALSE);
-	init_widgets(path);
-}
-
-static void
-init_widgets(char *path)
-{
-
-	GtkWidget *vbox, *hbox, *dialog;
-	icalcomponent_kind kind;
-	icalcomponent *subcomp;
-	GtkWidget *selector, *label;
-	ESourceList *source_list;
-	ESource *primary;
-	GtkWidget *scrolled;
-	ICalImporterData *icidata = g_malloc0(sizeof(*icidata));
-	GtkWidget *icon, *button;
-	char *label_str = NULL;
-	char *markup;
-
-	g_return_if_fail ( path != NULL);
-	dialog = gtk_dialog_new_with_buttons (_("Import ICS"),
-						NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
-						GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-						NULL);
-	icidata->window = dialog;
-	g_signal_connect (dialog,
-			  "response",
-			  G_CALLBACK (dialog_response_cb),
-			  icidata);
-
-	vbox = GTK_DIALOG(dialog)->vbox;
-	hbox = gtk_hbox_new (FALSE, FALSE);
-	label = gtk_label_new(NULL);
-
-	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6);
-
-	icidata->icalcomp = get_icalcomponent_from_file (path);
-
-	subcomp = icalcomponent_get_inner(icidata->icalcomp);
-	kind = icalcomponent_isa (subcomp);
-
-	if (kind == ICAL_VTODO_COMPONENT ) {
-		e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_TODO, NULL);
-		label_str = _("Select Task List");
-		icidata->source_type = E_CAL_SOURCE_TYPE_TODO;
-	} else if ( kind == ICAL_VEVENT_COMPONENT) {
-		e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_EVENT, NULL);
-		label_str = _("Select Calendar");
-		icidata->source_type = E_CAL_SOURCE_TYPE_EVENT;
-	}
-
-	markup = g_markup_printf_escaped ("<b>%s</b>", label_str);
-	gtk_label_set_markup (GTK_LABEL (label), markup);
-	g_free (markup);
-	hbox = gtk_hbox_new (FALSE, FALSE);
-	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6);
-	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 6);
-
-	selector = e_source_selector_new (source_list);
-	e_source_selector_show_selection (E_SOURCE_SELECTOR (selector), FALSE);
-	scrolled = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_container_add((GtkContainer *)scrolled, selector);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN);
-	hbox = gtk_hbox_new (FALSE, FALSE);
-	gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 6);
-	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 6);
-	icidata->selector = selector;
-
-
-	/* FIXME What if no sources? */
-	primary = e_source_list_peek_source_any (source_list);
-	e_source_selector_set_primary_selection (E_SOURCE_SELECTOR (selector), primary);
-
-	g_object_unref (source_list);
-	hbox = gtk_hbox_new (FALSE, FALSE);
-	icon = gtk_image_new_from_icon_name (
-		"stock_mail-import", GTK_ICON_SIZE_MENU);
-	gtk_box_pack_start (GTK_BOX(hbox), icon, FALSE, FALSE, 6);
-	label = gtk_label_new_with_mnemonic (_("_Import"));
-	gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 6);
-	gtk_widget_show(label);
-	button = gtk_button_new ();
-	gtk_container_add (GTK_CONTAINER (button), hbox);
-	gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
-	gtk_widget_grab_focus (button);
-
-	gtk_window_set_default_size (GTK_WINDOW (dialog), 210,340);
-	gtk_widget_show_all (dialog);
-	gtk_dialog_run (GTK_DIALOG (dialog));
-	gtk_widget_destroy (dialog);
-}
-
-static void
-dialog_response_cb (GtkDialog *dialog, gint response_id, ICalImporterData *icidata)
-{
-	switch (response_id) {
-		case GTK_RESPONSE_OK :
-			import_items(icidata);
-		break;
-
-		case GTK_RESPONSE_CANCEL :
-		case GTK_RESPONSE_DELETE_EVENT :
-		break;
-	}
-}
-
-/* This removes all components except VEVENTs and VTIMEZONEs from the toplevel */
-static void
-prepare_events (icalcomponent *icalcomp, GList **vtodos)
-{
-	icalcomponent *subcomp;
-	icalcompiter iter;
-
-	if (vtodos)
-		*vtodos = NULL;
-
-	iter = icalcomponent_begin_component (icalcomp, ICAL_ANY_COMPONENT);
-	while ((subcomp = icalcompiter_deref (&iter)) != NULL) {
-		icalcomponent_kind child_kind = icalcomponent_isa (subcomp);
-		if (child_kind != ICAL_VEVENT_COMPONENT
-		    && child_kind != ICAL_VTIMEZONE_COMPONENT) {
-
-			icalcompiter_next (&iter);
-
-			icalcomponent_remove_component (icalcomp, subcomp);
-			if (child_kind == ICAL_VTODO_COMPONENT && vtodos)
-				*vtodos = g_list_prepend (*vtodos, subcomp);
-			else
-                                icalcomponent_free (subcomp);
-		} else {
-			icalcompiter_next (&iter);
-		}
-	}
-}
-
-/* This removes all components except VTODOs and VTIMEZONEs from the toplevel
-   icalcomponent, and adds the given list of VTODO components. The list is
-   freed afterwards. */
-static void
-prepare_tasks (icalcomponent *icalcomp, GList *vtodos)
-{
-	icalcomponent *subcomp;
-	GList *elem;
-	icalcompiter iter;
-
-	iter = icalcomponent_begin_component (icalcomp, ICAL_ANY_COMPONENT);
-	while ((subcomp = icalcompiter_deref (&iter)) != NULL) {
-		icalcomponent_kind child_kind = icalcomponent_isa (subcomp);
-		if (child_kind != ICAL_VTODO_COMPONENT
-		    && child_kind != ICAL_VTIMEZONE_COMPONENT) {
-			icalcompiter_next (&iter);
-			icalcomponent_remove_component (icalcomp, subcomp);
-			icalcomponent_free (subcomp);
-		} else {
-			icalcompiter_next (&iter);
-		}
-	}
-
-	for (elem = vtodos; elem; elem = elem->next) {
-		icalcomponent_add_component (icalcomp, elem->data);
-	}
-	g_list_free (vtodos);
-}
-
-static void
-import_items(ICalImporterData *icidata)
-{
-	ESource *source;
-	g_return_if_fail (icidata != NULL);
-
-	source = e_source_selector_peek_primary_selection ((ESourceSelector *)icidata->selector);
-	g_return_if_fail ( source != NULL);
-
-	icidata->client = auth_new_cal_from_source (source, icidata->source_type);
-	e_cal_open (icidata->client, FALSE, NULL);
-
-	switch (icidata->source_type) {
-	case E_CAL_SOURCE_TYPE_EVENT:
-		prepare_events (icidata->icalcomp, NULL);
-		if (!update_objects (icidata->client, icidata->icalcomp))
-			/* FIXME: e_error ... */;
-		break;
-	case E_CAL_SOURCE_TYPE_TODO:
-		prepare_tasks (icidata->icalcomp, NULL);
-		if (!update_objects (icidata->client, icidata->icalcomp))
-			/* FIXME: e_error ... */;
-		break;
-	default:
-		g_assert_not_reached ();
-	}
-	ical_import_done (icidata);
-}
-
-static gboolean
-update_objects (ECal *client, icalcomponent *icalcomp)
-{
-	icalcomponent_kind kind;
-	icalcomponent *vcal;
-	gboolean success = TRUE;
-
-	kind = icalcomponent_isa (icalcomp);
-
-	if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT) {
-		vcal = e_cal_util_new_top_level ();
-		if (icalcomponent_get_method (icalcomp) == ICAL_METHOD_CANCEL)
-			icalcomponent_set_method (vcal, ICAL_METHOD_CANCEL);
-		else
-			icalcomponent_set_method (vcal, ICAL_METHOD_PUBLISH);
-		icalcomponent_add_component (vcal, icalcomponent_new_clone (icalcomp));
-	} else if (kind == ICAL_VCALENDAR_COMPONENT) {
-		vcal = icalcomponent_new_clone (icalcomp);
-		if (!icalcomponent_get_first_property (vcal, ICAL_METHOD_PROPERTY))
-			icalcomponent_set_method (vcal, ICAL_METHOD_PUBLISH);
-	} else
-		return FALSE;
-
-	if (!e_cal_receive_objects (client, vcal, NULL))
-		success = FALSE;
-
-	icalcomponent_free (vcal);
-
-	return success;
-}
-
-static void
-ical_import_done(ICalImporterData *icidata)
-{
-	g_object_unref (icidata->client);
-	icalcomponent_free (icidata->icalcomp);
-	g_free (icidata);
-}
-
-static icalcomponent *
-get_icalcomponent_from_file(char *filename)
-{
-	char *contents;
-	icalcomponent *icalcomp;
-
-	g_return_val_if_fail (filename != NULL, NULL);
-
-	if (!g_file_get_contents (filename, &contents, NULL, NULL)) {
-		g_free (filename);
-		return NULL;
-	}
-	g_free (filename);
-
-	icalcomp = e_cal_util_parse_ics_string (contents);
-	g_free (contents);
-
-	if (icalcomp) {
-		return icalcomp;
-	}
-	return NULL;
-}
diff --git a/plugins/import-ics-attachments/org-gnome-evolution-mail-attachments-import-ics.eplug.xml b/plugins/import-ics-attachments/org-gnome-evolution-mail-attachments-import-ics.eplug.xml
deleted file mode 100644
index 745d0fb..0000000
--- a/plugins/import-ics-attachments/org-gnome-evolution-mail-attachments-import-ics.eplug.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
-  <!-- the path to the shared library -->
-  <e-plugin
-    id="org.gnome.evolution.mail.attachments.import.ics"
-    type="shlib"
-    location="@PLUGINDIR@/liborg-gnome-evolution-mail-attachments-import-ics SOEXT@"
-    _name="Import to Calendar">
-    
-    <author name="Johnny Jacob" email="johnnyjacob gmail com"/>
-    <_description>Imports ICS attachments to calendar.</_description>
-
-    	<hook class="org.gnome.evolution.mail.popup:1.0">
-		<menu id="org.gnome.evolution.mail.formathtmldisplay.popup" target="part" factory="org_gnome_evolution_import_ics_part">
-		</menu>
-	</hook>
-    	<hook class="org.gnome.evolution.mail.popup:1.0">
-		<menu id="org.gnome.evolution.mail.attachments.popup" target="attachments" factory="org_gnome_evolution_import_ics_attachments">
-		</menu>
-	</hook>
-	<hook class="org.gnome.evolution.mail.popup:1.0">
-		<menu target="attachments" id="org.gnome.evolution.mail.composer.attachmentbar.popup" factory="org_gnome_evolution_import_ics_attachments">
-		</menu>
-	</hook>
-  </e-plugin>
-</e-plugin-list>
diff --git a/plugins/save-attachments/ChangeLog b/plugins/save-attachments/ChangeLog
deleted file mode 100644
index 9980fdf..0000000
--- a/plugins/save-attachments/ChangeLog
+++ /dev/null
@@ -1,102 +0,0 @@
-2009-01-28  Tor Lillqvist  <tml novell com>
-
-	* Makefile.am: Use -no-undefined and link with more libs on
-	Windows.
-
-2008-09-19  Sankar P  <psankar novell com>
-
-License Changes
-
-	* save-attachments.c:
-
-2007-12-20  Matthew Barnes  <mbarnes redhat com>
-
-	** Fixes part of bug #362638
-
-	* save-attachments.c:
-	Use the new MailMsg API for messages.
-
-2007-04-02  Sankar P  <psankar novell com>
-
-	* Committed on behalf of Gilles Dartiguelongue <dartigug esiee fr>
-
-	* org-gnome-save-attachments.eplug.xml:
-	Cleanup. 
-	Fixes part of #301149
-
-2007-03-29  Matthew Barnes  <mbarnes redhat com>
-
-	* save-attachments.c:
-	Evolution requires GLib 2.10 now; remove dead backward-compatibility
-	code for GLib < 2.8 (#418971).
-
-2007-01-27  Nickolay V. Shmyrev  <nshmyrev yandex ru>
-
-	* save-attachments.c: (save_got_message):
-	mark strings as translatable. See bug #399381 for details.
-
-2006-07-07  Hiroyuki Ikezoe  <poincare ikezoe net>
-
-	** Fixes bug #341369
-	* save-attachments.c: fixing a memory leak.
-
-2006-02-28  Shi Pu <shi pu sun com>
-
-	** Fixes #323853
-
-	* save-attachments.c: (save_response), (entry_changed),
-	(save_got_message):
-	replace GnomeFileEntry by GtkFileChooserButton.
-
-2005-12-17  Tor Lillqvist  <tml novell com>
-
-	* save-attachments.c (entry_changed): Use GLib API to manipulate
-	pathname.
-
-2005-05-16  Not Zed  <NotZed Ximian com>
-
-	* save-attachments.c: moved e-error to e-util
-
-2005-05-13  Rodney Dawes  <dobey novell com>
-
-	* org-gnome-save-attachments.xml: Update for new menu layout
-
-2005-05-12  Not Zed  <NotZed Ximian com>
-
-	* Makefile.am: setup built_sources/cleanfiles.
-
-2005-05-06  Not Zed  <NotZed Ximian com>
-
-	* Makefile.am: 
-	* org-gnome-save-attachments.eplug.xml: s/.in/.xml/ & i18n.
-
-2005-02-24  Björn Torkelsson  <torkel acc umu se>
-
-	* org-gnome-save-attachments.eplug.in: Removed plugin from the
-	name.
-	Fixed description and added author
-
-2005-02-07  Not Zed  <NotZed Ximian com>
-
-	* save-attachments.c (save_part): fix the access() call test.
-
-2005-01-04  Philip Van Hoof  <pvanhoof gnome org>
-
-	* save-attachments.c: Use standard error messages
-
-2004-12-27  Philip Van Hoof  <pvanhoof gnome org>
-
-	* save-attachments.c: Warning when overwriting file
-
-2004-11-01  JP Rosevear  <jpr novell com>
-
-	* Makefile.am: dist xml menu file
-
-2004-11-01  JP Rosevear  <jpr novell com>
-
-	* Makefile.am: dist .eplug.in file
-
-2004-10-20  Not Zed  <NotZed Ximian com>
-
-	* Imported save-attachments example plugin.
-
diff --git a/plugins/save-attachments/Makefile.am b/plugins/save-attachments/Makefile.am
deleted file mode 100644
index 05c724a..0000000
--- a/plugins/save-attachments/Makefile.am
+++ /dev/null
@@ -1,31 +0,0 @@
-if OS_WIN32
-NO_UNDEFINED_REQUIRED_LIBS =				\
-	$(top_builddir)/mail/libevolution-mail.la	\
-	$(EVOLUTION_MAIL_LIBS)				\
-	$(GNOME_PLATFORM_LIBS)				\
-	$(top_builddir)/e-util/libeutil.la
-endif
-
-INCLUDES =						\
-	-I$(top_srcdir)					\
-	$(EVOLUTION_MAIL_CFLAGS)
-
- EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-save-attachments.eplug org-gnome-save-attachments.xml
-plugin_LTLIBRARIES = liborg-gnome-save-attachments.la
-
-liborg_gnome_save_attachments_la_SOURCES = save-attachments.c
-liborg_gnome_save_attachments_la_LDFLAGS = -module \
-	-avoid-version $(NO_UNDEFINED)
-
-liborg_gnome_save_attachments_la_LIBADD =	\
-	$(NO_UNDEFINED_REQUIRED_LIBS)
-
-
-EXTRA_DIST = 					\
-	org-gnome-save-attachments.eplug.xml	\
-	org-gnome-save-attachments.xml
-
-BUILT_SOURCES = org-gnome-save-attachments.eplug
-CLEANFILES = $(BUILT_SOURCES)
diff --git a/plugins/save-attachments/org-gnome-save-attachments.eplug.xml b/plugins/save-attachments/org-gnome-save-attachments.eplug.xml
deleted file mode 100644
index d51b341..0000000
--- a/plugins/save-attachments/org-gnome-save-attachments.eplug.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
-  <!-- the path to the shared library -->
-  <e-plugin
-    id="org.gnome.plugin.attachments.save"
-    type="shlib"
-    location="@PLUGINDIR@/liborg-gnome-save-attachments SOEXT@"
-    _name="Save attachments">
-    
-    <author name="Not Zed" email="NotZed Ximian com"/>
-    <_description>A plugin for saving all attachments or parts of a message at once.</_description>
-
-    <hook class="org.gnome.evolution.mail.bonobomenu:1.0">
-      <menu id="org.gnome.evolution.mail.browser" target="select">
-	<!-- the path to the bonobo menu description -->
-	<ui file="@PLUGINDIR@/org-gnome-save-attachments.xml"/>
-	<item
-	  type="item"
-	  verb="EPSASaveAttachments"
-	  path="/commands/EPSASaveAttachments"
-	  enable="one"
-	  activate="org_gnome_save_attachments_save"/>
-      </menu>
-    </hook>
-  </e-plugin>
-</e-plugin-list>
diff --git a/plugins/save-attachments/org-gnome-save-attachments.xml b/plugins/save-attachments/org-gnome-save-attachments.xml
deleted file mode 100644
index 75f4aef..0000000
--- a/plugins/save-attachments/org-gnome-save-attachments.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<Root>
-  <commands>
-    <cmd name="EPSASaveAttachments" _label="Save Attachments..."
-      _tip="Save all attachments"
-      pixtype="stock" pixname="Save"/>
-  </commands>
-
-  <menu>
-<!--
-    <placeholder name="MessagePlaceholder">
-      <submenu name="Message">
-        <placeholder name="MailMessageActions">
-	  <separator f="" name="emaillist5"/>
-	  <menuitem name="EPSASaveAttachments" verb=""/>
-        </placeholder>
-   </submenu>
-    </placeholder>
--->
-  </menu>
-</Root>
diff --git a/plugins/save-attachments/save-attachments.c b/plugins/save-attachments/save-attachments.c
deleted file mode 100644
index c48711c..0000000
--- a/plugins/save-attachments/save-attachments.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * 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/>  
- *
- *
- * Authors:
- *		Michael Zucchi <notzed ximian com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-/* This is prototype code only, this may, or may not, use undocumented
- * unstable or private internal function calls. */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-#include <glib/gstdio.h>
-
-#include <camel/camel-folder.h>
-#include <camel/camel-exception.h>
-#include <camel/camel-mime-message.h>
-#include <camel/camel-multipart.h>
-#include <camel/camel-utf8.h>
-
-#include "e-util/e-error.h"
-
-#include "mail/em-menu.h"
-#include "mail/em-utils.h"
-
-/* these are sort of mail-internal */
-#include "mail/mail-mt.h"
-#include "mail/mail-ops.h"
-
-void org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target);
-
-struct _save_data {
-	CamelFolder *folder;
-	char *uid;
-	CamelMimeMessage *msg;
-
-	char *path;
-	char *base;
-
-	GtkWidget *entry;
-	GtkWidget *tree;
-	GtkTreeStore *model;
-};
-
-static void
-free_data(struct _save_data *data)
-{
-	if (data->msg)
-		camel_object_unref(data->msg);
-	g_free(data->base);
-	g_free(data->path);
-	g_free(data->uid);
-	camel_object_unref(data->folder);
-	if (data->model)
-		g_object_unref(data->model);
-	g_free(data);
-}
-
-static char *
-clean_name(const char *s)
-{
-	GString *out = g_string_new("");
-	int c;
-	char *r;
-
-	while ( (c = camel_utf8_getc((const unsigned char **)&s)) ) {
-		if (!g_unichar_isprint(c) || ( c < 0x7f && strchr(" /'\"`&();|<>$%{}!", c )))
-			c = '_';
-		g_string_append_u(out, c);
-	}
-
-	r = g_strdup(out->str);
-	g_string_free(out, TRUE);
-
-	return r;
-}
-
-static void
-fill_model_rec(CamelMimeMessage *msg, CamelMimePart *part, GtkTreeStore *model, GtkTreeIter *parent, GString *name)
-{
-	CamelDataWrapper *containee;
-	int parts, i;
-	char *type;
-	GtkTreeIter iter;
-	int len = name->len;
-	CamelContentType *mime;
-
-	containee = camel_medium_get_content_object((CamelMedium *)part);
-	if (containee == NULL)
-		return;
-
-	mime = ((CamelDataWrapper *)containee)->mime_type;
-	type = camel_content_type_simple(mime);
-
-	if (CAMEL_IS_MULTIPART(containee)) {
-		gtk_tree_store_append(model, &iter, parent);
-		g_string_append_printf(name, ".multipart");
-		gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1);
-
-		parts = camel_multipart_get_number((CamelMultipart *)containee);
-		for (i = 0; i < parts; i++) {
-			CamelMimePart *mpart = camel_multipart_get_part((CamelMultipart *)containee, i);
-
-			g_string_truncate(name, len);
-			g_string_append_printf(name, ".%d", i);
-			fill_model_rec(msg, mpart, model, &iter, name);
-		}
-	} else if (CAMEL_IS_MIME_MESSAGE(containee)) {
-		gtk_tree_store_append(model, &iter, parent);
-		g_string_append_printf(name, ".msg");
-		gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1);
-		fill_model_rec(msg, (CamelMimePart *)containee, model, &iter, name);
-	} else {
-		char *filename = NULL;
-		const char *ext = NULL, *tmp;
-		int save = FALSE;
-
-		gtk_tree_store_append(model, &iter, parent);
-		tmp = camel_mime_part_get_filename(part);
-		if (tmp) {
-			filename = clean_name(tmp);
-			ext = strrchr(filename, '.');
-		}
-		tmp = camel_mime_part_get_disposition(part);
-		if (tmp && !strcmp(tmp, "attachment"))
-			save = TRUE;
-
-		if (camel_content_type_is(mime, "text", "*")) {
-			if (ext == NULL) {
-				if ((ext = mime->subtype) == NULL || !strcmp(ext, "plain"))
-					ext = "text";
-			}
-		} else if (camel_content_type_is(mime, "image", "*")) {
-			if (ext == NULL) {
-				if ((ext = mime->subtype) == NULL)
-					ext = "image";
-			}
-			save = TRUE;
-		}
-
-		g_string_append_printf(name, ".%s", ext);
-		gtk_tree_store_set(model, &iter, 0, save, 1, type, 2, filename?filename:name->str, 3, filename?NULL:name->str, 4, part, -1);
-		g_free(filename);
-	}
-	g_free(type);
-
-	g_string_truncate(name, len);
-}
-
-static void
-fill_model(CamelMimeMessage *msg, GtkTreeStore *model)
-{
-	GString *name = g_string_new("");
-	GtkTreeIter iter;
-
-	gtk_tree_store_append(model, &iter, NULL);
-	gtk_tree_store_set(model, &iter, 0, FALSE, 1, "message/rfc822", 2, ".msg", 3, ".msg", 4, msg, -1);
-	fill_model_rec(msg, (CamelMimePart *)msg, model, &iter, name);
-	g_string_free(name, TRUE);
-}
-
-static gboolean
-save_part(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d)
-{
-	struct _save_data *data = d;
-	char *filename, *ext, *save;
-	CamelMimePart *part;
-	gboolean doit;
-
-	/* TODO: check for existing file */
-
-	gtk_tree_model_get(model, iter, 0, &doit, -1);
-	if (!doit)
-		return FALSE;
-
-	gtk_tree_model_get(model, iter, 2, &filename, 3, &ext, 4, &part, -1);
-	if (ext == NULL)
-		save = g_build_filename(data->path, filename, NULL);
-	else
-		save = g_strdup_printf("%s%s", data->base, ext);
-
-	/* FIXME: if part == data->msg then we need to save this
-	 * differently, not using the envelope MimePart */
-
-	/*
-	 * The underlying em_utils_save_part_to_file ain't using gnome-vfs. Therefor
-	 * the POSIX access-call should suffice for checking the file existence.
-	 */
-
-	if (g_access(save, F_OK) == 0)
-		doit = e_error_run(NULL, E_ERROR_ASK_FILE_EXISTS_OVERWRITE, save, NULL) == GTK_RESPONSE_OK;
-
-	if (doit)
-		em_utils_save_part_to_file(NULL, save, part);
-
-	g_free(ext);
-	g_free(filename);
-
-	return FALSE;
-}
-
-static void
-save_response(GtkWidget *d, int id, struct _save_data *data)
-{
-	if (id == GTK_RESPONSE_OK) {
-		char *tmp;
-
-		data->base = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (data->entry));
-		data->path = g_strdup(data->base);
-		tmp = strrchr(data->path, '/');
-		if (tmp)
-			*tmp = 0;
-		gtk_tree_model_foreach((GtkTreeModel *)data->model, save_part, data);
-	}
-
-	gtk_widget_destroy(d);
-	free_data(data);
-}
-
-static gboolean
-entry_changed_update(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d)
-{
-	const char *name = d;
-	char *filename, *ext;
-
-	gtk_tree_model_get(model, iter, 3, &ext, -1);
-	if (ext) {
-		filename = g_strdup_printf("%s%s", name, ext);
-		gtk_tree_store_set((GtkTreeStore *)model, iter, 2, filename, -1);
-		g_free(filename);
-		g_free(ext);
-	}
-
-	return FALSE;
-}
-
-static void
-entry_changed(GtkWidget *entry, struct _save_data *data)
-{
-	char *path;
-	char *basename = NULL;
-	const char *file;
-
-	path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (data->entry));
-	if (path == NULL
-	    || G_IS_DIR_SEPARATOR (path[strlen(path)-1])
-	    || (basename = g_path_get_basename(path)) == NULL
-	    || (basename[0] == '.' && basename[1] == '\0')
-	    || (g_file_test(path, G_FILE_TEST_IS_DIR)))
-		file = "attachment";
-	else
-		file = basename;
-
-	gtk_tree_model_foreach((GtkTreeModel *)data->model, entry_changed_update, (void *)file);
-	g_free(path);
-	g_free(basename);
-}
-
-static void
-toggle_changed(GtkWidget *entry, const char *spath, struct _save_data *data)
-{
-        GtkTreePath *path;
-        GtkTreeIter iter;
-
-        path = gtk_tree_path_new_from_string(spath);
-        if (gtk_tree_model_get_iter((GtkTreeModel *)data->model, &iter, path)) {
-		gboolean on;
-
-                gtk_tree_model_get((GtkTreeModel *)data->model, &iter, 0, &on, -1);
-		gtk_tree_store_set(data->model, &iter, 0, !on, -1);
-        }
-
-        gtk_tree_path_free (path);
-}
-
-static void
-save_got_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *d)
-{
-	struct _save_data *data = d;
-	GtkDialog *dialog;
-	GtkWidget *w, *tree;
-	GtkTreeStore *model;
-	GtkCellRenderer *renderer;
-
-	/* not found, the mailer will show an error box for this */
-	if (msg == NULL) {
-		free_data(data);
-		return;
-	}
-
-	data->msg = msg;
-	camel_object_ref(msg);
-
-	dialog = (GtkDialog *)gtk_dialog_new_with_buttons(_("Save attachments"),
-							  NULL, /* target->parent? */
-							  0,
-							  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-							  GTK_STOCK_SAVE, GTK_RESPONSE_OK,
-							  NULL);
-	w = gtk_file_chooser_button_new (_("Select save base name"), GTK_FILE_CHOOSER_ACTION_OPEN);
-	data->entry = w;
-	g_object_set(w, "filechooser_action", GTK_FILE_CHOOSER_ACTION_SAVE, NULL);
-	gtk_widget_show(w);
-	gtk_box_pack_start((GtkBox *)dialog->vbox, w, FALSE, TRUE, 6);
-
-	g_signal_connect(GTK_FILE_CHOOSER_BUTTON (w), "selection-changed", G_CALLBACK(entry_changed), data);
-
-	model = gtk_tree_store_new(5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
-	data->model = model;
-	fill_model(msg, model);
-
-	tree = gtk_tree_view_new_with_model((GtkTreeModel *)model);
-	data->tree = tree;
-	gtk_widget_show(tree);
-	gtk_tree_view_expand_all((GtkTreeView *)tree);
-
-	renderer = gtk_cell_renderer_text_new();
-	gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
-						    _("MIME Type"), renderer, "text", 1, NULL);
-	gtk_tree_view_set_expander_column((GtkTreeView *)tree, gtk_tree_view_get_column((GtkTreeView *)tree, 0));
-
-	renderer = gtk_cell_renderer_toggle_new();
-	g_object_set(renderer, "activatable", TRUE, NULL);
-	g_signal_connect(renderer, "toggled", G_CALLBACK(toggle_changed), data);
-
-	gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
-						    _("Save"), renderer, "active", 0, NULL);
-	renderer = gtk_cell_renderer_text_new();
-	gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
-						    _("Name"), renderer, "text", 2, NULL);
-
-	w = g_object_new(gtk_frame_get_type(),
-			 "shadow_type", GTK_SHADOW_NONE,
-			 "label_widget", g_object_new(gtk_label_get_type(),
-						      "label", "<span weight=\"bold\">Attachments</span>",
-						      "use_markup", TRUE,
-						      "xalign", 0.0, NULL),
-			 "child", g_object_new(gtk_alignment_get_type(),
-					       "left_padding", 12,
-					       "top_padding", 6,
-					       "child", g_object_new(gtk_scrolled_window_get_type(),
-								     "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
-								     "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
-								     "shadow_type", GTK_SHADOW_IN,
-								     "child", tree,
-								     NULL),
-					       NULL),
-			 NULL);
-	gtk_widget_show_all(w);
-
-	gtk_box_pack_start((GtkBox *)dialog->vbox, w, TRUE, TRUE, 0);
-	g_signal_connect(dialog, "response", G_CALLBACK(save_response), data);
-	gtk_window_set_default_size((GtkWindow *)dialog, 500, 500);
-	gtk_widget_show((GtkWidget *)dialog);
-}
-
-void
-org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target)
-{
-	struct _save_data *data;
-
-	if (target->uids->len != 1)
-		return;
-
-	data = g_malloc0(sizeof(*data));
-	data->folder = target->folder;
-	camel_object_ref(data->folder);
-	data->uid = g_strdup(target->uids->pdata[0]);
-
-	mail_get_message(data->folder, data->uid, save_got_message, data, mail_msg_unordered_push);
-}
diff --git a/shell/apps_evolution_shell.schemas.in b/shell/apps_evolution_shell.schemas.in
index 24172f2..c5c6276 100644
--- a/shell/apps_evolution_shell.schemas.in
+++ b/shell/apps_evolution_shell.schemas.in
@@ -41,7 +41,35 @@
       </locale>
     </schema>
 
- <!-- Offline Mode -->
+    <!-- Initial attachment view (icon or list) -->
+
+    <schema>
+      <key>/schemas/apps/evolution/shell/attachment_view</key>
+      <applyto>/apps/evolution/shell/attachment_view</applyto>
+      <owner>evolution</owner>
+      <type>int</type>
+      <default>0</default>
+      <locale name="C">
+        <short>Initial attachment view</short>
+        <long>Initial view for attachment bar widgets.
+        "0" is Icon View, "1" is List View.</long>
+      </locale>
+    </schema>
+
+    <!-- Initial GtkFileChooser Folder -->
+
+    <schema>
+      <key>/schemas/apps/evolution/shell/current_folder</key>
+      <applyto>/apps/evolution/shell/current-folder</applyto>
+      <owner>evolution</owner>
+      <type>string</type>
+      <locale name="C">
+        <short>Initial file chooser folder</short>
+        <long>Initial folder for GtkFileChooser dialogs.</long>
+      </locale>
+    </schema>
+
+    <!-- Offline Mode -->
 
     <schema>
       <key>/schemas/apps/evolution/shell/start_offline</key>
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index 95acd8b..3befe12 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -37,7 +37,15 @@ widgetsinclude_HEADERS =			\
 	e-account-combo-box.h			\
 	e-activity-handler.h			\
 	e-attachment.h				\
-	e-attachment-bar.h			\
+	e-attachment-button.h			\
+	e-attachment-dialog.h			\
+	e-attachment-handler.h			\
+	e-attachment-handler-image.h		\
+	e-attachment-icon-view.h		\
+	e-attachment-paned.h			\
+	e-attachment-store.h			\
+	e-attachment-tree-view.h		\
+	e-attachment-view.h			\
 	e-spinner.c				\
 	e-spinner.h				\
 	e-calendar.h				\
@@ -51,7 +59,6 @@ widgetsinclude_HEADERS =			\
 	e-combo-button.h			\
 	e-dateedit.h				\
 	e-dropdown-button.h			\
-	e-expander.h				\
 	e-icon-entry.h				\
 	e-image-chooser.h			\
 	e-info-label.h				\
@@ -88,7 +95,15 @@ libemiscwidgets_la_SOURCES =			\
 	e-activity-handler.c			\
 	e-calendar.c				\
 	e-attachment.c				\
-	e-attachment-bar.c			\
+	e-attachment-button.c			\
+	e-attachment-dialog.c			\
+	e-attachment-handler.c			\
+	e-attachment-handler-image.c		\
+	e-attachment-icon-view.c		\
+	e-attachment-paned.c			\
+	e-attachment-store.c			\
+	e-attachment-tree-view.c		\
+	e-attachment-view.c			\
 	e-calendar-item.c			\
 	e-cell-date-edit.c			\
 	e-cell-percent.c			\
@@ -99,7 +114,6 @@ libemiscwidgets_la_SOURCES =			\
 	e-combo-button.c			\
 	e-dateedit.c				\
 	e-dropdown-button.c			\
-	e-expander.c				\
 	e-icon-entry.c				\
 	e-image-chooser.c			\
 	e-info-label.c				\
diff --git a/widgets/misc/e-attachment-bar.c b/widgets/misc/e-attachment-bar.c
deleted file mode 100644
index 0210d21..0000000
--- a/widgets/misc/e-attachment-bar.c
+++ /dev/null
@@ -1,1504 +0,0 @@
-/*
- * 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/>  
- *
- *
- * Authors:
- *		Ettore Perazzoli <ettore ximian com>
- *      Jeffrey Stedfast <fejj ximian com>
- *	    Srinivasa Ragavan <sragavan novell com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <gtk/gtk.h>
-#include <gio/gio.h>
-#include <glade/glade.h>
-#include <gconf/gconf.h>
-#include <gconf/gconf-client.h>
-#include <gdk/gdkkeysyms.h>
-#include <glib/gi18n.h>
-#include <glib/gstdio.h>
-#include <libgnome/libgnome.h>
-
-#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
-#include <libgnomeui/gnome-thumbnail.h>
-#endif
-
-#include "e-attachment.h"
-#include "e-attachment-bar.h"
-
-#include <libedataserver/e-data-server-util.h>
-
-#include <camel/camel-data-wrapper.h>
-#include <camel/camel-iconv.h>
-#include <camel/camel-mime-message.h>
-#include <camel/camel-stream-fs.h>
-#include <camel/camel-stream-null.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-stream-filter.h>
-#include <camel/camel-mime-filter-bestenc.h>
-#include <camel/camel-mime-part.h>
-
-#include "e-util/e-util.h"
-#include "e-util/e-gui-utils.h"
-#include "e-util/e-icon-factory.h"
-#include "e-util/e-error.h"
-#include "e-util/e-mktemp.h"
-
-#define ICON_WIDTH 64
-#define ICON_SEPARATORS " /-_"
-#define ICON_SPACING 2
-#define ICON_ROW_SPACING ICON_SPACING
-#define ICON_COL_SPACING ICON_SPACING
-#define ICON_BORDER 2
-#define ICON_TEXT_SPACING 2
-
-
-static GnomeIconListClass *parent_class = NULL;
-
-struct _EAttachmentBarPrivate {
-	GtkWidget *attach;	/* attachment file dialogue, if active */
-
-	/* Recent documents. Use this widget directly when bonoboui is obsoleted */
-	GtkWidget *recent;
-
-	gboolean batch_unref;
-	GPtrArray *attachments;
-	char *path;
-};
-
-
-enum {
-	CHANGED,
-	LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-
-static void update (EAttachmentBar *bar);
-
-/* Attachment handling functions.  */
-
-static void
-attachment_destroy (EAttachmentBar *bar, EAttachment *attachment)
-{
-	if (bar->priv->batch_unref)
-		return;
-
-	if (g_ptr_array_remove (bar->priv->attachments, attachment)) {
-		update (bar);
-		g_signal_emit (bar, signals[CHANGED], 0);
-	}
-}
-
-static void
-attachment_changed_cb (EAttachment *attachment,
-		       gpointer data)
-{
-	update (E_ATTACHMENT_BAR (data));
-}
-
-static void
-add_common (EAttachmentBar *bar, EAttachment *attachment)
-{
-	g_return_if_fail (attachment != NULL);
-
-	g_ptr_array_add (bar->priv->attachments, attachment);
-	g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
-	g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar);
-
-	update (bar);
-
-	g_signal_emit (bar, signals[CHANGED], 0);
-}
-
-static void
-add_from_mime_part (EAttachmentBar *bar, CamelMimePart *part)
-{
-	add_common (bar, e_attachment_new_from_mime_part (part));
-}
-
-static void
-add_from_file (EAttachmentBar *bar, const char *file_name, const char *disposition)
-{
-	EAttachment *attachment;
-	CamelException ex;
-
-	camel_exception_init (&ex);
-
-	if ((attachment = e_attachment_new (file_name, disposition, &ex))) {
-		add_common (bar, attachment);
-	} else {
-		/* FIXME: Avoid using error from mailer */
-		e_error_run ((GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar), "mail-composer:no-attach",
-			     file_name, camel_exception_get_description (&ex), NULL);
-		camel_exception_clear (&ex);
-	}
-}
-
-/* get_system_thumbnail:
- * If filled store_uri, then creating thumbnail for it, otherwise, if is_available_local,
- * and attachment is not an application, then save to temp and create a thumbnail for the body.
- * Otherwise returns NULL (or if something goes wrong/library not available).
- */
-static GdkPixbuf *
-get_system_thumbnail (EAttachment *attachment, CamelContentType *content_type)
-{
-	GdkPixbuf *pixbuf = NULL;
-#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
-	struct stat file_stat;
-	char *file_uri = NULL;
-	gboolean is_tmp = FALSE;
-
-	if (!attachment || !attachment->is_available_local)
-		return NULL;
-
-	if (attachment->store_uri && g_str_has_prefix (attachment->store_uri, "file://"))
-		file_uri = attachment->store_uri;
-	else if (attachment->body) {
-		/* save part to the temp directory */
-		char *tmp_file;
-
-		is_tmp = TRUE;
-
-		tmp_file = e_mktemp ("tmp-XXXXXX");
-		if (tmp_file) {
-			CamelStream *stream;
-			char *mfilename = NULL;
-			const char * filename;
-
-			filename = camel_mime_part_get_filename (attachment->body);
-			if (filename == NULL)
-				filename = "unknown";
-			else {
-				char *utf8_mfilename;
-
-				utf8_mfilename = g_strdup (filename);
-				e_filename_make_safe (utf8_mfilename);
-				mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL);
-				g_free (utf8_mfilename);
-
-				filename = (const char *) mfilename;
-			}
-
-			file_uri = g_strjoin (NULL, "file://", tmp_file, "-", filename, NULL);
-
-			stream = camel_stream_fs_new_with_name (file_uri + 7, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-			if (stream) {
-				CamelDataWrapper *content;
-
-				content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
-
-				if (camel_data_wrapper_decode_to_stream (content, stream) == -1
-				    || camel_stream_flush (stream) == -1) {
-					g_free (file_uri);
-					file_uri = NULL;
-				}
-
-				camel_object_unref (stream);
-			} else {
-				g_free (file_uri);
-				file_uri = NULL;
-			}
-
-			g_free (mfilename);
-			g_free (tmp_file);
-		}
-	}
-
-	if (!file_uri || !g_str_has_prefix (file_uri, "file://")) {
-		if (is_tmp)
-			g_free (file_uri);
-
-		return NULL;
-	}
-
-	if (stat (file_uri + 7, &file_stat) != -1 && S_ISREG (file_stat.st_mode)) {
-		GnomeThumbnailFactory *th_factory;
-		char *th_file;
-
-		th_factory = gnome_thumbnail_factory_new (GNOME_THUMBNAIL_SIZE_NORMAL);
-		th_file = gnome_thumbnail_factory_lookup (th_factory, file_uri, file_stat.st_mtime);
-
-		if (th_file) {
-			pixbuf = gdk_pixbuf_new_from_file (th_file, NULL);
-			g_free (th_file);
-		} else if (content_type) {
-			char *mime = camel_content_type_simple (content_type);
-
-			if (gnome_thumbnail_factory_can_thumbnail (th_factory, file_uri, mime, file_stat.st_mtime)) {
-				pixbuf = gnome_thumbnail_factory_generate_thumbnail (th_factory, file_uri, mime);
-				
-				if (pixbuf && !is_tmp)
-					gnome_thumbnail_factory_save_thumbnail (th_factory, pixbuf, file_uri, file_stat.st_mtime);
-			}
-
-			g_free (mime);
-		}
-
-		g_object_unref (th_factory);
-	}
-
-	if (is_tmp) {
-		/* clear the temp */
-		g_remove (file_uri + 7);
-		g_free (file_uri);
-	}
-#endif
-
-	return pixbuf;
-}
-
-static GdkPixbuf *
-scale_pixbuf (GdkPixbuf *pixbuf)
-{
-	int ratio, width, height;
-
-	if (!pixbuf)
-		return NULL;
-
-	width = gdk_pixbuf_get_width (pixbuf);
-	height = gdk_pixbuf_get_height (pixbuf);
-	if (width >= height) {
-		if (width > 48) {
-			ratio = width / 48;
-			width = 48;
-			height = height / ratio;
-			if (height == 0)
-				height = 1;
-		}
-	} else {
-		if (height > 48) {
-			ratio = height / 48;
-			height = 48;
-			width = width / ratio;
-			if (width == 0)
-				width = 1;
-		}
-	}
-
-	return e_icon_factory_pixbuf_scale (pixbuf, width, height);
-}
-
-/* Icon list contents handling.  */
-
-static void
-calculate_height_width(EAttachmentBar *bar, int *new_width, int *new_height)
-{
-        int width, height, icon_width;
-        PangoFontMetrics *metrics;
-        PangoContext *context;
-
-        context = gtk_widget_get_pango_context ((GtkWidget *) bar);
-        metrics = pango_context_get_metrics (context, ((GtkWidget *) bar)->style->font_desc, pango_context_get_language (context));
-        width = PANGO_PIXELS (pango_font_metrics_get_approximate_char_width (metrics)) * 15;
-	/* This should be *2, but the icon list creates too much space above ... */
-	height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)) * 3;
-	pango_font_metrics_unref (metrics);
-	icon_width = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING;
-
-	if (new_width)
-		*new_width = MAX (icon_width, width);
-
-	if (new_height)
-		*new_height = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING + height;
-
-	return;
-}
-
-void
-e_attachment_bar_create_attachment_cache (EAttachment *attachment)
-{
-
-	CamelContentType *content_type;
-
-	if (!attachment->body)
-		return;
-
-	content_type = camel_mime_part_get_content_type (attachment->body);
-
-	if (camel_content_type_is(content_type, "image", "*")) {
-		CamelDataWrapper *wrapper;
-		CamelStreamMem *mstream;
-		GdkPixbufLoader *loader;
-		gboolean error = TRUE;
-		GdkPixbuf *pixbuf;
-
-		wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
-		mstream = (CamelStreamMem *) camel_stream_mem_new ();
-
-		camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
-
-		/* Stream image into pixbuf loader */
-		loader = gdk_pixbuf_loader_new ();
-		error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL);
-		gdk_pixbuf_loader_close (loader, NULL);
-
-		if (!error) {
-			pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-			attachment->pixbuf_cache = scale_pixbuf (pixbuf);
-			pixbuf = attachment->pixbuf_cache;
-			g_object_ref(pixbuf);
-		} else {
-			attachment->pixbuf_cache = NULL;
-			g_warning ("GdkPixbufLoader Error");
-		}
-
-		/* Destroy everything */
-		g_object_unref (loader);
-		camel_object_unref (mstream);
-	}
-}
-
-static void
-update (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	GnomeIconList *icon_list;
-	int bar_width, bar_height;
-	int i;
-
-	priv = bar->priv;
-	icon_list = GNOME_ICON_LIST (bar);
-
-	gnome_icon_list_freeze (icon_list);
-
-	gnome_icon_list_clear (icon_list);
-
-	/* FIXME could be faster, but we don't care.  */
-	for (i = 0; i < priv->attachments->len; i++) {
-		EAttachment *attachment;
-		CamelContentType *content_type;
-		char *size_string, *label;
-		GdkPixbuf *pixbuf = NULL;
-		char *desc;
-
-		attachment = priv->attachments->pdata[i];
-
-		if (!attachment->is_available_local || !attachment->body) {
-			if ((pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG))) {
-				attachment->index = gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, "");
-				g_object_unref (pixbuf);
-			}
-			continue;
-		}
-
-		content_type = camel_mime_part_get_content_type (attachment->body);
-		/* Get the image out of the attachment
-		   and create a thumbnail for it */
-		if ((pixbuf = attachment->pixbuf_cache)) {
-			g_object_ref(pixbuf);
-		} else if (camel_content_type_is(content_type, "image", "*")) {
-			CamelDataWrapper *wrapper;
-			CamelStreamMem *mstream;
-			GdkPixbufLoader *loader;
-			gboolean error = TRUE;
-
-			wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
-			mstream = (CamelStreamMem *) camel_stream_mem_new ();
-
-			camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
-
-			/* Stream image into pixbuf loader */
-			loader = gdk_pixbuf_loader_new ();
-			error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL);
-			gdk_pixbuf_loader_close (loader, NULL);
-
-			if (!error) {
-				pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-				attachment->pixbuf_cache = scale_pixbuf (pixbuf);
-				pixbuf = attachment->pixbuf_cache;
-				g_object_ref (pixbuf);
-			} else {
-				pixbuf = NULL;
-				g_warning ("GdkPixbufLoader Error");
-			}
-
-			/* Destroy everything */
-			g_object_unref (loader);
-			camel_object_unref (mstream);
-		} else if (!bar->expand && (pixbuf = get_system_thumbnail (attachment, content_type))) {
-			attachment->pixbuf_cache = scale_pixbuf (pixbuf);
-			pixbuf = attachment->pixbuf_cache;
-			g_object_ref (pixbuf);
-		}
-
-		desc = camel_mime_part_get_description (attachment->body);
-    
-		if (!desc || *desc == '\0') {
-			if (attachment->file_name) {
-				desc = g_filename_to_utf8 (attachment->file_name, -1, NULL, NULL, NULL);
-			} else {
-				desc = camel_mime_part_get_filename (attachment->body);
-				if (desc)
-					desc = g_strdup (desc);
-			}
-		} else {
-			desc = g_strdup (desc);
-		}
-
-		if (!desc)
-			desc = g_strdup (_("attachment"));
-
-		if (attachment->size && (size_string = g_format_size_for_display (attachment->size))) {
-			label = g_strdup_printf ("%s (%s)", desc, size_string);
-			g_free (desc);
-			g_free (size_string);
-		} else {
-			label = g_strdup (desc);
-			g_free (desc);
-		}
-
-		if (pixbuf == NULL) {
-			char *mime_type;
-
-			mime_type = camel_content_type_simple (content_type);
-			pixbuf = e_icon_for_mime_type (mime_type, 48);
-			if (pixbuf == NULL) {
-				g_warning("cannot find icon for mime type %s (installation problem?)", mime_type);
-				pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG);
-			}
-			g_free (mime_type);
-
-			/* remember this picture and use it later again */
-			if (pixbuf)
-				attachment->pixbuf_cache = g_object_ref (pixbuf);
-		}
-
-		if (pixbuf) {
-			GdkPixbuf *pixbuf_orig = pixbuf;
-			pixbuf = gdk_pixbuf_add_alpha (pixbuf_orig, TRUE, 255, 255, 255);
-
-			/* gdk_pixbuf_add_alpha returns a newly allocated pixbuf,
-			   free the original one.
-			*/
-			g_object_unref (pixbuf_orig);
-
-			/* In case of a attachment bar, in a signed/encrypted part, display the status as a emblem*/
-			if (attachment->sign) {
-				/* Show the signature status at the right-bottom.*/
-				GdkPixbuf *sign = NULL;
-				int x, y;
-
-				if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_BAD)
-					sign = e_icon_factory_get_icon ("stock_signature-bad", E_ICON_SIZE_MENU);
-				else if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_GOOD)
-					sign = e_icon_factory_get_icon ("stock_signature-ok", E_ICON_SIZE_MENU);
-				else
-					sign = e_icon_factory_get_icon ("stock_signature", E_ICON_SIZE_MENU);
-
-				x = gdk_pixbuf_get_width (pixbuf) - 17;
-				y = gdk_pixbuf_get_height (pixbuf) - 17;
-
-				gdk_pixbuf_copy_area (sign, 0, 0, 16, 16, pixbuf, x, y);
-				g_object_unref (sign);
-			}
-
-			if (attachment->encrypt) {
-				/* Show the encryption status at the top left.*/
-				GdkPixbuf *encrypt = e_icon_factory_get_icon ("stock_lock-ok", E_ICON_SIZE_MENU);
-
-				gdk_pixbuf_copy_area (encrypt, 0, 0, 16, 16, pixbuf, 1, 1);
-				g_object_unref (encrypt);
-			}
-
-			gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, label);
-			g_object_unref (pixbuf);
-		}
-
-		g_free (label);
-	}
-
-	gnome_icon_list_thaw (icon_list);
-
-	/* Resize */
-	if (bar->expand) {
-		gtk_widget_get_size_request ((GtkWidget *) bar, &bar_width, &bar_height);
-
-		if (bar->priv->attachments->len) {
-			int per_col, rows, height, width;
-
-			calculate_height_width(bar, &width, &height);
-			per_col = bar_width / width;
-			per_col = (per_col ? per_col : 1);
-			rows = (bar->priv->attachments->len + per_col -1) / per_col;
-			gtk_widget_set_size_request ((GtkWidget *) bar, bar_width, rows * height);
-		}
-	}
-}
-
-static void
-update_remote_file (EAttachment *attachment, EAttachmentBar *bar)
-{
-	GnomeIconList *icon_list;
-	GnomeIconTextItem *item;
-	char *msg, *base;
-
-	if (attachment->percentage == -1) {
-		update (bar);
-		return;
-	}
-
-	base = g_path_get_basename(attachment->file_name);
-	msg = g_strdup_printf("%s (%d%%)", base, attachment->percentage);
-	g_free(base);
-
-	icon_list = GNOME_ICON_LIST (bar);
-
-	gnome_icon_list_freeze (icon_list);
-
-	item = gnome_icon_list_get_icon_text_item (icon_list, attachment->index);
-	if (!item->is_text_allocated)
-		g_free (item->text);
-
-	gnome_icon_text_item_configure (item, item->x, item->y, item->width, item->fontname, msg, item->is_editable, TRUE);
-
-	gnome_icon_list_thaw (icon_list);
-}
-
-void
-e_attachment_bar_remove_selected (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	int id, left, nrem = 0;
-	GList *items;
-	GPtrArray *temp_arr;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	priv = bar->priv;
-
-	if (!(items = gnome_icon_list_get_selection ((GnomeIconList *) bar)))
-		return;
-
-	temp_arr = g_ptr_array_new ();
-	while (items != NULL) {
-		if ((id = GPOINTER_TO_INT (items->data) - nrem) < priv->attachments->len) {
-			attachment = E_ATTACHMENT(g_ptr_array_index (priv->attachments, id));
-			g_ptr_array_add (temp_arr, (gpointer)attachment);
-			g_ptr_array_remove_index (priv->attachments, id);
-			nrem++;
-		}
-
-		items = items->next;
-	}
-
-	g_ptr_array_foreach (temp_arr, (GFunc)g_object_unref, NULL);
-	g_ptr_array_free (temp_arr, TRUE);
-
-	update (bar);
-
-	g_signal_emit (bar, signals[CHANGED], 0);
-
-	id++;
-
-	if ((left = gnome_icon_list_get_num_icons ((GnomeIconList *) bar)) > 0)
-		gnome_icon_list_focus_icon ((GnomeIconList *) bar, left > id ? id : left - 1);
-}
-
-void
-e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width)
-{
-	int per_col, rows, height, width;
-
-	calculate_height_width(bar, &width, &height);
-	per_col = bar_width / width;
-	per_col = (per_col ? per_col : 1);
-	rows = (bar->priv->attachments->len + per_col - 1) / per_col;
-	gtk_widget_set_size_request ((GtkWidget *)bar, bar_width, rows * height);
-}
-
-void
-e_attachment_bar_edit_selected (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	GList *items;
-	int id;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	priv = bar->priv;
-
-	items = gnome_icon_list_get_selection ((GnomeIconList *) bar);
-	while (items != NULL) {
-		if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) {
-			attachment = priv->attachments->pdata[id];
-			e_attachment_edit (attachment, GTK_WIDGET (bar));
-		}
-
-		items = items->next;
-	}
-}
-
-GtkWidget **
-e_attachment_bar_get_selector(EAttachmentBar *bar)
-{
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	return &bar->priv->attach;
-}
-
-/**
- * e_attachment_bar_get_selected:
- * @bar: an #EAttachmentBar object
- *
- * Returns a newly allocated #GSList of ref'd #EAttachment objects
- * representing the selected items in the #EAttachmentBar Icon List.
- **/
-GSList *
-e_attachment_bar_get_selected (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	GSList *attachments = NULL;
-	EAttachment *attachment;
-	GList *items;
-	int id;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	priv = bar->priv;
-
-	items = gnome_icon_list_get_selection ((GnomeIconList *) bar);
-
-	while (items != NULL) {
-		if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) {
-			attachment = priv->attachments->pdata[id];
-			attachments = g_slist_prepend (attachments, attachment);
-			g_object_ref (attachment);
-		}
-
-		items = items->next;
-	}
-
-	attachments = g_slist_reverse (attachments);
-
-	return attachments;
-}
-
-/* FIXME: Cleanup this, since there is a api to get selected attachments */
-/**
- * e_attachment_bar_get_attachment:
- * @bar: an #EAttachmentBar object
- * @id: Index of the desired attachment or -1 to request all selected attachments
- *
- * Returns a newly allocated #GSList of ref'd #EAttachment objects
- * representing the requested item(s) in the #EAttachmentBar Icon
- * List.
- **/
-GSList *
-e_attachment_bar_get_attachment (EAttachmentBar *bar, int id)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	GSList *attachments;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	priv = bar->priv;
-
-	if (id == -1 || id > priv->attachments->len)
-		return e_attachment_bar_get_selected (bar);
-
-	attachment = priv->attachments->pdata[id];
-	attachments = g_slist_prepend (NULL, attachment);
-	g_object_ref (attachment);
-
-	return attachments;
-}
-
-
-/**
- * e_attachment_bar_get_all_attachments:
- * @bar: an #EAttachmentBar object
- *
- * Returns a newly allocated #GSList of ref'd #EAttachment objects.
- **/
-GSList *
-e_attachment_bar_get_all_attachments (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	GSList *attachments = NULL;
-	EAttachment *attachment;
-	int i;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	priv = bar->priv;
-
-	for (i = priv->attachments->len - 1; i >= 0; i--) {
-		attachment = priv->attachments->pdata[i];
-		if (attachment->is_available_local) {
-			attachments = g_slist_prepend (attachments, attachment);
-			g_object_ref (attachment);
-		}
-	}
-
-	return attachments;
-}
-
-/* Just the GSList has to be freed by the caller */
-GSList *
-e_attachment_bar_get_parts (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	GSList *parts = NULL;
-	int i;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	priv = bar->priv;
-
-	for (i = 0; i < priv->attachments->len; i++) {
-		attachment = priv->attachments->pdata[i];
-		if (attachment->is_available_local)
-			parts = g_slist_prepend (parts, attachment->body);
-	}
-
-        return parts;
-}
-
-/* GtkObject methods.  */
-
-static void
-destroy (GtkObject *object)
-{
-	EAttachmentBar *bar = (EAttachmentBar *) object;
-	struct _EAttachmentBarPrivate *priv = bar->priv;
-	EAttachment *attachment;
-	int i;
-
-	if ((priv = bar->priv)) {
-		priv->batch_unref = TRUE;
-		for (i = 0; i < priv->attachments->len; i++) {
-			attachment = priv->attachments->pdata[i];
-			g_object_weak_unref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
-			g_object_unref (attachment);
-		}
-		g_ptr_array_free (priv->attachments, TRUE);
-
-		if (priv->attach)
-			gtk_widget_destroy (priv->attach);
-
-		if (priv->recent)
-			gtk_widget_destroy (priv->recent);
-
-		if (priv->path)
-			g_free (priv->path);
-
-		g_free (priv);
-		bar->priv = NULL;
-	}
-
-	if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
-		(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
-}
-
-static char *
-temp_save_part (CamelMimePart *part, gboolean readonly)
-{
-	const char *filename;
-	char *tmpdir, *path, *mfilename = NULL, *utf8_mfilename = NULL;
-	CamelStream *stream;
-	CamelDataWrapper *wrapper;
-
-	if (!(tmpdir = e_mkdtemp ("evolution-tmp-XXXXXX")))
-		return NULL;
-
-	if (!(filename = camel_mime_part_get_filename (part))) {
-		/* This is the default filename used for temporary file creation */
-		filename = _("Unknown");
-	} else {
-		utf8_mfilename = g_strdup (filename);
-		e_filename_make_safe (utf8_mfilename);
-		mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL);
-		g_free (utf8_mfilename);
-		filename = (const char *) mfilename;
-	}
-
-	path = g_build_filename (tmpdir, filename, NULL);
-	g_free (tmpdir);
-	g_free (mfilename);
-
-	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
-	if (readonly)
-		stream = camel_stream_fs_new_with_name (path, O_RDWR|O_CREAT|O_TRUNC, 0444);
-	else
-		stream = camel_stream_fs_new_with_name (path, O_RDWR|O_CREAT|O_TRUNC, 0644);
-
-	if (!stream) {
-		/* TODO handle error conditions */
-		g_message ("DEBUG: could not open the file to write\n");
-		g_free (path);
-		return NULL;
-	}
-
-	if (camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) stream) == -1) {
-		g_free (path);
-		camel_stream_close (stream);
-		camel_object_unref (stream);
-		g_message ("DEBUG: could not write to file\n");
-		return NULL;
-	}
-
-	camel_stream_close(stream);
-	camel_object_unref(stream);
-
-	return path;
-}
-
-static void
-eab_drag_data_get(EAttachmentBar *bar, GdkDragContext *drag, GtkSelectionData *data, guint info, guint time)
-{
-	struct _EAttachmentBarPrivate *priv = bar->priv;
-	EAttachment *attachment;
-	char *path, **uris;
-	int len, n, i = 0;
-	CamelURL *url;
-	GList *items;
-
-	if (info)
-		return;
-
-	items = gnome_icon_list_get_selection (GNOME_ICON_LIST (bar));
-	len = g_list_length (items);
-
-	uris = g_malloc0 (sizeof (char *) * (len + 1));
-
-	for ( ; items != NULL; items = items->next) {
-		if (!((n = GPOINTER_TO_INT (items->data)) < priv->attachments->len))
-			continue;
-
-		attachment = priv->attachments->pdata[n];
-
-		if (!attachment->is_available_local)
-			continue;
-
-		if (attachment->store_uri) {
-			uris[i++] = attachment->store_uri;
-			continue;
-		}
-
-		/* If we are not able to save, ignore it */
-		if (!(path = temp_save_part (attachment->body, FALSE)))
-			continue;
-
-		url = camel_url_new ("file://", NULL);
-		camel_url_set_path (url, path);
-		attachment->store_uri = camel_url_to_string (url, 0);
-		camel_url_free (url);
-		g_free (path);
-
-		uris[i++] = attachment->store_uri;
-	}
-
-	uris[i] = NULL;
-
-	gtk_selection_data_set_uris (data, uris);
-
-	g_free (uris);
-
-	return;
-}
-
-static gboolean
-eab_button_release_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy)
-{
-	GnomeIconList *icon_list = GNOME_ICON_LIST(bar);
-	GList *selected;
-	int length;
-	GtkTargetEntry drag_types[] = {
-		{ "text/uri-list", 0, 0 },
-	};
-
-	if (event && event->button == 1) {
-		selected = gnome_icon_list_get_selection(icon_list);
-		length = g_list_length (selected);
-		if (length)
-			gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY);
-		else
-			gtk_drag_source_unset((GtkWidget *)bar);
-	}
-
-	return FALSE;
-}
-
-static gboolean
-eab_button_press_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy)
-{
-	GnomeIconList *icon_list = GNOME_ICON_LIST(bar);
-	GList *selected = NULL, *tmp;
-	int length, icon_number;
-	gboolean take_selected = FALSE;
-	GtkTargetEntry drag_types[] = {
-		{ "text/uri-list", 0, 0 },
-	};
-
-	selected = gnome_icon_list_get_selection(icon_list);
-	length = g_list_length (selected);
-
-	if (event) {
-		icon_number = gnome_icon_list_get_icon_at(icon_list, event->x, event->y);
-		if (icon_number < 0) {
-			/* When nothing is selected, deselect all */
-			gnome_icon_list_unselect_all (icon_list);
-			length = 0;
-			selected = NULL;
-		}
-
-		if (event->button == 1) {
-			/* If something is selected, then allow drag or else help to select */
-			if (length)
-				gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY);
-			else
-				gtk_drag_source_unset((GtkWidget *)bar);
-			return FALSE;
-		}
-
-		/* If not r-click dont progress any more.*/
-		if (event->button != 3)
-			return FALSE;
-
-		/* When a r-click on something, if it is in the already selected list, consider a r-click of multiple things
-		 * or deselect all and select only this for r-click
-		 */
-		if (icon_number >= 0) {
-			for (tmp = selected; tmp; tmp = tmp->next) {
-				if (GPOINTER_TO_INT(tmp->data) == icon_number)
-					take_selected = TRUE;
-			}
-
-			if (!take_selected) {
-				gnome_icon_list_unselect_all(icon_list);
-				gnome_icon_list_select_icon(icon_list, icon_number);
-			}
-		}
-	}
-
-	return FALSE;
-}
-
-static gboolean
-eab_icon_clicked_cb (EAttachmentBar *bar, GdkEvent *event, gpointer *dummy)
-{
-	EAttachment *attachment;
-	gboolean ret = FALSE;
-	CamelURL *url;
-	char *path;
-	GSList *p;
-
-	if (E_IS_ATTACHMENT_BAR (bar) && event->type == GDK_2BUTTON_PRESS) {
-		p = e_attachment_bar_get_selected (bar);
-		/* check if has body already, remote files can take longer to fetch */
-		if (p && p->next == NULL && ((EAttachment *)p->data)->body) {
-			attachment = p->data;
-
-			/* Check if the file is stored already */
-			if (!attachment->store_uri) {
-				path = temp_save_part (attachment->body, TRUE);
-				url = camel_url_new ("file://", NULL);
-				camel_url_set_path (url, path);
-				attachment->store_uri = camel_url_to_string (url, 0);
-				camel_url_free (url);
-				g_free (path);
-			}
-
-			/* FIXME Pass a parent window. */
-			e_show_uri (NULL, attachment->store_uri);
-
-			ret = TRUE;
-		}
-
-		if (p) {
-			g_slist_foreach (p, (GFunc) g_object_unref, NULL);
-			g_slist_free (p);
-		}
-	}
-
-	return ret;
-}
-
-/* Initialization.  */
-
-static void
-class_init (EAttachmentBarClass *klass)
-{
-	GtkObjectClass *object_class;
-
-	object_class = GTK_OBJECT_CLASS (klass);
-
-	parent_class = g_type_class_ref (gnome_icon_list_get_type ());
-
-	object_class->destroy = destroy;
-
-	/* Setup signals.  */
-
-	signals[CHANGED] =
-		g_signal_new ("changed",
-			      E_TYPE_ATTACHMENT_BAR,
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EAttachmentBarClass, changed),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
-}
-
-static void
-init (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-
-	priv = g_new (struct _EAttachmentBarPrivate, 1);
-
-	priv->attach = NULL;
-	priv->batch_unref = FALSE;
-	priv->attachments = g_ptr_array_new ();
-
-	priv->recent = gtk_recent_chooser_menu_new ();
-	gtk_recent_chooser_menu_set_show_numbers (GTK_RECENT_CHOOSER_MENU (priv->recent), TRUE);
-	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (priv->recent), GTK_RECENT_SORT_MRU);
-	gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER (priv->recent), FALSE);
-	gtk_recent_chooser_set_show_private (GTK_RECENT_CHOOSER (priv->recent), FALSE);
-	gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (priv->recent), TRUE);
-	gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER (priv->recent), TRUE);
-
-	priv->path = NULL;
-
-	bar->priv = priv;
-	bar->expand = FALSE;
-}
-
-
-GType
-e_attachment_bar_get_type (void)
-{
-	static GType type = 0;
-
-	if (type == 0) {
-		static const GTypeInfo info = {
-			sizeof (EAttachmentBarClass),
-			NULL, NULL,
-			(GClassInitFunc) class_init,
-			NULL, NULL,
-			sizeof (EAttachmentBar),
-			0,
-			(GInstanceInitFunc) init,
-		};
-
-		type = g_type_register_static (GNOME_TYPE_ICON_LIST, "EAttachmentBar", &info, 0);
-	}
-
-	return type;
-}
-
-GtkWidget *
-e_attachment_bar_new (GtkAdjustment *adj)
-{
-	EAttachmentBar *new;
-	GnomeIconList *icon_list;
-	int icon_width, window_height;
-
-	new = g_object_new (e_attachment_bar_get_type (), NULL);
-
-	icon_list = GNOME_ICON_LIST (new);
-
-	calculate_height_width (new, &icon_width, &window_height);
-
-	gnome_icon_list_construct (icon_list, icon_width, adj, 0);
-
-	gtk_widget_set_size_request (GTK_WIDGET (new), icon_width * 4, window_height);
-
-        GTK_WIDGET_SET_FLAGS (new, GTK_CAN_FOCUS);
-
-	gnome_icon_list_set_separators (icon_list, ICON_SEPARATORS);
-	gnome_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING);
-	gnome_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING);
-	gnome_icon_list_set_icon_border (icon_list, ICON_BORDER);
-	gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
-	gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE);
-
-	atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (new)),
-			     _("Attachment Bar"));
-
-	g_signal_connect (new, "button_release_event", G_CALLBACK(eab_button_release_event), NULL);
-	g_signal_connect (new, "button_press_event", G_CALLBACK(eab_button_press_event), NULL);
-	g_signal_connect (new, "drag-data-get", G_CALLBACK(eab_drag_data_get), NULL);
-	g_signal_connect (icon_list, "event", G_CALLBACK (eab_icon_clicked_cb), NULL);
-
-	return GTK_WIDGET (new);
-}
-
-static char *
-get_default_charset (void)
-{
-	GConfClient *gconf;
-	const char *locale;
-	char *charset;
-
-	gconf = gconf_client_get_default ();
-	charset = gconf_client_get_string (gconf, "/apps/evolution/mail/composer/charset", NULL);
-
-	if (!charset || charset[0] == '\0') {
-		g_free (charset);
-		charset = gconf_client_get_string (gconf, "/apps/evolution/mail/format/charset", NULL);
-		if (charset && charset[0] == '\0') {
-			g_free (charset);
-			charset = NULL;
-		}
-	}
-
-	g_object_unref (gconf);
-
-	if (!charset && (locale = camel_iconv_locale_charset ()))
-		charset = g_strdup (locale);
-
-	return charset ? charset : g_strdup ("us-ascii");
-}
-
-static void
-attach_to_multipart (CamelMultipart *multipart,
-		     EAttachment *attachment,
-		     const char *default_charset)
-{
-	CamelContentType *content_type;
-	CamelDataWrapper *content;
-
-	if (!attachment->body)
-		return;
-
-	content_type = camel_mime_part_get_content_type (attachment->body);
-	content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
-
-	if (!CAMEL_IS_MULTIPART (content)) {
-		if (camel_content_type_is (content_type, "text", "*")) {
-			CamelTransferEncoding encoding;
-			CamelStreamFilter *filter_stream;
-			CamelMimeFilterBestenc *bestenc;
-			CamelStream *stream;
-			const char *charset;
-			char *buf = NULL;
-			char *type;
-
-			charset = camel_content_type_param (content_type, "charset");
-
-			stream = camel_stream_null_new ();
-			filter_stream = camel_stream_filter_new_with_stream (stream);
-			bestenc = camel_mime_filter_bestenc_new (CAMEL_BESTENC_GET_ENCODING);
-			camel_stream_filter_add (filter_stream, CAMEL_MIME_FILTER (bestenc));
-			camel_object_unref (stream);
-
-			camel_data_wrapper_decode_to_stream (content, CAMEL_STREAM (filter_stream));
-			camel_object_unref (filter_stream);
-
-			encoding = camel_mime_filter_bestenc_get_best_encoding (bestenc, CAMEL_BESTENC_8BIT);
-			camel_mime_part_set_encoding (attachment->body, encoding);
-
-			if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) {
-				/* the text fits within us-ascii so this is safe */
-				/* FIXME: check that this isn't iso-2022-jp? */
-				default_charset = "us-ascii";
-			} else if (!charset) {
-				if (!default_charset)
-					default_charset = buf = get_default_charset ();
-
-				/* FIXME: We should really check that this fits within the
-                                   default_charset and if not find one that does and/or
-				   allow the user to specify? */
-			}
-
-			if (!charset) {
-				/* looks kinda nasty, but this is how ya have to do it */
-				camel_content_type_set_param (content_type, "charset", default_charset);
-				type = camel_content_type_format (content_type);
-				camel_mime_part_set_content_type (attachment->body, type);
-				g_free (type);
-				g_free (buf);
-			}
-
-			camel_object_unref (bestenc);
-		} else if (!CAMEL_IS_MIME_MESSAGE (content)) {
-			camel_mime_part_set_encoding (attachment->body, CAMEL_TRANSFER_ENCODING_BASE64);
-		}
-	}
-
-	camel_multipart_add_part (multipart, attachment->body);
-}
-
-void
-e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart, const char *default_charset)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	int i;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-	g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
-
-	priv = bar->priv;
-
-	for (i = 0; i < priv->attachments->len; i++) {
-		attachment = priv->attachments->pdata[i];
-		if (attachment->is_available_local)
-			attach_to_multipart (multipart, attachment, default_charset);
-	}
-}
-
-guint
-e_attachment_bar_get_num_attachments (EAttachmentBar *bar)
-{
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), 0);
-
-	return bar->priv->attachments->len;
-}
-
-void
-e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition)
-{
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-	g_return_if_fail (file_name != NULL && disposition != NULL);
-
-	add_from_file (bar, file_name, disposition);
-}
-
-void
-e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment)
-{
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	add_common (bar, attachment);
-}
-
-void
-e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment)
-{
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-	g_return_if_fail (attachment != NULL);
-
-	g_ptr_array_add (bar->priv->attachments, attachment);
-	g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
-	g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar);
-
-
-	g_signal_emit (bar, signals[CHANGED], 0);
-}
-
-void
-e_attachment_bar_refresh (EAttachmentBar *bar)
-{
-	update (bar);
-
-}
-
-int
-e_attachment_bar_get_download_count (EAttachmentBar *bar)
-{
-	struct _EAttachmentBarPrivate *priv;
-	EAttachment *attachment;
-	int i, n = 0;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), 0);
-
-	priv = bar->priv;
-
-	for (i = 0; i < priv->attachments->len; i++) {
-		attachment = priv->attachments->pdata[i];
-		if (!attachment->is_available_local)
-			n++;
-	}
-
-	return n;
-}
-
-void
-e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition)
-{
-	EAttachment *attachment;
-	CamelException ex;
-	GtkWindow *parent;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	if (!bar->priv->path)
-		bar->priv->path = e_mkdtemp ("attach-XXXXXX");
-
-	parent = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar);
-	camel_exception_init (&ex);
-	if ((attachment = e_attachment_new_remote_file (parent, url, disposition, bar->priv->path, &ex))) {
-		add_common (bar, attachment);
-		g_signal_connect (attachment, "update", G_CALLBACK (update_remote_file), bar);
-	} else {
-		e_error_run (parent, "mail-composer:no-attach",
-			     url, camel_exception_get_description (&ex), NULL);
-		camel_exception_clear (&ex);
-	}
-}
-
-void
-e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part)
-{
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	add_from_mime_part (bar, part);
-}
-
-/* FIXME: Remove this API if nobody uses it */
-void 
-e_attachment_bar_bonobo_ui_populate_with_recent (BonoboUIComponent *uic, const char *path,
-						 EAttachmentBar *bar, 
-						 BonoboUIVerbFn verb_cb, gpointer user_data)
-{
-	struct _EAttachmentBarPrivate *priv;
-	GList *items, *l;
-	gint limit, i;
-	GString *menuitems;
-	char *encoded_label, *label;
-
-	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
-	priv = bar->priv;
-	limit = gtk_recent_chooser_get_limit (GTK_RECENT_CHOOSER (priv->recent));
-	items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (priv->recent));
-
-	menuitems = g_string_new ("<submenu");
-	g_string_append (menuitems, " name=\"RecentDocsSubmenu\"");
-	g_string_append_printf (menuitems, " sensitive=\"%s\"", items ? "1" : "0");
-	g_string_append_printf (menuitems, " label=\"%s\"", _("Recent _Documents"));
-	g_string_append (menuitems, ">\n");
-
-	for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) {
-		GtkRecentInfo *info = ((GtkRecentInfo *)(l->data));
-		const gchar *info_dn = gtk_recent_info_get_display_name (info);
-		char *display_name, *u;
-
-		/* escape _'s in the display name so that it doesn't become an underline in a GtkLabel */
-		if ((u = strchr (info_dn, '_'))) {
-			int extra = 1;
-			char *d;
-			const char *s;
-
-			while ((u = strchr (u + 1, '_')))
-				extra++;
-
-			d = display_name = g_alloca (strlen (info_dn) + extra + 1);
-			s = info_dn;
-			while (*s != '\0') {
-				if (*s == '_')
-					*d++ = '_';
-				*d++ = *s++;
-			}
-			*d = '\0';
-		} else
-			display_name = (char *) info_dn;
-
-		/* Add menu item */
-		label = g_strdup (display_name);
-		encoded_label = bonobo_ui_util_encode_str (label);
-		g_string_append_printf (menuitems, 
-					"  <menuitem name=\"Recent-%d\" verb=\"\" label=\"%s\"/>\n",
-					i, encoded_label);
-		g_free (encoded_label);
-		g_free (label);
-	}
-
-	g_string_append (menuitems, "</submenu>\n");
-
-	bonobo_ui_component_set (uic, path, menuitems->str, NULL);
-
-	g_string_free (menuitems, TRUE);
-
-	/* Add uri prop */
-	for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) {
-		GtkRecentInfo *info = ((GtkRecentInfo *)(l->data));
-		const gchar *info_uri = gtk_recent_info_get_uri (info);
-		label = g_strdup_printf ("/commands/Recent-%d", i);
-		bonobo_ui_component_set_prop (uic, label, "uri", info_uri, NULL);
-		g_free (label);
-	}
-
-	/* Add verb */
-	for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) {
-		label = g_strdup_printf ("Recent-%d", i);
-		bonobo_ui_component_add_verb (uic, label, verb_cb, user_data);
-		g_free (label);
-	}
-
-	for (l = g_list_first (items); l; l = l->next)
-		gtk_recent_info_unref ((GtkRecentInfo *)(l->data));
-	g_list_free (items);
-}
-
-static void
-action_recent_cb (GtkAction *action, 
-		  EAttachmentBar *attachment_bar)
-{
-	GtkRecentChooser *chooser;
-	GFile *file;
-	gchar *uri;
-
-	chooser = GTK_RECENT_CHOOSER (action);
-
-	/* Wish: gtk_recent_chooser_get_current_file() */
-	uri = gtk_recent_chooser_get_current_uri (chooser);
-	file = g_file_new_for_uri (uri);
-	g_free (uri);
-
-	if (g_file_is_native (file))
-		e_attachment_bar_attach (
-			E_ATTACHMENT_BAR (attachment_bar),
-			g_file_get_path (file), "attachment");
-	else
-		e_attachment_bar_attach_remote_file (
-			E_ATTACHMENT_BAR (attachment_bar),
-			g_file_get_uri (file), "attachment");
-
-	g_object_unref (file);
-}
-
-GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar, 
-				const gchar *action_name,
-				const gchar *action_label)
-{
-	GtkAction *action;
-	GtkRecentChooser *chooser;
-
-	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
-	action = gtk_recent_action_new (
-		action_name, action_label, NULL, NULL);
-	gtk_recent_action_set_show_numbers (GTK_RECENT_ACTION (action), TRUE);
-
-	chooser = GTK_RECENT_CHOOSER (action);
-	gtk_recent_chooser_set_show_icons (chooser, TRUE);
-	gtk_recent_chooser_set_show_not_found (chooser, FALSE);
-	gtk_recent_chooser_set_show_private (chooser, FALSE);
-	gtk_recent_chooser_set_show_tips (chooser, TRUE);
-	gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU);
-
-	g_signal_connect (
-		action, "item-activated",
-		G_CALLBACK (action_recent_cb), bar);
-
-	return action;
-}
-
diff --git a/widgets/misc/e-attachment-bar.h b/widgets/misc/e-attachment-bar.h
deleted file mode 100644
index 7f8b479..0000000
--- a/widgets/misc/e-attachment-bar.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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/>  
- *
- *
- * Authors:
- *		Ettore Perazzoli <ettore ximian com>
- * 	   	Srinivasa Ragavan <sragavan novell com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifndef __E_ATTACHMENT_BAR_H__
-#define __E_ATTACHMENT_BAR_H__
-
-#include <libgnomeui/gnome-icon-list.h>
-
-#include <bonobo/bonobo-ui-node.h>
-#include <bonobo/bonobo-ui-util.h>
-
-#include <camel/camel-multipart.h>
-#include "e-attachment.h"
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#define E_TYPE_ATTACHMENT_BAR \
-	(e_attachment_bar_get_type ())
-#define E_ATTACHMENT_BAR(obj) \
-	(G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBar))
-#define E_ATTACHMENT_BAR_CLASS(klass) \
-	(G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
-#define E_IS_ATTACHMENT_BAR(obj) \
-	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT_BAR))
-#define E_IS_ATTACHMENT_BAR_CLASS(klass) \
-	(G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT_BAR))
-
-typedef struct _EAttachmentBar EAttachmentBar;
-typedef struct _EAttachmentBarClass EAttachmentBarClass;
-
-struct _EAttachmentBar {
-	GnomeIconList parent;
-	gboolean expand;
-
-	struct _EAttachmentBarPrivate *priv;
-};
-
-struct _EAttachmentBarClass {
-	GnomeIconListClass parent_class;
-
-	void (* changed) (EAttachmentBar *bar);
-};
-
-
-GType e_attachment_bar_get_type (void);
-
-GtkWidget *e_attachment_bar_new (GtkAdjustment *adj);
-void e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart,
-				    const char *default_charset);
-guint e_attachment_bar_get_num_attachments (EAttachmentBar *bar);
-void e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition);
-void e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part);
-int e_attachment_bar_get_download_count (EAttachmentBar *bar);
-void e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition);
-GSList *e_attachment_bar_get_attachment (EAttachmentBar *bar, int id);
-void e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment);
-void e_attachment_bar_edit_selected (EAttachmentBar *bar);
-void e_attachment_bar_remove_selected (EAttachmentBar *bar);
-GtkWidget ** e_attachment_bar_get_selector(EAttachmentBar *bar);
-GSList *e_attachment_bar_get_parts (EAttachmentBar *bar);
-GSList *e_attachment_bar_get_selected (EAttachmentBar *bar);
-void e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width);
-GSList * e_attachment_bar_get_all_attachments (EAttachmentBar *bar);
-void e_attachment_bar_create_attachment_cache (EAttachment *attachment);
-void 
-e_attachment_bar_bonobo_ui_populate_with_recent (BonoboUIComponent *uic, const char *path,
-						 EAttachmentBar *bar, 
-						 BonoboUIVerbFn verb_cb, gpointer user_data);
-GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar, 
-				const gchar *action_name,
-				const gchar *action_label);
-void 
-e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment);
-void 
-e_attachment_bar_refresh (EAttachmentBar *bar);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __E_ATTACHMENT_BAR_H__ */
diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c
index 4f5e9ac..f472a26 100644
--- a/widgets/misc/e-attachment.c
+++ b/widgets/misc/e-attachment.c
@@ -1,4 +1,5 @@
 /*
+ * e-attachment.c
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -14,162 +15,845 @@
  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
  *
  *
- * Authors:
- *			Ettore Perazzoli <ettore ximian com>
- *          Jeffrey Stedfast <fejj ximian com>
- *	     	Srinivasa Ragavan <sragavan novell com>
- *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef G_OS_WIN32
-/* Include <windows.h> early (as the gio stuff below will
- * include it anyway, sigh) to workaround the DATADIR problem.
- * <windows.h> (and the headers it includes) stomps all over the
- * namespace like a baboon on crack, and especially the DATADIR enum
- * in objidl.h causes problems.
- */
-#undef DATADIR
-#define DATADIR crap_DATADIR
-#include <windows.h>
-#undef DATADIR
-#endif
+#include "e-attachment.h"
 
-#include <sys/stat.h>
-#include <string.h>
 #include <errno.h>
-
-#include <camel/camel.h>
-
+#include <config.h>
 #include <glib/gi18n.h>
-#include <glib/gstdio.h>
-
-#include <libebook/e-vcard.h>
+#include <camel/camel-iconv.h>
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-stream-null.h>
+#include <camel/camel-stream-vfs.h>
 
 #include "e-util/e-util.h"
-#include "e-util/e-error.h"
 #include "e-util/e-mktemp.h"
-#include "e-util/e-util-private.h"
-
-#include "e-attachment.h"
+#include "e-attachment-store.h"
+
+#define E_ATTACHMENT_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate))
+
+/* Fallback Icon */
+#define DEFAULT_ICON_NAME	"mail-attachment"
+
+/* Emblems */
+#define EMBLEM_CANCELLED	"gtk-cancel"
+#define EMBLEM_LOADING		"emblem-downloads"
+#define EMBLEM_SAVING		"document-save"
+#define EMBLEM_ENCRYPT_WEAK	"security-low"
+#define EMBLEM_ENCRYPT_STRONG	"security-high"
+#define EMBLEM_ENCRYPT_UNKNOWN	"security-medium"
+#define EMBLEM_SIGN_BAD		"stock_signature_bad"
+#define EMBLEM_SIGN_GOOD	"stock_signature-ok"
+#define EMBLEM_SIGN_UNKNOWN	"stock_signature"
+
+/* Attributes needed for EAttachmentStore columns. */
+#define ATTACHMENT_QUERY "standard::*,preview::*,thumbnail::*"
+
+struct _EAttachmentPrivate {
+	GFile *file;
+	GFileInfo *file_info;
+	GCancellable *cancellable;
+	CamelMimePart *mime_part;
+	guint emblem_timeout_id;
+	gchar *disposition;
+	gint percent;
+
+	guint can_show : 1;
+	guint loading  : 1;
+	guint saving   : 1;
+	guint shown    : 1;
+
+	camel_cipher_validity_encrypt_t encrypted;
+	camel_cipher_validity_sign_t signed_;
+
+	/* This is a reference to our row in an EAttachmentStore,
+	 * serving as a means of broadcasting "row-changed" signals.
+	 * If we are removed from the store, we lazily free the
+	 * reference when it is found to be to be invalid. */
+	GtkTreeRowReference *reference;
+};
 
 enum {
-	CHANGED,
-	UPDATE,
-	LAST_SIGNAL
+	PROP_0,
+	PROP_CAN_SHOW,
+	PROP_DISPOSITION,
+	PROP_ENCRYPTED,
+	PROP_FILE,
+	PROP_FILE_INFO,
+	PROP_LOADING,
+	PROP_MIME_PART,
+	PROP_PERCENT,
+	PROP_REFERENCE,
+	PROP_SAVING,
+	PROP_SHOWN,
+	PROP_SIGNED
 };
 
-static guint signals[LAST_SIGNAL] = { 0 };
+static gpointer parent_class;
 
-static GObjectClass *parent_class = NULL;
+static gchar *
+attachment_get_default_charset (void)
+{
+	GConfClient *client;
+	const gchar *key;
+	gchar *charset;
+
+	/* XXX This doesn't really belong here. */
+
+	client = gconf_client_get_default ();
+	key = "/apps/evolution/mail/composer/charset";
+	charset = gconf_client_get_string (client, key, NULL);
+	if (charset == NULL || *charset == '\0') {
+		g_free (charset);
+		key = "/apps/evolution/mail/format/charset";
+		charset = gconf_client_get_string (client, key, NULL);
+		if (charset == NULL || *charset == '\0') {
+			g_free (charset);
+			charset = NULL;
+		}
+	}
+	g_object_unref (client);
+
+	if (charset == NULL)
+		charset = g_strdup (camel_iconv_locale_charset ());
+
+	if (charset == NULL)
+		charset = g_strdup ("us-ascii");
+
+	return charset;
+}
 
 static void
-changed (EAttachment *attachment)
+attachment_update_file_info_columns (EAttachment *attachment)
 {
-	g_signal_emit (attachment, signals[CHANGED], 0);
-}
+	GtkTreeRowReference *reference;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	GFileInfo *file_info;
+	const gchar *content_type;
+	const gchar *description;
+	const gchar *display_name;
+	gchar *content_desc;
+	gchar *display_size;
+	gchar *caption;
+	goffset size;
+
+	reference = e_attachment_get_reference (attachment);
+	if (!gtk_tree_row_reference_valid (reference))
+		return;
+
+	file_info = e_attachment_get_file_info (attachment);
+	if (file_info == NULL)
+		return;
+
+	model = gtk_tree_row_reference_get_model (reference);
+	path = gtk_tree_row_reference_get_path (reference);
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+
+	content_type = g_file_info_get_content_type (file_info);
+	display_name = g_file_info_get_display_name (file_info);
+	size = g_file_info_get_size (file_info);
 
+	content_desc = g_content_type_get_description (content_type);
+	display_size = g_format_size_for_display (size);
 
-/* GtkObject methods.  */
+	description = e_attachment_get_description (attachment);
+	if (description == NULL || *description == '\0')
+		description = display_name;
+
+	if (size > 0)
+		caption = g_strdup_printf (
+			"%s\n(%s)", description, display_size);
+	else
+		caption = g_strdup (description);
+
+	gtk_list_store_set (
+		GTK_LIST_STORE (model), &iter,
+		E_ATTACHMENT_STORE_COLUMN_CAPTION, caption,
+		E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_desc,
+		E_ATTACHMENT_STORE_COLUMN_DESCRIPTION, description,
+		E_ATTACHMENT_STORE_COLUMN_SIZE, size,
+		-1);
+
+	g_free (content_desc);
+	g_free (display_size);
+	g_free (caption);
+}
 
 static void
-finalise (GObject *object)
+attachment_update_icon_column (EAttachment *attachment)
 {
-	EAttachment *attachment = (EAttachment *) object;
-	GtkWidget *dialog;
+	GtkTreeRowReference *reference;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	GFileInfo *file_info;
+	GCancellable *cancellable;
+	GIcon *icon = NULL;
+	const gchar *emblem_name = NULL;
+	const gchar *thumbnail_path = NULL;
 
-	if (attachment->editor_gui != NULL) {
-		dialog = glade_xml_get_widget (attachment->editor_gui, "dialog");
-		g_signal_emit_by_name (dialog, "response", GTK_RESPONSE_CLOSE);
+	reference = e_attachment_get_reference (attachment);
+	if (!gtk_tree_row_reference_valid (reference))
+		return;
+
+	model = gtk_tree_row_reference_get_model (reference);
+	path = gtk_tree_row_reference_get_path (reference);
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+
+	cancellable = attachment->priv->cancellable;
+	file_info = e_attachment_get_file_info (attachment);
+
+	if (file_info != NULL) {
+		icon = g_file_info_get_icon (file_info);
+		thumbnail_path = g_file_info_get_attribute_byte_string (
+			file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
 	}
 
-	if (attachment->is_available_local) {
-		camel_object_unref (attachment->body);
-		if (attachment->pixbuf_cache != NULL)
-			g_object_unref (attachment->pixbuf_cache);
-	} else {
-		if (attachment->cancellable) {
-			/* the operation is still running, so cancel it */
-			g_cancellable_cancel (attachment->cancellable);
-			attachment->cancellable = NULL;
+	/* Prefer the thumbnail if we have one. */
+	if (thumbnail_path != NULL && *thumbnail_path != '\0') {
+		GFile *file;
+
+		file = g_file_new_for_path (thumbnail_path);
+		icon = g_file_icon_new (file);
+		g_object_unref (file);
+
+	/* Else use the standard icon for the content type. */
+	} else if (icon != NULL)
+		g_object_ref (icon);
+
+	/* Last ditch fallback.  (GFileInfo not yet loaded?) */
+	else
+		icon = g_themed_icon_new (DEFAULT_ICON_NAME);
+
+	/* Pick an emblem, limit one.  Choices listed by priority. */
+
+	if (g_cancellable_is_cancelled (cancellable))
+		emblem_name = EMBLEM_CANCELLED;
+
+	else if (e_attachment_get_loading (attachment))
+		emblem_name = EMBLEM_LOADING;
+
+	else if (e_attachment_get_saving (attachment))
+		emblem_name = EMBLEM_SAVING;
+
+	else if (e_attachment_get_encrypted (attachment))
+		switch (e_attachment_get_encrypted (attachment)) {
+			case CAMEL_CIPHER_VALIDITY_ENCRYPT_WEAK:
+				emblem_name = EMBLEM_ENCRYPT_WEAK;
+				break;
+
+			case CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED:
+				emblem_name = EMBLEM_ENCRYPT_UNKNOWN;
+				break;
+
+			case CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG:
+				emblem_name = EMBLEM_ENCRYPT_STRONG;
+				break;
+
+			default:
+				g_warn_if_reached ();
+				break;
 		}
-		g_free (attachment->description);
+
+	else if (e_attachment_get_signed (attachment))
+		switch (e_attachment_get_signed (attachment)) {
+			case CAMEL_CIPHER_VALIDITY_SIGN_GOOD:
+				emblem_name = EMBLEM_SIGN_GOOD;
+				break;
+
+			case CAMEL_CIPHER_VALIDITY_SIGN_BAD:
+				emblem_name = EMBLEM_SIGN_BAD;
+				break;
+
+			case CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN:
+			case CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY:
+				emblem_name = EMBLEM_SIGN_UNKNOWN;
+				break;
+
+			default:
+				g_warn_if_reached ();
+				break;
+		}
+
+	if (emblem_name != NULL) {
+		GIcon *emblemed_icon;
+		GEmblem *emblem;
+
+		emblemed_icon = g_themed_icon_new (emblem_name);
+		emblem = g_emblem_new (emblemed_icon);
+		g_object_unref (emblemed_icon);
+
+		emblemed_icon = g_emblemed_icon_new (icon, emblem);
+		g_object_unref (emblem);
+		g_object_unref (icon);
+
+		icon = emblemed_icon;
 	}
 
-	g_free (attachment->file_name);
-	g_free (attachment->store_uri);
+	gtk_list_store_set (
+		GTK_LIST_STORE (model), &iter,
+		E_ATTACHMENT_STORE_COLUMN_ICON, icon,
+		-1);
 
-	G_OBJECT_CLASS (parent_class)->finalize (object);
+	g_object_unref (icon);
 }
 
+static void
+attachment_update_progress_columns (EAttachment *attachment)
+{
+	GtkTreeRowReference *reference;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	gboolean loading;
+	gboolean saving;
+	gint percent;
+
+	reference = e_attachment_get_reference (attachment);
+	if (!gtk_tree_row_reference_valid (reference))
+		return;
 
-/* Signals.  */
+	model = gtk_tree_row_reference_get_model (reference);
+	path = gtk_tree_row_reference_get_path (reference);
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+
+	/* Don't show progress bars until we have progress to report. */
+	percent = e_attachment_get_percent (attachment);
+	loading = e_attachment_get_loading (attachment) && (percent > 0);
+	saving = e_attachment_get_saving (attachment) && (percent > 0);
+
+	gtk_list_store_set (
+		GTK_LIST_STORE (model), &iter,
+		E_ATTACHMENT_STORE_COLUMN_LOADING, loading,
+		E_ATTACHMENT_STORE_COLUMN_PERCENT, percent,
+		E_ATTACHMENT_STORE_COLUMN_SAVING, saving,
+		-1);
+}
 
 static void
-real_changed (EAttachment *attachment)
+attachment_set_file_info (EAttachment *attachment,
+                          GFileInfo *file_info)
 {
-	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	GtkTreeRowReference *reference;
+	GIcon *icon;
+
+	reference = e_attachment_get_reference (attachment);
+
+	if (file_info != NULL)
+		g_object_ref (file_info);
+
+	if (attachment->priv->file_info != NULL)
+		g_object_unref (attachment->priv->file_info);
+
+	attachment->priv->file_info = file_info;
+
+	/* If the GFileInfo contains a GThemedIcon, append a
+	 * fallback icon name to ensure we display something. */
+	icon = g_file_info_get_icon (file_info);
+	if (G_IS_THEMED_ICON (icon))
+		g_themed_icon_append_name (
+			G_THEMED_ICON (icon), DEFAULT_ICON_NAME);
+
+	g_object_notify (G_OBJECT (attachment), "file-info");
+
+	/* Tell the EAttachmentStore its total size changed. */
+	if (gtk_tree_row_reference_valid (reference)) {
+		GtkTreeModel *model;
+		model = gtk_tree_row_reference_get_model (reference);
+		g_object_notify (G_OBJECT (model), "total-size");
+	}
 }
 
 static void
-real_update_attachment (EAttachment *attachment, char *msg)
+attachment_set_loading (EAttachment *attachment,
+                        gboolean loading)
 {
-	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	GtkTreeRowReference *reference;
+
+	reference = e_attachment_get_reference (attachment);
+
+	attachment->priv->percent = 0;
+	attachment->priv->loading = loading;
+
+	g_object_freeze_notify (G_OBJECT (attachment));
+	g_object_notify (G_OBJECT (attachment), "percent");
+	g_object_notify (G_OBJECT (attachment), "loading");
+	g_object_thaw_notify (G_OBJECT (attachment));
+
+	if (gtk_tree_row_reference_valid (reference)) {
+		GtkTreeModel *model;
+		model = gtk_tree_row_reference_get_model (reference);
+		g_object_notify (G_OBJECT (model), "num-loading");
+	}
+}
+
+static void
+attachment_set_saving (EAttachment *attachment,
+                       gboolean saving)
+{
+	attachment->priv->percent = 0;
+	attachment->priv->saving = saving;
+
+	g_object_freeze_notify (G_OBJECT (attachment));
+	g_object_notify (G_OBJECT (attachment), "percent");
+	g_object_notify (G_OBJECT (attachment), "saving");
+	g_object_thaw_notify (G_OBJECT (attachment));
+}
+
+static void
+attachment_progress_cb (goffset current_num_bytes,
+                        goffset total_num_bytes,
+                        EAttachment *attachment)
+{
+	attachment->priv->percent =
+		(current_num_bytes * 100) / total_num_bytes;
+
+	g_object_notify (G_OBJECT (attachment), "percent");
+}
+
+static gboolean
+attachment_cancelled_timeout_cb (EAttachment *attachment)
+{
+	attachment->priv->emblem_timeout_id = 0;
+	g_cancellable_reset (attachment->priv->cancellable);
+
+	attachment_update_icon_column (attachment);
+
+	return FALSE;
+}
+
+static void
+attachment_cancelled_cb (EAttachment *attachment)
+{
+	/* Reset the GCancellable after one second.  This causes a
+	 * cancel emblem to be briefly shown on the attachment icon
+	 * as visual feedback that an operation was cancelled. */
+
+	if (attachment->priv->emblem_timeout_id > 0)
+		g_source_remove (attachment->priv->emblem_timeout_id);
+
+	attachment->priv->emblem_timeout_id = g_timeout_add_seconds (
+		1, (GSourceFunc) attachment_cancelled_timeout_cb, attachment);
+
+	attachment_update_icon_column (attachment);
+}
+
+static void
+attachment_set_property (GObject *object,
+                         guint property_id,
+                         const GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_CAN_SHOW:
+			e_attachment_set_can_show (
+				E_ATTACHMENT (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_DISPOSITION:
+			e_attachment_set_disposition (
+				E_ATTACHMENT (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_ENCRYPTED:
+			e_attachment_set_encrypted (
+				E_ATTACHMENT (object),
+				g_value_get_int (value));
+			return;
+
+		case PROP_FILE:
+			e_attachment_set_file (
+				E_ATTACHMENT (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_SHOWN:
+			e_attachment_set_shown (
+				E_ATTACHMENT (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_MIME_PART:
+			e_attachment_set_mime_part (
+				E_ATTACHMENT (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_REFERENCE:
+			e_attachment_set_reference (
+				E_ATTACHMENT (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_SIGNED:
+			e_attachment_set_signed (
+				E_ATTACHMENT (object),
+				g_value_get_int (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_get_property (GObject *object,
+                         guint property_id,
+                         GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_CAN_SHOW:
+			g_value_set_boolean (
+				value, e_attachment_get_can_show (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_DISPOSITION:
+			g_value_set_string (
+				value, e_attachment_get_disposition (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_ENCRYPTED:
+			g_value_set_int (
+				value, e_attachment_get_encrypted (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_FILE:
+			g_value_set_object (
+				value, e_attachment_get_file (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_FILE_INFO:
+			g_value_set_object (
+				value, e_attachment_get_file_info (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_SHOWN:
+			g_value_set_boolean (
+				value, e_attachment_get_shown (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_LOADING:
+			g_value_set_boolean (
+				value, e_attachment_get_loading (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_MIME_PART:
+			g_value_set_boxed (
+				value, e_attachment_get_mime_part (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_PERCENT:
+			g_value_set_int (
+				value, e_attachment_get_percent (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_REFERENCE:
+			g_value_set_boxed (
+				value, e_attachment_get_reference (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_SAVING:
+			g_value_set_boolean (
+				value, e_attachment_get_saving (
+				E_ATTACHMENT (object)));
+			return;
+
+		case PROP_SIGNED:
+			g_value_set_int (
+				value, e_attachment_get_signed (
+				E_ATTACHMENT (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
+static void
+attachment_dispose (GObject *object)
+{
+	EAttachmentPrivate *priv;
+
+	priv = E_ATTACHMENT_GET_PRIVATE (object);
+
+	if (priv->file != NULL) {
+		g_object_unref (priv->file);
+		priv->file = NULL;
+	}
+
+	if (priv->file_info != NULL) {
+		g_object_unref (priv->file_info);
+		priv->file_info = NULL;
+	}
+
+	if (priv->cancellable != NULL) {
+		g_object_unref (priv->cancellable);
+		priv->cancellable = NULL;
+	}
+
+	if (priv->mime_part != NULL) {
+		camel_object_unref (priv->mime_part);
+		priv->mime_part = NULL;
+	}
+
+	if (priv->emblem_timeout_id > 0) {
+		g_source_remove (priv->emblem_timeout_id);
+		priv->emblem_timeout_id = 0;
+	}
+
+	/* This accepts NULL arguments. */
+	gtk_tree_row_reference_free (priv->reference);
+	priv->reference = NULL;
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
 
 static void
-class_init (EAttachmentClass *klass)
+attachment_finalize (GObject *object)
+{
+	EAttachmentPrivate *priv;
+
+	priv = E_ATTACHMENT_GET_PRIVATE (object);
+
+	g_free (priv->disposition);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+attachment_class_init (EAttachmentClass *class)
 {
 	GObjectClass *object_class;
 
-	object_class = (GObjectClass*) klass;
-	parent_class = g_type_class_ref (G_TYPE_OBJECT);
-
-	object_class->finalize = finalise;
-	klass->changed = real_changed;
-	klass->update = real_update_attachment;
-
-	signals[CHANGED] = g_signal_new ("changed",
-					 E_TYPE_ATTACHMENT,
-					 G_SIGNAL_RUN_FIRST,
-					 G_STRUCT_OFFSET (EAttachmentClass, changed),
-					 NULL,
-					 NULL,
-					 g_cclosure_marshal_VOID__VOID,
-					 G_TYPE_NONE, 0);
-	signals[UPDATE] = g_signal_new ("update",
-					 E_TYPE_ATTACHMENT,
-					 G_SIGNAL_RUN_FIRST,
-					 G_STRUCT_OFFSET (EAttachmentClass, update),
-					 NULL,
-					 NULL,
-					 g_cclosure_marshal_VOID__VOID,
-					 G_TYPE_NONE, 0);
-
-}
-
-static void
-init (EAttachment *attachment)
-{
-	attachment->editor_gui = NULL;
-	attachment->body = NULL;
-	attachment->size = 0;
-	attachment->pixbuf_cache = NULL;
-	attachment->index = -1;
-	attachment->file_name = NULL;
-	attachment->percentage = -1;
-	attachment->description = NULL;
-	attachment->disposition = FALSE;
-	attachment->sign = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
-	attachment->encrypt = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
-	attachment->store_uri = NULL;
-	attachment->cancellable = NULL;
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EAttachmentPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = attachment_set_property;
+	object_class->get_property = attachment_get_property;
+	object_class->dispose = attachment_dispose;
+	object_class->finalize = attachment_finalize;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CAN_SHOW,
+		g_param_spec_boolean (
+			"can-show",
+			"Can Show",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DISPOSITION,
+		g_param_spec_string (
+			"disposition",
+			"Disposition",
+			NULL,
+			"attachment",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	/* FIXME Define a GEnumClass for this. */
+	g_object_class_install_property (
+		object_class,
+		PROP_ENCRYPTED,
+		g_param_spec_int (
+			"encrypted",
+			"Encrypted",
+			NULL,
+			CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE,
+			CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG,
+			CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FILE,
+		g_param_spec_object (
+			"file",
+			"File",
+			NULL,
+			G_TYPE_FILE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FILE_INFO,
+		g_param_spec_object (
+			"file-info",
+			"File Info",
+			NULL,
+			G_TYPE_FILE_INFO,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_LOADING,
+		g_param_spec_boolean (
+			"loading",
+			"Loading",
+			NULL,
+			FALSE,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MIME_PART,
+		g_param_spec_boxed (
+			"mime-part",
+			"MIME Part",
+			NULL,
+			E_TYPE_CAMEL_OBJECT,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PERCENT,
+		g_param_spec_int (
+			"percent",
+			"Percent",
+			NULL,
+			0,
+			100,
+			0,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_REFERENCE,
+		g_param_spec_boxed (
+			"reference",
+			"Reference",
+			NULL,
+			GTK_TYPE_TREE_ROW_REFERENCE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SAVING,
+		g_param_spec_boolean (
+			"saving",
+			"Saving",
+			NULL,
+			FALSE,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHOWN,
+		g_param_spec_boolean (
+			"shown",
+			"Shown",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	/* FIXME Define a GEnumClass for this. */
+	g_object_class_install_property (
+		object_class,
+		PROP_SIGNED,
+		g_param_spec_int (
+			"signed",
+			"Signed",
+			NULL,
+			CAMEL_CIPHER_VALIDITY_SIGN_NONE,
+			CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY,
+			CAMEL_CIPHER_VALIDITY_SIGN_NONE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+}
+
+static void
+attachment_init (EAttachment *attachment)
+{
+	attachment->priv = E_ATTACHMENT_GET_PRIVATE (attachment);
+	attachment->priv->cancellable = g_cancellable_new ();
+	attachment->priv->encrypted = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
+	attachment->priv->signed_ = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
+
+	g_signal_connect (
+		attachment, "notify::encrypted",
+		G_CALLBACK (attachment_update_icon_column), NULL);
+
+	g_signal_connect (
+		attachment, "notify::file-info",
+		G_CALLBACK (attachment_update_file_info_columns), NULL);
+
+	g_signal_connect (
+		attachment, "notify::file-info",
+		G_CALLBACK (attachment_update_icon_column), NULL);
+
+	g_signal_connect (
+		attachment, "notify::loading",
+		G_CALLBACK (attachment_update_icon_column), NULL);
+
+	g_signal_connect (
+		attachment, "notify::loading",
+		G_CALLBACK (attachment_update_progress_columns), NULL);
+
+	g_signal_connect (
+		attachment, "notify::percent",
+		G_CALLBACK (attachment_update_progress_columns), NULL);
+
+	g_signal_connect (
+		attachment, "notify::reference",
+		G_CALLBACK (attachment_update_file_info_columns), NULL);
+
+	g_signal_connect (
+		attachment, "notify::reference",
+		G_CALLBACK (attachment_update_icon_column), NULL);
+
+	g_signal_connect (
+		attachment, "notify::reference",
+		G_CALLBACK (attachment_update_progress_columns), NULL);
+
+	g_signal_connect (
+		attachment, "notify::saving",
+		G_CALLBACK (attachment_update_icon_column), NULL);
+
+	g_signal_connect (
+		attachment, "notify::saving",
+		G_CALLBACK (attachment_update_progress_columns), NULL);
+
+	g_signal_connect (
+		attachment, "notify::signed",
+		G_CALLBACK (attachment_update_icon_column), NULL);
+
+	g_signal_connect_swapped (
+		attachment->priv->cancellable, "cancelled",
+		G_CALLBACK (attachment_cancelled_cb), attachment);
 }
 
 GType
@@ -177,707 +861,1814 @@ e_attachment_get_type (void)
 {
 	static GType type = 0;
 
-	if (type == 0) {
-		static const GTypeInfo info = {
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
 			sizeof (EAttachmentClass),
-			NULL,
-			NULL,
-			(GClassInitFunc) class_init,
-			NULL,
-			NULL,
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) attachment_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
 			sizeof (EAttachment),
-			0,
-			(GInstanceInitFunc) init,
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) attachment_init,
+			NULL   /* value_table */
 		};
 
-		type = g_type_register_static (G_TYPE_OBJECT, "EAttachment", &info, 0);
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "EAttachment", &type_info, 0);
 	}
 
 	return type;
 }
 
-/**
- * file_ext_is:
- * @param file_name: path for file
- * @param ext: desired extension, with a dot
- * @return if file_name has extension ext or not
- **/
+EAttachment *
+e_attachment_new (void)
+{
+	return g_object_new (E_TYPE_ATTACHMENT, NULL);
+}
 
-static gboolean
-file_ext_is (const char *file_name, const char *ext)
+EAttachment *
+e_attachment_new_for_path (const gchar *path)
 {
-	int i, dot = -1;
+	EAttachment *attachment;
+	GFile *file;
 
-	if (!file_name || !ext)
-		return FALSE;
+	g_return_val_if_fail (path != NULL, NULL);
 
-	for (i = 0; file_name[i]; i++) {
-		if (file_name [i] == '.')
-			dot = i;
-	}
+	file = g_file_new_for_path (path);
+	attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL);
+	g_object_unref (file);
 
-	if (dot > 0) {
-		return 0 == g_ascii_strcasecmp (file_name + dot, ext);
-	}
+	return attachment;
+}
 
-	return FALSE;
+EAttachment *
+e_attachment_new_for_uri (const gchar *uri)
+{
+	EAttachment *attachment;
+	GFile *file;
+
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	file = g_file_new_for_uri (uri);
+	attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL);
+	g_object_unref (file);
+
+	return attachment;
 }
 
-static char *
-attachment_guess_mime_type (const char *file_name)
+EAttachment *
+e_attachment_new_for_message (CamelMimeMessage *message)
 {
-	char *type;
-	gchar *content = NULL;
+	CamelDataWrapper *wrapper;
+	CamelMimePart *mime_part;
+	EAttachment *attachment;
+	GString *description;
+	const gchar *subject;
 
-	type = e_util_guess_mime_type (file_name, TRUE);
+	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
 
-	if (type && strcmp (type, "text/directory") == 0 &&
-	    file_ext_is (file_name, ".vcf") &&
-	    g_file_get_contents (file_name, &content, NULL, NULL) &&
-	    content) {
-		EVCard *vc = e_vcard_new_from_string (content);
+	mime_part = camel_mime_part_new ();
+	camel_mime_part_set_disposition (mime_part, "inline");
+	subject = camel_mime_message_get_subject (message);
 
-		if (vc) {
-			g_free (type);
-			g_object_unref (G_OBJECT (vc));
+	description = g_string_new (_("Attached message"));
+	if (subject != NULL)
+		g_string_append_printf (description, " - %s", subject);
+	camel_mime_part_set_description (mime_part, description->str);
+	g_string_free (description, TRUE);
+
+	wrapper = CAMEL_DATA_WRAPPER (message);
+	camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
+	camel_mime_part_set_content_type (mime_part, "message/rfc822");
+
+	attachment = e_attachment_new ();
+	e_attachment_set_mime_part (attachment, mime_part);
+	camel_object_unref (mime_part);
+
+	return attachment;
+}
+
+void
+e_attachment_add_to_multipart (EAttachment *attachment,
+                               CamelMultipart *multipart,
+                               const gchar *default_charset)
+{
+	CamelContentType *content_type;
+	CamelDataWrapper *wrapper;
+	CamelMimePart *mime_part;
+
+	/* XXX EMsgComposer might be a better place for this function. */
+
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
+
+	/* Still loading?  Too bad. */
+	mime_part = e_attachment_get_mime_part (attachment);
+	if (mime_part == NULL)
+		return;
+
+	content_type = camel_mime_part_get_content_type (mime_part);
+	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+
+	if (CAMEL_IS_MULTIPART (wrapper))
+		goto exit;
+
+	/* For text content, determine the best encoding and character set. */
+	if (camel_content_type_is (content_type, "text", "*")) {
+		CamelTransferEncoding encoding;
+		CamelStreamFilter *filtered_stream;
+		CamelMimeFilterBestenc *filter;
+		CamelStream *stream;
+		const gchar *charset;
+
+		charset = camel_content_type_param (content_type, "charset");
+
+		/* Determine the best encoding by writing the MIME
+		 * part to a NULL stream with a "bestenc" filter. */
+		stream = camel_stream_null_new ();
+		filtered_stream = camel_stream_filter_new_with_stream (stream);
+		filter = camel_mime_filter_bestenc_new (
+			CAMEL_BESTENC_GET_ENCODING);
+		camel_stream_filter_add (
+			filtered_stream, CAMEL_MIME_FILTER (filter));
+		camel_data_wrapper_decode_to_stream (
+			wrapper, CAMEL_STREAM (filtered_stream));
+		camel_object_unref (filtered_stream);
+		camel_object_unref (stream);
+
+		/* Retrieve the best encoding from the filter. */
+		encoding = camel_mime_filter_bestenc_get_best_encoding (
+			filter, CAMEL_BESTENC_8BIT);
+		camel_mime_part_set_encoding (mime_part, encoding);
+		camel_object_unref (filter);
+
+		if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) {
+			/* The text fits within us-ascii, so this is safe.
+			 * FIXME Check that this isn't iso-2022-jp? */
+			default_charset = "us-ascii";
+
+		} else if (charset == NULL && default_charset == NULL) {
+			default_charset = attachment_get_default_charset ();
+			/* FIXME Check that this fits within the
+			 *       default_charset and if not, find one
+			 *       that does and/or allow the user to
+			 *       specify. */
+		}
 
-			type = g_strdup ("text/x-vcard");
+		if (charset == NULL) {
+			gchar *type;
+
+			camel_content_type_set_param (
+				content_type, "charset", default_charset);
+			type = camel_content_type_format (content_type);
+			camel_mime_part_set_content_type (mime_part, type);
+			g_free (type);
 		}
 
+	/* Otherwise, unless it's a message/rfc822, Base64 encode it. */
+	} else if (!CAMEL_IS_MIME_MESSAGE (wrapper))
+		camel_mime_part_set_encoding (
+			mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
+
+exit:
+	camel_multipart_add_part (multipart, mime_part);
+}
+
+void
+e_attachment_cancel (EAttachment *attachment)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	g_cancellable_cancel (attachment->priv->cancellable);
+}
+
+gboolean
+e_attachment_get_can_show (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+	return attachment->priv->can_show;
+}
+
+void
+e_attachment_set_can_show (EAttachment *attachment,
+                           gboolean can_show)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	attachment->priv->can_show = can_show;
+
+	g_object_notify (G_OBJECT (attachment), "can-show");
+}
+
+const gchar *
+e_attachment_get_disposition (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	return attachment->priv->disposition;
+}
+
+void
+e_attachment_set_disposition (EAttachment *attachment,
+                              const gchar *disposition)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	g_free (attachment->priv->disposition);
+	attachment->priv->disposition = g_strdup (disposition);
+
+	g_object_notify (G_OBJECT (attachment), "disposition");
+}
+
+GFile *
+e_attachment_get_file (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	return attachment->priv->file;
+}
+
+void
+e_attachment_set_file (EAttachment *attachment,
+                       GFile *file)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	if (file != NULL) {
+		g_return_if_fail (G_IS_FILE (file));
+		g_object_ref (file);
 	}
 
-	g_free (content);
+	if (attachment->priv->file != NULL)
+		g_object_unref (attachment->priv->file);
 
-	if (type) {
-		/* Check if returned mime_type is valid */
-		CamelContentType *ctype = camel_content_type_decode (type);
+	attachment->priv->file = file;
 
-		if (!ctype) {
-			g_free (type);
-			type = NULL;
-		} else
-			camel_content_type_unref (ctype);
+	g_object_notify (G_OBJECT (attachment), "file");
+}
+
+GFileInfo *
+e_attachment_get_file_info (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	return attachment->priv->file_info;
+}
+
+gboolean
+e_attachment_get_loading (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+	return attachment->priv->loading;
+}
+
+CamelMimePart *
+e_attachment_get_mime_part (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	return attachment->priv->mime_part;
+}
+
+void
+e_attachment_set_mime_part (EAttachment *attachment,
+                            CamelMimePart *mime_part)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	if (mime_part != NULL) {
+		g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+		camel_object_ref (mime_part);
 	}
 
-	return type;
+	if (attachment->priv->mime_part != NULL)
+		camel_object_unref (attachment->priv->mime_part);
+
+	attachment->priv->mime_part = mime_part;
+
+	g_object_notify (G_OBJECT (attachment), "mime-part");
 }
 
-
-/**
- * e_attachment_new:
- * @file_name: filename to attach
- * @disposition: Content-Disposition of the attachment
- * @ex: exception
- *
- * Return value: the new attachment, or %NULL on error
- **/
-EAttachment *
-e_attachment_new (const char *file_name, const char *disposition, CamelException *ex)
+gint
+e_attachment_get_percent (EAttachment *attachment)
 {
-	EAttachment *new;
-	CamelMimePart *part;
-	CamelDataWrapper *wrapper;
-	CamelStream *stream;
-	struct stat statbuf;
-	char *mime_type;
-	char *filename;
-	CamelURL *url;
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), 0);
+
+	return attachment->priv->percent;
+}
+
+GtkTreeRowReference *
+e_attachment_get_reference (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	return attachment->priv->reference;
+}
+
+void
+e_attachment_set_reference (EAttachment *attachment,
+                            GtkTreeRowReference *reference)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	if (reference != NULL)
+		reference = gtk_tree_row_reference_copy (reference);
+
+	gtk_tree_row_reference_free (attachment->priv->reference);
+	attachment->priv->reference = reference;
+
+	g_object_notify (G_OBJECT (attachment), "reference");
+}
+
+gboolean
+e_attachment_get_saving (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+	return attachment->priv->saving;
+}
+
+gboolean
+e_attachment_get_shown (EAttachment *attachment)
+{
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+	return attachment->priv->shown;
+}
+
+void
+e_attachment_set_shown (EAttachment *attachment,
+                        gboolean shown)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	attachment->priv->shown = shown;
+
+	g_object_notify (G_OBJECT (attachment), "shown");
+}
+
+camel_cipher_validity_encrypt_t
+e_attachment_get_encrypted (EAttachment *attachment)
+{
+	g_return_val_if_fail (
+		E_IS_ATTACHMENT (attachment),
+		CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE);
 
-	g_return_val_if_fail (file_name != NULL, NULL);
+	return attachment->priv->encrypted;
+}
+
+void
+e_attachment_set_encrypted (EAttachment *attachment,
+                            camel_cipher_validity_encrypt_t encrypted)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	attachment->priv->encrypted = encrypted;
+
+	g_object_notify (G_OBJECT (attachment), "encrypted");
+}
 
-	if (g_stat (file_name, &statbuf) < 0) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: %s"),
-				      file_name, g_strerror (errno));
+camel_cipher_validity_sign_t
+e_attachment_get_signed (EAttachment *attachment)
+{
+	g_return_val_if_fail (
+		E_IS_ATTACHMENT (attachment),
+		CAMEL_CIPHER_VALIDITY_SIGN_NONE);
+
+	return attachment->priv->signed_;
+}
+
+void
+e_attachment_set_signed (EAttachment *attachment,
+                         camel_cipher_validity_sign_t signed_)
+{
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+	attachment->priv->signed_ = signed_;
+
+	g_object_notify (G_OBJECT (attachment), "signed");
+}
+
+const gchar *
+e_attachment_get_description (EAttachment *attachment)
+{
+	GFileInfo *file_info;
+	const gchar *attribute;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+	file_info = e_attachment_get_file_info (attachment);
+
+	if (file_info == NULL)
 		return NULL;
-	}
 
-	/* return if it's not a regular file */
-	if (!S_ISREG (statbuf.st_mode)) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: not a regular file"),
-				      file_name);
+	return g_file_info_get_attribute_string (file_info, attribute);
+}
+
+const gchar *
+e_attachment_get_thumbnail_path (EAttachment *attachment)
+{
+	GFileInfo *file_info;
+	const gchar *attribute;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	attribute = G_FILE_ATTRIBUTE_THUMBNAIL_PATH;
+	file_info = e_attachment_get_file_info (attachment);
+
+	if (file_info == NULL)
 		return NULL;
-	}
 
-	if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: %s"),
-				      file_name, g_strerror (errno));
+	return g_file_info_get_attribute_byte_string (file_info, attribute);
+}
+
+gboolean
+e_attachment_is_rfc822 (EAttachment *attachment)
+{
+	GFileInfo *file_info;
+	const gchar *content_type;
+	gchar *mime_type;
+	gboolean is_rfc822;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+	file_info = e_attachment_get_file_info (attachment);
+	if (file_info == NULL)
+		return FALSE;
+
+	content_type = g_file_info_get_content_type (file_info);
+	if (content_type == NULL)
+		return FALSE;
+
+	mime_type = g_content_type_get_mime_type (content_type);
+	is_rfc822 = (g_ascii_strcasecmp (mime_type, "message/rfc822") == 0);
+	g_free (mime_type);
+
+	return is_rfc822;
+}
+
+GList *
+e_attachment_list_apps (EAttachment *attachment)
+{
+	GList *app_info_list;
+	GFileInfo *file_info;
+	const gchar *content_type;
+	const gchar *display_name;
+	gchar *allocated;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+	file_info = e_attachment_get_file_info (attachment);
+	if (file_info == NULL)
 		return NULL;
-	}
 
-	if ((mime_type = attachment_guess_mime_type (file_name))) {
-		if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
-			wrapper = (CamelDataWrapper *) camel_mime_message_new ();
-		} else {
-			wrapper = camel_data_wrapper_new ();
-		}
+	content_type = g_file_info_get_content_type (file_info);
+	display_name = g_file_info_get_display_name (file_info);
+	g_return_val_if_fail (content_type != NULL, NULL);
+
+	app_info_list = g_app_info_get_all_for_type (content_type);
+
+	if (app_info_list != NULL || display_name == NULL)
+		goto exit;
+
+	if (!g_content_type_is_unknown (content_type))
+		goto exit;
 
-		camel_data_wrapper_construct_from_stream (wrapper, stream);
-		camel_data_wrapper_set_mime_type (wrapper, mime_type);
-		g_free (mime_type);
-	} else {
+	allocated = g_content_type_guess (display_name, NULL, 0, NULL);
+	app_info_list = g_app_info_get_all_for_type (allocated);
+	g_free (allocated);
+
+exit:
+	return app_info_list;
+}
+
+/************************* e_attachment_load_async() *************************/
+
+typedef struct _LoadContext LoadContext;
+
+struct _LoadContext {
+	EAttachment *attachment;
+	GSimpleAsyncResult *simple;
+
+	GInputStream *input_stream;
+	GOutputStream *output_stream;
+	GFileInfo *file_info;
+	goffset total_num_bytes;
+	gssize bytes_read;
+	gchar buffer[4096];
+};
+
+/* Forward Declaration */
+static void
+attachment_load_stream_read_cb (GInputStream *input_stream,
+                                GAsyncResult *result,
+                                LoadContext *load_context);
+
+static LoadContext *
+attachment_load_context_new (EAttachment *attachment,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	LoadContext *load_context;
+	GSimpleAsyncResult *simple;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (attachment), callback,
+		user_data, e_attachment_load_async);
+
+	load_context = g_slice_new0 (LoadContext);
+	load_context->attachment = g_object_ref (attachment);
+	load_context->simple = simple;
+
+	attachment_set_loading (load_context->attachment, TRUE);
+
+	return load_context;
+}
+
+static void
+attachment_load_context_free (LoadContext *load_context)
+{
+	/* Do not free the GSimpleAsyncResult. */
+	g_object_unref (load_context->attachment);
+
+	if (load_context->input_stream != NULL)
+		g_object_unref (load_context->input_stream);
+
+	if (load_context->output_stream != NULL)
+		g_object_unref (load_context->output_stream);
+
+	if (load_context->file_info != NULL)
+		g_object_unref (load_context->file_info);
+
+	g_slice_free (LoadContext, load_context);
+}
+
+static gboolean
+attachment_load_check_for_error (LoadContext *load_context,
+                                 GError *error)
+{
+	GSimpleAsyncResult *simple;
+
+	if (error == NULL)
+		return FALSE;
+
+	/* Steal the result. */
+	simple = load_context->simple;
+	load_context->simple = NULL;
+
+	g_simple_async_result_set_from_error (simple, error);
+	g_simple_async_result_complete (simple);
+	g_error_free (error);
+
+	attachment_load_context_free (load_context);
+
+	return TRUE;
+}
+
+static void
+attachment_load_finish (LoadContext *load_context)
+{
+	GFileInfo *file_info;
+	EAttachment *attachment;
+	GMemoryOutputStream *output_stream;
+	GSimpleAsyncResult *simple;
+	CamelDataWrapper *wrapper;
+	CamelMimePart *mime_part;
+	CamelStream *stream;
+	const gchar *attribute;
+	const gchar *content_type;
+	const gchar *display_name;
+	const gchar *description;
+	const gchar *disposition;
+	gchar *mime_type;
+	gpointer data;
+	gsize size;
+
+	/* Steal the result. */
+	simple = load_context->simple;
+	load_context->simple = NULL;
+
+	file_info = load_context->file_info;
+	attachment = load_context->attachment;
+	output_stream = G_MEMORY_OUTPUT_STREAM (load_context->output_stream);
+
+	if (e_attachment_is_rfc822 (attachment))
+		wrapper = (CamelDataWrapper *) camel_mime_message_new ();
+	else
 		wrapper = camel_data_wrapper_new ();
-		camel_data_wrapper_construct_from_stream (wrapper, stream);
-		camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
-	}
 
+	content_type = g_file_info_get_content_type (file_info);
+	mime_type = g_content_type_get_mime_type (content_type);
+
+	data = g_memory_output_stream_get_data (output_stream);
+	size = g_memory_output_stream_get_data_size (output_stream);
+
+	stream = camel_stream_mem_new_with_buffer (data, size);
+	camel_data_wrapper_construct_from_stream (wrapper, stream);
+	camel_data_wrapper_set_mime_type (wrapper, mime_type);
+	camel_stream_close (stream);
 	camel_object_unref (stream);
 
-	part = camel_mime_part_new ();
-	camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
+	mime_part = camel_mime_part_new ();
+	camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
+
 	camel_object_unref (wrapper);
+	g_free (mime_type);
 
-	camel_mime_part_set_disposition (part, disposition);
-	filename = g_path_get_basename (file_name);
-	camel_mime_part_set_filename (part, filename);
-
-#if 0
-	/* Note: Outlook 2002 is broken with respect to Content-Ids on
-           non-multipart/related parts, so as an interoperability
-           workaround, don't set a Content-Id on these parts. Fixes
-           bug #10032 */
-	/* set the Content-Id */
-	content_id = camel_header_msgid_generate ();
-	camel_mime_part_set_content_id (part, content_id);
-	g_free (content_id);
-#endif
+	display_name = g_file_info_get_display_name (file_info);
+	if (display_name != NULL)
+		camel_mime_part_set_filename (mime_part, display_name);
 
-	new = g_object_new (E_TYPE_ATTACHMENT, NULL);
-	new->editor_gui = NULL;
-	new->body = part;
-	new->size = statbuf.st_size;
-	new->guessed_type = TRUE;
-	new->cancellable = NULL;
-	new->is_available_local = TRUE;
-	new->file_name = filename;
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+	description = g_file_info_get_attribute_string (file_info, attribute);
+	if (description != NULL)
+		camel_mime_part_set_description (mime_part, description);
 
-	url = camel_url_new ("file://", NULL);
-	camel_url_set_path (url, file_name);
-	new->store_uri = camel_url_to_string (url, 0);
-	camel_url_free (url);
+	disposition = e_attachment_get_disposition (attachment);
+	if (disposition != NULL)
+		camel_mime_part_set_disposition (mime_part, disposition);
 
-	return new;
-}
+	g_simple_async_result_set_op_res_gpointer (
+		simple, mime_part, (GDestroyNotify) camel_object_unref);
+
+	g_simple_async_result_complete (simple);
 
+	attachment_load_context_free (load_context);
+}
 
-typedef struct {
+static void
+attachment_load_write_cb (GOutputStream *output_stream,
+                          GAsyncResult *result,
+                          LoadContext *load_context)
+{
 	EAttachment *attachment;
-	char *file_name;
-	char *uri;
-	GtkWindow *parent; /* for error dialog */
-
-	guint64 file_size; /* zero indicates unknown size */
-	GInputStream *istream; /* read from here ... */
-	GOutputStream *ostream; /* ...and write into this. */
-	gboolean was_error;
 	GCancellable *cancellable;
+	GInputStream *input_stream;
+	gssize bytes_written;
+	GError *error = NULL;
+
+	bytes_written = g_output_stream_write_finish (
+		output_stream, result, &error);
 
-	void *buffer; /* read into this, not more than buffer_size bytes */
-	gsize buffer_size;
-} DownloadInfo;
+	if (attachment_load_check_for_error (load_context, error))
+		return;
+
+	attachment = load_context->attachment;
+	cancellable = attachment->priv->cancellable;
+	input_stream = load_context->input_stream;
+
+	attachment_progress_cb (
+		g_seekable_tell (G_SEEKABLE (output_stream)),
+		load_context->total_num_bytes, attachment);
+
+	if (bytes_written < load_context->bytes_read) {
+		g_memmove (
+			load_context->buffer,
+			load_context->buffer + bytes_written,
+			load_context->bytes_read - bytes_written);
+		load_context->bytes_read -= bytes_written;
+
+		g_output_stream_write_async (
+			output_stream,
+			load_context->buffer,
+			load_context->bytes_read,
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback) attachment_load_write_cb,
+			load_context);
+	} else
+		g_input_stream_read_async (
+			input_stream,
+			load_context->buffer,
+			sizeof (load_context->buffer),
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback) attachment_load_stream_read_cb,
+			load_context);
+}
 
 static void
-download_info_free (DownloadInfo *download_info)
+attachment_load_stream_read_cb (GInputStream *input_stream,
+                                GAsyncResult *result,
+                                LoadContext *load_context)
 {
-	/* if there was an error, then free attachment too */
-	if (download_info->was_error)
-		g_object_unref (download_info->attachment);
+	EAttachment *attachment;
+	GCancellable *cancellable;
+	GOutputStream *output_stream;
+	gssize bytes_read;
+	GError *error = NULL;
 
-	if (download_info->ostream)
-		g_object_unref (download_info->ostream);
+	bytes_read = g_input_stream_read_finish (
+		input_stream, result, &error);
 
-	if (download_info->istream)
-		g_object_unref (download_info->istream);
+	if (attachment_load_check_for_error (load_context, error))
+		return;
 
-	if (download_info->cancellable)
-		g_object_unref (download_info->cancellable);
+	if (bytes_read == 0) {
+		attachment_load_finish (load_context);
+		return;
+	}
 
-	g_free (download_info->file_name);
-	g_free (download_info->uri);
-	g_free (download_info->buffer);
-	g_free (download_info);
+	attachment = load_context->attachment;
+	cancellable = attachment->priv->cancellable;
+	output_stream = load_context->output_stream;
+	load_context->bytes_read = bytes_read;
+
+	g_output_stream_write_async (
+		output_stream,
+		load_context->buffer,
+		load_context->bytes_read,
+		G_PRIORITY_DEFAULT, cancellable,
+		(GAsyncReadyCallback) attachment_load_write_cb,
+		load_context);
 }
 
 static void
-data_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+attachment_load_file_read_cb (GFile *file,
+                              GAsyncResult *result,
+                              LoadContext *load_context)
 {
-	DownloadInfo *download_info = (DownloadInfo *)user_data;
+	EAttachment *attachment;
+	GCancellable *cancellable;
+	GFileInputStream *input_stream;
+	GOutputStream *output_stream;
 	GError *error = NULL;
-	gssize read;
 
-	g_return_if_fail (download_info != NULL);
+	/* Input stream might be NULL, so don't use cast macro. */
+	input_stream = g_file_read_finish (file, result, &error);
+	load_context->input_stream = (GInputStream *) input_stream;
 
-	if (g_cancellable_is_cancelled (download_info->cancellable)) {
-		/* finish the operation and close both streams */
-		g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, NULL);
+	if (attachment_load_check_for_error (load_context, error))
+		return;
 
-		g_output_stream_close (download_info->ostream, NULL, NULL);
-		g_input_stream_close  (download_info->istream, NULL, NULL);
+	/* Load the contents into a GMemoryOutputStream. */
+	output_stream = g_memory_output_stream_new (
+		NULL, 0, g_realloc, g_free);
+
+	attachment = load_context->attachment;
+	cancellable = attachment->priv->cancellable;
+	load_context->output_stream = output_stream;
+
+	g_input_stream_read_async (
+		load_context->input_stream,
+		load_context->buffer,
+		sizeof (load_context->buffer),
+		G_PRIORITY_DEFAULT, cancellable,
+		(GAsyncReadyCallback) attachment_load_stream_read_cb,
+		load_context);
+}
 
-		/* The only way how to get this canceled is in EAttachment's finalize method,
-		   and because the download_info_free free's the attachment on error,
-		   then do not consider cancellation as an error. */
-		download_info_free (download_info);
+static void
+attachment_load_query_info_cb (GFile *file,
+                               GAsyncResult *result,
+                               LoadContext *load_context)
+{
+	EAttachment *attachment;
+	GCancellable *cancellable;
+	GFileInfo *file_info;
+	GError *error = NULL;
+
+	attachment = load_context->attachment;
+	cancellable = attachment->priv->cancellable;
+
+	file_info = g_file_query_info_finish (file, result, &error);
+	attachment_set_file_info (attachment, file_info);
+	load_context->file_info = file_info;
+
+	if (attachment_load_check_for_error (load_context, error))
 		return;
+
+	load_context->total_num_bytes = g_file_info_get_size (file_info);
+
+	g_file_read_async (
+		file, G_PRIORITY_DEFAULT,
+		cancellable, (GAsyncReadyCallback)
+		attachment_load_file_read_cb, load_context);
+}
+
+static void
+attachment_load_from_mime_part (LoadContext *load_context)
+{
+	GFileInfo *file_info;
+	EAttachment *attachment;
+	GSimpleAsyncResult *simple;
+	CamelContentType *content_type;
+	CamelMimePart *mime_part;
+	const gchar *attribute;
+	const gchar *string;
+	gchar *allocated;
+	goffset size;
+
+	attachment = load_context->attachment;
+	mime_part = e_attachment_get_mime_part (attachment);
+
+	file_info = g_file_info_new ();
+	load_context->file_info = file_info;
+
+	content_type = camel_mime_part_get_content_type (mime_part);
+	allocated = camel_content_type_simple (content_type);
+	if (allocated != NULL) {
+		GIcon *icon;
+		gchar *cp;
+
+		/* GIO expects lowercase MIME types. */
+		for (cp = allocated; *cp != '\0'; cp++)
+			*cp = g_ascii_tolower (*cp);
+
+		/* Swap the MIME type for a content type. */
+		cp = g_content_type_from_mime_type (allocated);
+		g_free (allocated);
+		allocated = cp;
+
+		/* Use the MIME part's filename if we have to. */
+		if (g_content_type_is_unknown (allocated)) {
+			string = camel_mime_part_get_filename (mime_part);
+			if (string != NULL) {
+				g_free (allocated);
+				allocated = g_content_type_guess (
+					string, NULL, 0, NULL);
+			}
+		}
+
+		g_file_info_set_content_type (file_info, allocated);
+
+		icon = g_content_type_get_icon (allocated);
+		if (icon != NULL) {
+			g_file_info_set_icon (file_info, icon);
+			g_object_unref (icon);
+		}
 	}
+	g_free (allocated);
 
-	read = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
+	string = camel_mime_part_get_filename (mime_part);
+	if (string == NULL)
+		/* Translators: Default attachment filename. */
+		string = _("attachment.dat");
+	g_file_info_set_display_name (file_info, string);
 
-	if (!error)
-		g_output_stream_write_all (download_info->ostream, download_info->buffer, read, NULL, download_info->cancellable, &error);
+	attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+	string = camel_mime_part_get_description (mime_part);
+	if (string != NULL)
+		g_file_info_set_attribute_string (
+			file_info, attribute, string);
 
-	if (error) {
-		download_info->was_error = error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED;
-		if (download_info->was_error)
-			e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, error->message, NULL);
+	size = (goffset) camel_mime_part_get_content_size (mime_part);
+	g_file_info_set_size (file_info, size);
 
-		g_error_free (error);
+	string = camel_mime_part_get_disposition (mime_part);
+	e_attachment_set_disposition (attachment, string);
+
+	attachment_set_file_info (attachment, file_info);
 
-		download_info->attachment->cancellable = NULL;
-		download_info_free (download_info);
+	/* Steal the result. */
+	simple = load_context->simple;
+	load_context->simple = NULL;
+
+	camel_object_ref (mime_part);
+	g_simple_async_result_set_op_res_gpointer (
+		simple, mime_part,
+		(GDestroyNotify) camel_object_unref);
+	g_simple_async_result_complete_in_idle (simple);
+
+	attachment_load_context_free (load_context);
+}
+
+void
+e_attachment_load_async (EAttachment *attachment,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+	LoadContext *load_context;
+	GCancellable *cancellable;
+	CamelMimePart *mime_part;
+	GFile *file;
+
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (callback != NULL);
+
+	if (e_attachment_get_loading (attachment)) {
+		g_simple_async_report_error_in_idle (
+			G_OBJECT (attachment), callback, user_data,
+			G_IO_ERROR, G_IO_ERROR_BUSY,
+			_("A load operation is already in progress"));
+		return;
+	}
+
+	if (e_attachment_get_saving (attachment)) {
+		g_simple_async_report_error_in_idle (
+			G_OBJECT (attachment), callback, user_data,
+			G_IO_ERROR, G_IO_ERROR_BUSY,
+			_("A save operation is already in progress"));
 		return;
 	}
 
-	if (read == 0) {
-		CamelException ex;
+	file = e_attachment_get_file (attachment);
+	mime_part = e_attachment_get_mime_part (attachment);
+	g_return_if_fail (file != NULL || mime_part != NULL);
 
-		/* done with reading */
-		g_output_stream_close (download_info->ostream, NULL, NULL);
-		g_input_stream_close  (download_info->istream, NULL, NULL);
+	load_context = attachment_load_context_new (
+		attachment, callback, user_data);
 
-		download_info->attachment->cancellable = NULL;
+	cancellable = attachment->priv->cancellable;
+	g_cancellable_reset (cancellable);
 
-		camel_exception_init (&ex);
-		e_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex);
+	if (file != NULL)
+		g_file_query_info_async (
+			file, ATTACHMENT_QUERY,
+			G_FILE_QUERY_INFO_NONE,G_PRIORITY_DEFAULT,
+			cancellable, (GAsyncReadyCallback)
+			attachment_load_query_info_cb, load_context);
 
-		if (camel_exception_is_set (&ex)) {
-			download_info->was_error = TRUE;
-			e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, camel_exception_get_description (&ex), NULL);
-			camel_exception_clear (&ex);
-		}
+	else if (mime_part != NULL)
+		attachment_load_from_mime_part (load_context);
+
+}
+
+gboolean
+e_attachment_load_finish (EAttachment *attachment,
+                          GAsyncResult *result,
+                          GError **error)
+{
+	GSimpleAsyncResult *simple;
+	CamelMimePart *mime_part;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	mime_part = g_simple_async_result_get_op_res_gpointer (simple);
+	if (mime_part != NULL)
+		e_attachment_set_mime_part (attachment, mime_part);
+	g_simple_async_result_propagate_error (simple, error);
+	g_object_unref (simple);
+
+	attachment_set_loading (attachment, FALSE);
+
+	return (mime_part != NULL);
+}
 
-		download_info->attachment->percentage = -1;
-		download_info->attachment->is_available_local = TRUE;
-		g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+void
+e_attachment_load_handle_error (EAttachment *attachment,
+                                GAsyncResult *result,
+                                GtkWindow *parent)
+{
+	GtkWidget *dialog;
+	GFileInfo *file_info;
+	GtkTreeRowReference *reference;
+	const gchar *display_name;
+	const gchar *primary_text;
+	GError *error = NULL;
 
-		download_info_free (download_info);
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (G_IS_ASYNC_RESULT (result));
+	g_return_if_fail (GTK_IS_WINDOW (parent));
+
+	if (e_attachment_load_finish (attachment, result, &error))
 		return;
-	} else 	if (download_info->file_size) {
-		download_info->attachment->percentage = read * 100 / download_info->file_size;
-		download_info->file_size -= MIN (download_info->file_size, read);
-		g_signal_emit (download_info->attachment, signals[UPDATE], 0);
-	} else {
-		download_info->attachment->percentage = 0;
-		g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+
+	/* XXX Calling EAttachmentStore functions from here violates
+	 *     the abstraction, but for now it's not hurting anything. */
+	reference = e_attachment_get_reference (attachment);
+	if (gtk_tree_row_reference_valid (reference)) {
+		GtkTreeModel *model;
+
+		model = gtk_tree_row_reference_get_model (reference);
+
+		e_attachment_store_remove_attachment (
+			E_ATTACHMENT_STORE (model), attachment);
 	}
 
-	/* read next chunk */
-	g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+	/* Ignore cancellations. */
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	file_info = e_attachment_get_file_info (attachment);
+
+	if (file_info != NULL)
+		display_name = g_file_info_get_display_name (file_info);
+	else
+		display_name = NULL;
+
+	if (display_name != NULL)
+		primary_text = g_strdup_printf (
+			_("Could not load '%s'"), display_name);
+	else
+		primary_text = g_strdup_printf (
+			_("Could not load the attachment"));
+
+	dialog = gtk_message_dialog_new_with_markup (
+		parent, GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+		"<big><b>%s</b></big>", primary_text);
+
+	gtk_message_dialog_format_secondary_text (
+		GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
+
+	gtk_dialog_run (GTK_DIALOG (dialog));
+
+	gtk_widget_destroy (dialog);
+	g_error_free (error);
+}
+
+/************************* e_attachment_open_async() *************************/
+
+typedef struct _OpenContext OpenContext;
+
+struct _OpenContext {
+	EAttachment *attachment;
+	GSimpleAsyncResult *simple;
+
+	GAppInfo *app_info;
+};
+
+static OpenContext *
+attachment_open_context_new (EAttachment *attachment,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	OpenContext *open_context;
+	GSimpleAsyncResult *simple;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (attachment), callback,
+		user_data, e_attachment_open_async);
+
+	open_context = g_slice_new0 (OpenContext);
+	open_context->attachment = g_object_ref (attachment);
+	open_context->simple = simple;
+
+	return open_context;
+}
+
+static void
+attachment_open_context_free (OpenContext *open_context)
+{
+	/* Do not free the GSimpleAsyncResult. */
+	g_object_unref (open_context->attachment);
+
+	if (open_context->app_info != NULL)
+		g_object_unref (open_context->app_info);
+
+	g_slice_free (OpenContext, open_context);
 }
 
 static gboolean
-download_to_local_path (DownloadInfo *download_info, CamelException *ex)
+attachment_open_check_for_error (OpenContext *open_context,
+                                 GError *error)
 {
-	GError *error = NULL;
-	GFile *src = g_file_new_for_uri (download_info->uri);
-	GFile *des = g_file_new_for_path (download_info->file_name);
-	gboolean res = FALSE;
+	GSimpleAsyncResult *simple;
 
-	g_return_val_if_fail (src != NULL && des != NULL, FALSE);
+	if (error == NULL)
+		return FALSE;
 
-	download_info->ostream = G_OUTPUT_STREAM (g_file_replace (des, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));
+	/* Steal the result. */
+	simple = open_context->simple;
+	open_context->simple = NULL;
 
-	if (download_info->ostream && !error) {
-		GFileInfo *fi;
+	g_simple_async_result_set_from_error (simple, error);
+	g_simple_async_result_complete (simple);
+	g_error_free (error);
 
-		fi = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+	attachment_open_context_free (open_context);
 
-		if (fi) {
-			download_info->file_size = g_file_info_get_attribute_uint64 (fi, G_FILE_ATTRIBUTE_STANDARD_SIZE);
-			g_object_unref (fi);
-		} else {
-			download_info->file_size = 0;
-		}
+	return TRUE;
+}
 
-		download_info->istream = G_INPUT_STREAM (g_file_read (src, NULL, &error));
+static void
+attachment_open_file (GFile *file,
+                      OpenContext *open_context)
+{
+	GdkAppLaunchContext *context;
+	GSimpleAsyncResult *simple;
+	GList *file_list;
+	gboolean success;
+	GError *error = NULL;
 
-		if (download_info->istream && !error) {
-			download_info->cancellable = g_cancellable_new ();
-			download_info->attachment->cancellable = download_info->cancellable;
-			download_info->buffer_size = 10240; /* max 10KB chunk */
-			download_info->buffer = g_malloc (sizeof (char) * download_info->buffer_size);
+	/* Steal the result. */
+	simple = open_context->simple;
+	open_context->simple = NULL;
 
-			g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+	/* Find a default app based on content type. */
+	if (open_context->app_info == NULL) {
+		EAttachment *attachment;
+		GFileInfo *file_info;
+		const gchar *content_type;
 
-			res = TRUE;
-		}
+		attachment = open_context->attachment;
+		file_info = e_attachment_get_file_info (attachment);
+		if (file_info == NULL)
+			goto exit;
+
+		content_type = g_file_info_get_content_type (file_info);
+		if (content_type == NULL)
+			goto exit;
+
+		open_context->app_info = g_app_info_get_default_for_type (
+			content_type, FALSE);
 	}
 
-	if (error) {
-		/* propagate error */
-		if (ex)
-			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, error->message);
+	if (open_context->app_info == NULL)
+		goto exit;
+
+	context = gdk_app_launch_context_new ();
+	file_list = g_list_prepend (NULL, file);
+
+	success = g_app_info_launch (
+		open_context->app_info, file_list,
+		G_APP_LAUNCH_CONTEXT (context), &error);
 
+	g_simple_async_result_set_op_res_gboolean (simple, success);
+
+	g_list_free (file_list);
+	g_object_unref (context);
+
+exit:
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
 		g_error_free (error);
-		download_info->was_error = TRUE;
-		download_info_free (download_info);
 	}
 
-	g_object_unref (src);
-	g_object_unref (des);
+	g_simple_async_result_complete (simple);
+	attachment_open_context_free (open_context);
+}
 
-	return res;
+static void
+attachment_open_save_finished_cb (EAttachment *attachment,
+                                  GAsyncResult *result,
+                                  OpenContext *open_context)
+{
+	GFile *file;
+	GError *error = NULL;
+
+	file = e_attachment_save_finish (attachment, result, &error);
+
+	if (attachment_open_check_for_error (open_context, error))
+		return;
+
+	attachment_open_file (file, open_context);
+	g_object_unref (file);
 }
 
-EAttachment *
-e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, const char *disposition, const char *path, CamelException *ex)
+static void
+attachment_open_save_temporary (OpenContext *open_context)
 {
-	EAttachment *new;
-	DownloadInfo *download_info;
-	CamelURL *url;
-	char *base;
+	GFile *file;
+	gchar *template;
+	gchar *path;
+	GError *error = NULL;
 
-	g_return_val_if_fail (uri != NULL, NULL);
+	errno = 0;
 
-	url = camel_url_new (uri, NULL);
-	base = g_path_get_basename (url->path);
-	camel_url_free (url);
-
-	new = g_object_new (E_TYPE_ATTACHMENT, NULL);
-	new->editor_gui = NULL;
-	new->body = NULL;
-	new->size = 0;
-	new->guessed_type = FALSE;
-	new->cancellable = NULL;
-	new->is_available_local = FALSE;
-	new->percentage = 0;
-	new->file_name = g_build_filename (path, base, NULL);
-
-	g_free (base);
-
-	download_info = g_new0 (DownloadInfo, 1);
-	download_info->attachment = new;
-	download_info->file_name = g_strdup (new->file_name);
-	download_info->uri = g_strdup (uri);
-	download_info->parent = error_dlg_parent;
-	download_info->was_error = FALSE;
-
-	/* it frees all on the error, so do not free it twice */
-	if (!download_to_local_path (download_info, ex))
-		return NULL;
+	/* XXX This could trigger a blocking temp directory cleanup. */
+	template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ());
+	path = e_mktemp (template);
+	g_free (template);
 
-	return new;
+	/* XXX Let's hope errno got set properly. */
+	if (path == NULL)
+		g_set_error (
+			&error, G_FILE_ERROR,
+			g_file_error_from_errno (errno),
+			"%s", g_strerror (errno));
+
+	/* We already know if there's an error, but this does the cleanup. */
+	if (attachment_open_check_for_error (open_context, error))
+		return;
+
+	file = g_file_new_for_path (path);
+
+	g_free (path);
+
+	e_attachment_save_async (
+		open_context->attachment, file, (GAsyncReadyCallback)
+		attachment_open_save_finished_cb, open_context);
+
+	g_object_unref (file);
+}
+
+void
+e_attachment_open_async (EAttachment *attachment,
+                         GAppInfo *app_info,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+	OpenContext *open_context;
+	CamelMimePart *mime_part;
+	GFile *file;
+
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (callback != NULL);
+
+	file = e_attachment_get_file (attachment);
+	mime_part = e_attachment_get_mime_part (attachment);
+	g_return_if_fail (file != NULL || mime_part != NULL);
+
+	open_context = attachment_open_context_new (
+		attachment, callback, user_data);
+
+	if (G_IS_APP_INFO (app_info))
+		open_context->app_info = g_object_ref (app_info);
+
+	/* If the attachment already references a GFile, we can launch
+	 * the application directly.  Otherwise we have to save the MIME
+	 * part to a temporary file and launch the application from that. */
+	if (file != NULL) {
+		attachment_open_file (file, open_context);
+
+	} else if (mime_part != NULL)
+		attachment_open_save_temporary (open_context);
 }
 
+gboolean
+e_attachment_open_finish (EAttachment *attachment,
+                          GAsyncResult *result,
+                          GError **error)
+{
+	GSimpleAsyncResult *simple;
+	gboolean success;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	success = g_simple_async_result_get_op_res_gboolean (simple);
+	g_simple_async_result_propagate_error (simple, error);
+	g_object_unref (simple);
+
+	return success;
+}
 
 void
-e_attachment_build_remote_file (const char *file_name, EAttachment *attachment, const char *disposition, CamelException *ex)
+e_attachment_open_handle_error (EAttachment *attachment,
+                                GAsyncResult *result,
+                                GtkWindow *parent)
 {
-	CamelMimePart *part;
-	CamelDataWrapper *wrapper;
-	CamelStream *stream;
-	struct stat statbuf;
-	char *mime_type;
-	char *filename;
-	CamelURL *url;
-
-	g_return_if_fail (file_name != NULL);
-
-	if (g_stat (file_name, &statbuf) == -1) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: %s"),
-				      file_name, g_strerror (errno));
-		g_message ("Cannot attach file %s: %s\n", file_name, g_strerror (errno));
-		return;
-	}
+	GtkWidget *dialog;
+	GFileInfo *file_info;
+	const gchar *display_name;
+	const gchar *primary_text;
+	GError *error = NULL;
 
-	/* return if it's not a regular file */
-	if (!S_ISREG (statbuf.st_mode)) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: not a regular file"),
-				      file_name);
-		g_message ("Cannot attach file %s: not a regular file", file_name);
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (G_IS_ASYNC_RESULT (result));
+	g_return_if_fail (GTK_IS_WINDOW (parent));
+
+	if (e_attachment_open_finish (attachment, result, &error))
 		return;
-	}
 
-	if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Cannot attach file %s: %s"),
-				      file_name, g_strerror (errno));
+	/* Ignore cancellations. */
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
-	}
 
-	if ((mime_type = attachment_guess_mime_type (file_name))) {
-		if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
-			wrapper = (CamelDataWrapper *) camel_mime_message_new ();
-		} else {
-			wrapper = camel_data_wrapper_new ();
-		}
+	file_info = e_attachment_get_file_info (attachment);
 
-		camel_data_wrapper_construct_from_stream (wrapper, stream);
-		camel_data_wrapper_set_mime_type (wrapper, mime_type);
-		g_free (mime_type);
-	} else {
-		wrapper = camel_data_wrapper_new ();
-		camel_data_wrapper_construct_from_stream (wrapper, stream);
-		camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
-	}
+	if (file_info != NULL)
+		display_name = g_file_info_get_display_name (file_info);
+	else
+		display_name = NULL;
 
-	camel_object_unref (stream);
+	if (display_name != NULL)
+		primary_text = g_strdup_printf (
+			_("Could not open '%s'"), display_name);
+	else
+		primary_text = g_strdup_printf (
+			_("Could not open the attachment"));
 
-	part = camel_mime_part_new ();
-	camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
-	camel_object_unref (wrapper);
+	dialog = gtk_message_dialog_new_with_markup (
+		parent, GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+		"<big><b>%s</b></big>", primary_text);
 
-	if (attachment->disposition)
-		camel_mime_part_set_disposition (part, "inline");
-	else
-		camel_mime_part_set_disposition (part, "attachment");
+	gtk_message_dialog_format_secondary_text (
+		GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
 
-	if (!attachment->file_name)
-		filename = g_path_get_basename (file_name);
-	else
-		filename = g_path_get_basename (attachment->file_name);
+	gtk_dialog_run (GTK_DIALOG (dialog));
 
-	camel_mime_part_set_filename (part, filename);
+	gtk_widget_destroy (dialog);
+	g_error_free (error);
+}
 
-	if (attachment->description) {
-		camel_mime_part_set_description (part, attachment->description);
-		g_free (attachment->description);
-		attachment->description = NULL;
-	}
+/************************* e_attachment_save_async() *************************/
 
-	attachment->editor_gui = NULL;
-	attachment->body = part;
-	attachment->size = statbuf.st_size;
-	attachment->guessed_type = TRUE;
-	g_free (attachment->file_name);
-	attachment->file_name = filename;
+typedef struct _SaveContext SaveContext;
 
-	url = camel_url_new ("file://", NULL);
-	camel_url_set_path (url, file_name);
-	attachment->store_uri = camel_url_to_string (url, 0);
-	camel_url_free (url);
+struct _SaveContext {
+	EAttachment *attachment;
+	GSimpleAsyncResult *simple;
+
+	GFile *directory;
+	GFile *destination;
+	GInputStream *input_stream;
+	GOutputStream *output_stream;
+	goffset total_num_bytes;
+	gssize bytes_read;
+	gchar buffer[4096];
+	gint count;
+};
 
-}
+/* Forward Declaration */
+static void
+attachment_save_read_cb (GInputStream *input_stream,
+                         GAsyncResult *result,
+                         SaveContext *save_context);
+
+static SaveContext *
+attachment_save_context_new (EAttachment *attachment,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	SaveContext *save_context;
+	GSimpleAsyncResult *simple;
 
+	simple = g_simple_async_result_new (
+		G_OBJECT (attachment), callback,
+		user_data, e_attachment_save_async);
 
-/**
- * e_attachment_new_from_mime_part:
- * @part: a CamelMimePart
- *
- * Return value: a new EAttachment based on the mime part
- **/
-EAttachment *
-e_attachment_new_from_mime_part (CamelMimePart *part)
+	save_context = g_slice_new0 (SaveContext);
+	save_context->attachment = g_object_ref (attachment);
+	save_context->simple = simple;
+
+	attachment_set_saving (save_context->attachment, TRUE);
+
+	return save_context;
+}
+
+static void
+attachment_save_context_free (SaveContext *save_context)
 {
-	EAttachment *new;
+	/* Do not free the GSimpleAsyncResult. */
+	g_object_unref (save_context->attachment);
 
-	g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
+	if (save_context->directory != NULL)
+		g_object_unref (save_context->directory);
 
-	new = g_object_new (E_TYPE_ATTACHMENT, NULL);
-	new->editor_gui = NULL;
-	camel_object_ref (part);
-	new->body = part;
-	new->guessed_type = FALSE;
-	new->is_available_local = TRUE;
-	new->size = camel_mime_part_get_content_size (part);
-	new->file_name = g_strdup (camel_mime_part_get_filename(part));
+	if (save_context->destination != NULL)
+		g_object_unref (save_context->destination);
 
-	return new;
+	if (save_context->input_stream != NULL)
+		g_object_unref (save_context->input_stream);
+
+	if (save_context->output_stream != NULL)
+		g_object_unref (save_context->output_stream);
+
+	g_slice_free (SaveContext, save_context);
 }
 
-
-/* The attachment property dialog.  */
+static gboolean
+attachment_save_check_for_error (SaveContext *save_context,
+                                 GError *error)
+{
+	GSimpleAsyncResult *simple;
 
-typedef struct {
-	GtkWidget *dialog;
-	GtkEntry *file_name_entry;
-	GtkEntry *description_entry;
-	GtkEntry *mime_type_entry;
-	GtkToggleButton *disposition_checkbox;
+	if (error == NULL)
+		return FALSE;
+
+	/* Steal the result. */
+	simple = save_context->simple;
+	save_context->simple = NULL;
+
+	g_simple_async_result_set_from_error (simple, error);
+	g_simple_async_result_complete (simple);
+	g_error_free (error);
+
+	attachment_save_context_free (save_context);
+
+	return TRUE;
+}
+
+static GFile *
+attachment_save_new_candidate (SaveContext *save_context)
+{
+	GFile *candidate;
+	GFileInfo *file_info;
 	EAttachment *attachment;
-} DialogData;
+	const gchar *display_name;
+	gchar *basename;
+
+	attachment = save_context->attachment;
+	file_info = e_attachment_get_file_info (attachment);
+
+	if (file_info != NULL)
+		display_name = g_file_info_get_display_name (file_info);
+	if (display_name == NULL)
+		/* Translators: Default attachment filename. */
+		display_name = _("attachment.dat");
+
+	if (save_context->count == 0)
+		basename = g_strdup (display_name);
+	else {
+		GString *string;
+		const gchar *ext;
+		gsize length;
+
+		string = g_string_sized_new (strlen (display_name));
+		ext = g_utf8_strchr (display_name, -1, '.');
+
+		if (ext != NULL)
+			length = ext - display_name;
+		else
+			length = strlen (display_name);
+
+		g_string_append_len (string, display_name, length);
+		g_string_append_printf (string, " (%d)", save_context->count);
+		g_string_append (string, (ext != NULL) ? ext : "");
+
+		basename = g_string_free (string, FALSE);
+	}
+
+	save_context->count++;
+
+	candidate = g_file_get_child (save_context->directory, basename);
+
+	g_free (basename);
+
+	return candidate;
+}
 
 static void
-destroy_dialog_data (DialogData *data)
+attachment_save_write_cb (GOutputStream *output_stream,
+                          GAsyncResult *result,
+                          SaveContext *save_context)
 {
-	g_free (data);
-}
+	EAttachment *attachment;
+	GCancellable *cancellable;
+	GInputStream *input_stream;
+	gssize bytes_written;
+	GError *error = NULL;
 
-/*
- * fixme: I am converting EVERYTHING to/from UTF-8, although mime types
- * are in ASCII. This is not strictly necessary, but we want to be
- * consistent and possibly check for errors somewhere.
- */
+	bytes_written = g_output_stream_write_finish (
+		output_stream, result, &error);
+
+	if (attachment_save_check_for_error (save_context, error))
+		return;
+
+	attachment = save_context->attachment;
+	cancellable = attachment->priv->cancellable;
+	input_stream = save_context->input_stream;
+
+	if (bytes_written < save_context->bytes_read) {
+		g_memmove (
+			save_context->buffer,
+			save_context->buffer + bytes_written,
+			save_context->bytes_read - bytes_written);
+		save_context->bytes_read -= bytes_written;
+
+		g_output_stream_write_async (
+			output_stream,
+			save_context->buffer,
+			save_context->bytes_read,
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback) attachment_save_write_cb,
+			save_context);
+	} else
+		g_input_stream_read_async (
+			input_stream,
+			save_context->buffer,
+			sizeof (save_context->buffer),
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback) attachment_save_read_cb,
+			save_context);
+}
 
 static void
-set_entry (GladeXML *xml, const char *widget_name, const char *value)
+attachment_save_read_cb (GInputStream *input_stream,
+                         GAsyncResult *result,
+                         SaveContext *save_context)
 {
-	GtkEntry *entry;
+	EAttachment *attachment;
+	GCancellable *cancellable;
+	GOutputStream *output_stream;
+	gssize bytes_read;
+	GError *error = NULL;
 
-	entry = GTK_ENTRY (glade_xml_get_widget (xml, widget_name));
-	if (entry == NULL)
-		g_warning ("Entry for `%s' not found.", widget_name);
-	else
-		gtk_entry_set_text (entry, value ? value : "");
+	bytes_read = g_input_stream_read_finish (
+		input_stream, result, &error);
+
+	if (attachment_save_check_for_error (save_context, error))
+		return;
+
+	if (bytes_read == 0) {
+		GSimpleAsyncResult *simple;
+		GFile *destination;
+
+		/* Steal the result. */
+		simple = save_context->simple;
+		save_context->simple = NULL;
+
+		/* Steal the destination. */
+		destination = save_context->destination;
+		save_context->destination = NULL;
+
+		g_simple_async_result_set_op_res_gpointer (
+			simple, destination, (GDestroyNotify) g_object_unref);
+		g_simple_async_result_complete (simple);
+
+		attachment_save_context_free (save_context);
+
+		return;
+	}
+
+	attachment = save_context->attachment;
+	cancellable = attachment->priv->cancellable;
+	output_stream = save_context->output_stream;
+	save_context->bytes_read = bytes_read;
+
+	attachment_progress_cb (
+		g_seekable_tell (G_SEEKABLE (input_stream)),
+		save_context->total_num_bytes, attachment);
+
+	g_output_stream_write_async (
+		output_stream,
+		save_context->buffer,
+		save_context->bytes_read,
+		G_PRIORITY_DEFAULT, cancellable,
+		(GAsyncReadyCallback) attachment_save_write_cb,
+		save_context);
 }
 
 static void
-connect_widget (GladeXML *gui, const char *name, const char *signal_name,
-		GCallback func, gpointer data)
+attachment_save_got_output_stream (SaveContext *save_context)
 {
-	GtkWidget *widget;
+	GCancellable *cancellable;
+	GInputStream *input_stream;
+	CamelDataWrapper *wrapper;
+	CamelMimePart *mime_part;
+	CamelStream *stream;
+	EAttachment *attachment;
+	GByteArray *buffer;
+
+	attachment = save_context->attachment;
+	cancellable = attachment->priv->cancellable;
+	mime_part = e_attachment_get_mime_part (attachment);
+
+	/* Decode the MIME part to an in-memory buffer.  We have to do
+	 * this because CamelStream is synchronous-only, and using threads
+	 * is dangerous because CamelDataWrapper is not reentrant. */
+	buffer = g_byte_array_new ();
+	stream = camel_stream_mem_new ();
+	camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (stream), buffer);
+	wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+	camel_data_wrapper_decode_to_stream (wrapper, stream);
+	camel_object_unref (stream);
 
-	widget = glade_xml_get_widget (gui, name);
-	g_signal_connect (widget, signal_name, func, data);
+	/* Load the buffer into a GMemoryInputStream. */
+	input_stream = g_memory_input_stream_new_from_data (
+		buffer->data, (gssize) buffer->len,
+		(GDestroyNotify) g_free);
+	save_context->input_stream = input_stream;
+	save_context->total_num_bytes = (goffset) buffer->len;
+	g_byte_array_free (buffer, FALSE);
+
+	g_input_stream_read_async (
+		input_stream,
+		save_context->buffer,
+		sizeof (save_context->buffer),
+		G_PRIORITY_DEFAULT, cancellable,
+		(GAsyncReadyCallback) attachment_save_read_cb,
+		save_context);
 }
 
 static void
-close_cb (GtkWidget *widget, gpointer data)
+attachment_save_create_cb (GFile *destination,
+                           GAsyncResult *result,
+                           SaveContext *save_context)
 {
 	EAttachment *attachment;
-	DialogData *dialog_data;
+	GCancellable *cancellable;
+	GFileOutputStream *output_stream;
+	GError *error = NULL;
+
+	/* Output stream might be NULL, so don't use cast macro. */
+	output_stream = g_file_create_finish (destination, result, &error);
+	save_context->output_stream = (GOutputStream *) output_stream;
+
+	attachment = save_context->attachment;
+	cancellable = attachment->priv->cancellable;
+
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
+		destination = attachment_save_new_candidate (save_context);
 
-	dialog_data = (DialogData *) data;
-	attachment = dialog_data->attachment;
+		g_file_create_async (
+			destination, G_FILE_CREATE_NONE,
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback) attachment_save_create_cb,
+			save_context);
 
-	gtk_widget_destroy (dialog_data->dialog);
-	g_object_unref (attachment->editor_gui);
-	attachment->editor_gui = NULL;
+		g_object_unref (destination);
+		g_error_free (error);
+		return;
+	}
+
+	if (attachment_save_check_for_error (save_context, error))
+		return;
+
+	save_context->destination = g_object_ref (destination);
+	attachment_save_got_output_stream (save_context);
+}
+
+static void
+attachment_save_replace_cb (GFile *destination,
+                            GAsyncResult *result,
+                            SaveContext *save_context)
+{
+	GFileOutputStream *output_stream;
+	GError *error = NULL;
 
-	destroy_dialog_data (dialog_data);
+	/* Output stream might be NULL, so don't use cast macro. */
+	output_stream = g_file_replace_finish (destination, result, &error);
+	save_context->output_stream = (GOutputStream *) output_stream;
+
+	if (attachment_save_check_for_error (save_context, error))
+		return;
+
+	save_context->destination = g_object_ref (destination);
+	attachment_save_got_output_stream (save_context);
 }
 
 static void
-ok_cb (GtkWidget *widget, gpointer data)
+attachment_save_query_info_cb (GFile *destination,
+                               GAsyncResult *result,
+                               SaveContext *save_context)
 {
-	DialogData *dialog_data;
 	EAttachment *attachment;
-	const char *str;
-
-	dialog_data = (DialogData *) data;
-	attachment = dialog_data->attachment;
-
-	str = gtk_entry_get_text (dialog_data->file_name_entry);
-	if (attachment->is_available_local)
-		camel_mime_part_set_filename (attachment->body, str);
-	g_free (attachment->file_name);
-	attachment->file_name = g_strdup (str);
-
-	str = gtk_entry_get_text (dialog_data->description_entry);
-	if (attachment->is_available_local) {
-		camel_mime_part_set_description (attachment->body, str);
-	} else {
-		g_free (attachment->description);
-		attachment->description = g_strdup (str);
+	GCancellable *cancellable;
+	GFileInfo *file_info;
+	GFileType file_type;
+	GError *error = NULL;
+
+	attachment = save_context->attachment;
+	cancellable = attachment->priv->cancellable;
+
+	file_info = g_file_query_info_finish (destination, result, &error);
+
+	/* G_IO_ERROR_NOT_FOUND just means we're creating a new file. */
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+		g_error_free (error);
+		goto replace;
 	}
 
-	str = gtk_entry_get_text (dialog_data->mime_type_entry);
-	if (attachment->is_available_local) {
-		camel_mime_part_set_content_type (attachment->body, str);
-		camel_data_wrapper_set_mime_type(camel_medium_get_content_object(CAMEL_MEDIUM (attachment->body)), str);
+	if (attachment_save_check_for_error (save_context, error))
+		return;
+
+	file_type = g_file_info_get_file_type (file_info);
+	g_object_unref (file_info);
+
+	if (file_type == G_FILE_TYPE_DIRECTORY) {
+		save_context->directory = g_object_ref (destination);
+		destination = attachment_save_new_candidate (save_context);
+
+		g_file_create_async (
+			destination, G_FILE_CREATE_NONE,
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback) attachment_save_create_cb,
+			save_context);
+
+		g_object_unref (destination);
+
+		return;
 	}
 
-	if (attachment->is_available_local) {
-		switch (gtk_toggle_button_get_active (dialog_data->disposition_checkbox)) {
-		case 0:
-			camel_mime_part_set_disposition (attachment->body, "attachment");
-			break;
-		case 1:
-			camel_mime_part_set_disposition (attachment->body, "inline");
-			break;
-		default:
-			/* Hmmmm? */
-			break;
-		}
-	} else {
-		attachment->disposition = gtk_toggle_button_get_active (dialog_data->disposition_checkbox);
+replace:
+	g_file_replace_async (
+		destination, NULL, FALSE,
+#if GLIB_CHECK_VERSION(2,20,0)
+		G_FILE_CREATE_REPLACE_DESTINATION,
+#else
+		G_FILE_CREATE_NONE,
+#endif
+		G_PRIORITY_DEFAULT, cancellable,
+		(GAsyncReadyCallback) attachment_save_replace_cb,
+		save_context);
+}
+
+void
+e_attachment_save_async (EAttachment *attachment,
+                         GFile *destination,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+	SaveContext *save_context;
+	GCancellable *cancellable;
+
+	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (G_IS_FILE (destination));
+	g_return_if_fail (callback != NULL);
+
+	if (e_attachment_get_loading (attachment)) {
+		g_simple_async_report_error_in_idle (
+			G_OBJECT (attachment), callback, user_data,
+			G_IO_ERROR, G_IO_ERROR_BUSY,
+			_("A load operation is already in progress"));
+		return;
 	}
 
-	changed (attachment);
-	close_cb (widget, data);
+	if (e_attachment_get_saving (attachment)) {
+		g_simple_async_report_error_in_idle (
+			G_OBJECT (attachment), callback, user_data,
+			G_IO_ERROR, G_IO_ERROR_BUSY,
+			_("A save operation is already in progress"));
+		return;
+	}
+
+	if (e_attachment_get_mime_part (attachment) == NULL) {
+		g_simple_async_report_error_in_idle (
+			G_OBJECT (attachment), callback, user_data,
+			G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+			_("Attachment contents not loaded"));
+		return;
+	}
+
+	save_context = attachment_save_context_new (
+		attachment, callback, user_data);
+
+	cancellable = attachment->priv->cancellable;
+	g_cancellable_reset (cancellable);
+
+	/* First we need to know if destination is a directory. */
+	g_file_query_info_async (
+		destination, G_FILE_ATTRIBUTE_STANDARD_TYPE,
+		G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
+		cancellable, (GAsyncReadyCallback)
+		attachment_save_query_info_cb, save_context);
 }
 
-static void
-response_cb (GtkWidget *widget, gint response, gpointer data)
+GFile *
+e_attachment_save_finish (EAttachment *attachment,
+                          GAsyncResult *result,
+                          GError **error)
 {
-	if (response == GTK_RESPONSE_OK)
-		ok_cb (widget, data);
-	else
-		close_cb (widget, data);
+	GSimpleAsyncResult *simple;
+	GFile *destination;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	destination = g_simple_async_result_get_op_res_gpointer (simple);
+	if (destination != NULL)
+		g_object_ref (destination);
+	g_simple_async_result_propagate_error (simple, error);
+	g_object_unref (simple);
+
+	attachment_set_saving (attachment, FALSE);
+
+	return destination;
 }
 
 void
-e_attachment_edit (EAttachment *attachment, GtkWidget *parent)
+e_attachment_save_handle_error (EAttachment *attachment,
+                                GAsyncResult *result,
+                                GtkWindow *parent)
 {
-	CamelContentType *content_type;
-	const char *disposition;
-	DialogData *dialog_data;
-	GladeXML *editor_gui;
-	GtkWidget *window;
-	char *type;
-	char *filename;
+	GFile *file;
+	GFileInfo *file_info;
+	GtkWidget *dialog;
+	const gchar *display_name;
+	const gchar *primary_text;
+	GError *error = NULL;
 
 	g_return_if_fail (E_IS_ATTACHMENT (attachment));
+	g_return_if_fail (G_IS_ASYNC_RESULT (result));
+	g_return_if_fail (GTK_IS_WINDOW (parent));
+
+	file = e_attachment_save_finish (attachment, result, &error);
 
-	if (attachment->editor_gui != NULL) {
-		window = glade_xml_get_widget (attachment->editor_gui, "dialog");
-		gdk_window_show (window->window);
+	if (file != NULL) {
+		g_object_unref (file);
 		return;
 	}
 
-	filename = g_build_filename (EVOLUTION_GLADEDIR, "e-attachment.glade", NULL);
-	editor_gui = glade_xml_new (filename, NULL, NULL);
-	g_free (filename);
-
-	if (editor_gui == NULL) {
-		g_warning ("Cannot load `e-attachment.glade'");
+	/* Ignore cancellations. */
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
-	}
 
-	attachment->editor_gui = editor_gui;
-
-	gtk_window_set_transient_for (GTK_WINDOW (glade_xml_get_widget (editor_gui, "dialog")),
-				      GTK_WINDOW (gtk_widget_get_toplevel (parent)));
-
-	dialog_data = g_new (DialogData, 1);
-	dialog_data->attachment = attachment;
-	dialog_data->dialog = glade_xml_get_widget (editor_gui, "dialog");
-	dialog_data->file_name_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "file_name_entry"));
-	dialog_data->description_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "description_entry"));
-	dialog_data->mime_type_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "mime_type_entry"));
-	dialog_data->disposition_checkbox = GTK_TOGGLE_BUTTON (glade_xml_get_widget (editor_gui, "disposition_checkbox"));
-
-	if (attachment->is_available_local && attachment->body) {
-		set_entry (editor_gui, "file_name_entry", camel_mime_part_get_filename (attachment->body));
-		set_entry (editor_gui, "description_entry", camel_mime_part_get_description (attachment->body));
-		content_type = camel_mime_part_get_content_type (attachment->body);
-		type = camel_content_type_simple (content_type);
-		set_entry (editor_gui, "mime_type_entry", type);
-		g_free (type);
-
-		disposition = camel_mime_part_get_disposition (attachment->body);
-		gtk_toggle_button_set_active (dialog_data->disposition_checkbox,
-					      disposition && !g_ascii_strcasecmp (disposition, "inline"));
-	} else {
-		set_entry (editor_gui, "file_name_entry", attachment->file_name);
-		set_entry (editor_gui, "description_entry", attachment->description);
-		if ((type = attachment_guess_mime_type (attachment->file_name))) {
-			set_entry (editor_gui, "mime_type_entry", type);
-			g_free (type);
-		} else {
-			set_entry (editor_gui, "mime_type_entry", "");
-		}
+	file_info = e_attachment_get_file_info (attachment);
 
-		gtk_toggle_button_set_active (dialog_data->disposition_checkbox, attachment->disposition);
-	}
+	if (file_info != NULL)
+		display_name = g_file_info_get_display_name (file_info);
+	else
+		display_name = NULL;
+
+	if (display_name != NULL)
+		primary_text = g_strdup_printf (
+			_("Could not save '%s'"), display_name);
+	else
+		primary_text = g_strdup_printf (
+			_("Could not save the attachment"));
+
+	dialog = gtk_message_dialog_new_with_markup (
+		parent, GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+		"<big><b>%s</b></big>", primary_text);
+
+	gtk_message_dialog_format_secondary_text (
+		GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
 
-	connect_widget (editor_gui, "dialog", "response", (GCallback)response_cb, dialog_data);
+	gtk_dialog_run (GTK_DIALOG (dialog));
 
-	/* make sure that when the parent gets hidden/closed that our windows also close */
-	parent = gtk_widget_get_toplevel (parent);
-	gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog_data->dialog), TRUE);
+	gtk_widget_destroy (dialog);
+	g_error_free (error);
 }
diff --git a/widgets/misc/e-attachment.h b/widgets/misc/e-attachment.h
index 7b45f24..934e1e0 100644
--- a/widgets/misc/e-attachment.h
+++ b/widgets/misc/e-attachment.h
@@ -1,4 +1,6 @@
 /*
+ * e-attachment.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
@@ -13,91 +15,131 @@
  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
  *
  *
- * Authors:
- *		Ettore Perazzoli <ettore ximian com>
- * 	   	Srinivasa Ragavan <sragavan novell com>
- *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
  */
 
-#ifndef __E_ATTACHMENT_H__
-#define __E_ATTACHMENT_H__
+#ifndef E_ATTACHMENT_H
+#define E_ATTACHMENT_H
 
-#include <gio/gio.h>
 #include <gtk/gtk.h>
-#include <glade/glade-xml.h>
-#include <camel/camel-mime-part.h>
-#include <camel/camel-exception.h>
 #include <camel/camel-cipher-context.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#define E_TYPE_ATTACHMENT				(e_attachment_get_type ())
-#define E_ATTACHMENT(obj)				(G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT, EAttachment))
-#define E_ATTACHMENT_CLASS(klass)			(G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT, EAttachmentClass))
-#define E_IS_ATTACHMENT(obj)				(G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT))
-#define E_IS_ATTACHMENT_CLASS(klass)			(G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT))
-
-
-typedef struct _EAttachment       EAttachment;
-typedef struct _EAttachmentClass  EAttachmentClass;
+#include <camel/camel-mime-part.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-multipart.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT \
+	(e_attachment_get_type ())
+#define E_ATTACHMENT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT, EAttachment))
+#define E_ATTACHMENT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT, EAttachmentClass))
+#define E_IS_ATTACHMENT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT))
+#define E_IS_ATTACHMENT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT))
+#define E_ATTACHMENT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT, EAttachmentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachment EAttachment;
+typedef struct _EAttachmentClass EAttachmentClass;
+typedef struct _EAttachmentPrivate EAttachmentPrivate;
 
 struct _EAttachment {
 	GObject parent;
-
-	GladeXML *editor_gui;
-
-	CamelMimePart *body;
-	gboolean guessed_type;
-	gulong size;
-
-	GdkPixbuf *pixbuf_cache;
-
-	GCancellable *cancellable;
-
-	gboolean is_available_local;
-	int percentage;
-	char *file_name;
-	char *description;
-	gboolean disposition;
-	int index;
-	char *store_uri;
-
-	/* Status of signed/encrypted attachments */
-	camel_cipher_validity_sign_t sign;
-	camel_cipher_validity_encrypt_t encrypt;
+	EAttachmentPrivate *priv;
 };
 
 struct _EAttachmentClass {
 	GObjectClass parent_class;
-
-	void (*changed)	(EAttachment *attachment);
-	void (*update) (EAttachment *attachment, char *msg);
 };
 
-GType e_attachment_get_type (void);
-EAttachment *e_attachment_new (const char *file_name,
-			       const char *disposition,
-			       CamelException *ex);
-EAttachment * e_attachment_new_remote_file (GtkWindow *error_dlg_parent,
-					    const char *url,
-			       		    const char *disposition,
-					    const char *path,
-	  	   			    CamelException *ex);
-void e_attachment_build_remote_file (const char *filename,
-				     EAttachment *attachment,
-		 	   	     const char *disposition,
-				     CamelException *ex);
-EAttachment *e_attachment_new_from_mime_part (CamelMimePart *part);
-void e_attachment_edit (EAttachment *attachment,
-			GtkWidget *parent);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __E_ATTACHMENT_H__ */
+GType		e_attachment_get_type		(void);
+EAttachment *	e_attachment_new		(void);
+EAttachment *	e_attachment_new_for_path	(const gchar *path);
+EAttachment *	e_attachment_new_for_uri	(const gchar *uri);
+EAttachment *	e_attachment_new_for_message	(CamelMimeMessage *message);
+void		e_attachment_add_to_multipart	(EAttachment *attachment,
+						 CamelMultipart *multipart,
+						 const gchar *default_charset);
+void		e_attachment_cancel		(EAttachment *attachment);
+gboolean	e_attachment_get_can_show	(EAttachment *attachment);
+void		e_attachment_set_can_show	(EAttachment *attachment,
+						 gboolean can_show);
+const gchar *	e_attachment_get_disposition	(EAttachment *attachment);
+void		e_attachment_set_disposition	(EAttachment *attachment,
+						 const gchar *disposition);
+GFile *		e_attachment_get_file		(EAttachment *attachment);
+void		e_attachment_set_file		(EAttachment *attachment,
+						 GFile *file);
+GFileInfo *	e_attachment_get_file_info	(EAttachment *attachment);
+gboolean	e_attachment_get_loading	(EAttachment *attachment);
+CamelMimePart *	e_attachment_get_mime_part	(EAttachment *attachment);
+void		e_attachment_set_mime_part	(EAttachment *attachment,
+						 CamelMimePart *mime_part);
+gint		e_attachment_get_percent	(EAttachment *attachment);
+GtkTreeRowReference *
+		e_attachment_get_reference	(EAttachment *attachment);
+void		e_attachment_set_reference	(EAttachment *attachment,
+						 GtkTreeRowReference *reference);
+gboolean	e_attachment_get_saving		(EAttachment *attachment);
+gboolean	e_attachment_get_shown		(EAttachment *attachment);
+void		e_attachment_set_shown		(EAttachment *attachment,
+						 gboolean shown);
+camel_cipher_validity_encrypt_t
+		e_attachment_get_encrypted	(EAttachment *attachment);
+void		e_attachment_set_encrypted	(EAttachment *attachment,
+						 camel_cipher_validity_encrypt_t encrypted);
+camel_cipher_validity_sign_t
+		e_attachment_get_signed		(EAttachment *attachment);
+void		e_attachment_set_signed		(EAttachment *attachment,
+						 camel_cipher_validity_sign_t signed_);
+const gchar *	e_attachment_get_description	(EAttachment *attachment);
+const gchar *	e_attachment_get_thumbnail_path	(EAttachment *attachment);
+gboolean	e_attachment_is_rfc822		(EAttachment *attachment);
+GList *		e_attachment_list_apps		(EAttachment *attachment);
+
+/* Asynchronous Operations */
+void		e_attachment_load_async		(EAttachment *attachment,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_attachment_load_finish	(EAttachment *attachment,
+						 GAsyncResult *result,
+						 GError **error);
+void		e_attachment_open_async		(EAttachment *attachment,
+						 GAppInfo *app_info,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_attachment_open_finish	(EAttachment *attachment,
+						 GAsyncResult *result,
+						 GError **error);
+void		e_attachment_save_async		(EAttachment *attachment,
+						 GFile *destination,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+GFile *		e_attachment_save_finish	(EAttachment *attachment,
+						 GAsyncResult *result,
+						 GError **error);
+
+/* Handy GAsyncReadyCallback Functions */
+void		e_attachment_load_handle_error	(EAttachment *attachment,
+						 GAsyncResult *result,
+						 GtkWindow *parent);
+void		e_attachment_open_handle_error	(EAttachment *attachment,
+						 GAsyncResult *result,
+						 GtkWindow *parent);
+void		e_attachment_save_handle_error	(EAttachment *attachment,
+						 GAsyncResult *result,
+						 GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_H */
diff --git a/widgets/misc/e-expander.c b/widgets/misc/e-expander.c
deleted file mode 100644
index 7715987..0000000
--- a/widgets/misc/e-expander.c
+++ /dev/null
@@ -1,1341 +0,0 @@
-/*
- * GTK - The GIMP Toolkit
- *
- * 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/>  
- *
- *
- * Authors:
- *		Mark McLoughlin <mark skynet ie>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- * Copyright (C) 2003 Sun Microsystems, Inc.
- *
- */
-
-#include <config.h>
-
-#include "e-expander.h"
-#include "ea-widgets.h"
-
-#include <gdk/gdkkeysyms.h>
-
-#define DEFAULT_EXPANDER_SIZE 10
-#define DEFAULT_EXPANDER_SPACING 2
-
-/* ESTUFF */
-#ifndef _
-#define _(x) (x)
-#endif
-#define E_EXPANDER_GET_PRIVATE(expander) ((EExpanderPrivate *)g_object_get_data (G_OBJECT (expander), "e-expander-priv"))
-
-enum {
-  PROP_0,
-  PROP_EXPANDED,
-  PROP_LABEL,
-  PROP_USE_UNDERLINE,
-  PROP_PADDING,
-  PROP_LABEL_WIDGET
-};
-
-typedef struct {
-  GtkWidget        *label_widget;
-  gint              spacing;
-
-  GtkExpanderStyle  expander_style;
-  guint             animation_timeout;
-
-  guint      expanded : 1;
-  guint      use_underline : 1;
-  guint      button_down : 1;
-} EExpanderPrivate;
-
-static void e_expander_class_init (EExpanderClass *klass);
-static void e_expander_init       (EExpander      *expander);
-
-static void e_expander_set_property (GObject          *object,
-				       guint             prop_id,
-				       const GValue     *value,
-				       GParamSpec       *pspec);
-static void e_expander_get_property (GObject          *object,
-				       guint             prop_id,
-				       GValue           *value,
-				       GParamSpec       *pspec);
-
-static void e_expander_destroy (GtkObject *object);
-
-static void     e_expander_realize        (GtkWidget        *widget);
-static void     e_expander_size_request   (GtkWidget        *widget,
-					     GtkRequisition   *requisition);
-static void     e_expander_size_allocate  (GtkWidget        *widget,
-					     GtkAllocation    *allocation);
-static void     e_expander_map            (GtkWidget        *widget);
-static gboolean e_expander_expose         (GtkWidget        *widget,
-					     GdkEventExpose   *event);
-static gboolean e_expander_button_press   (GtkWidget        *widget,
-					     GdkEventButton   *event);
-static gboolean e_expander_button_release (GtkWidget        *widget,
-					     GdkEventButton   *event);
-static gboolean e_expander_motion_notify  (GtkWidget        *widget,
-					     GdkEventMotion   *event);
-static gboolean e_expander_enter_notify   (GtkWidget        *widget,
-					     GdkEventCrossing *event);
-static gboolean e_expander_leave_notify   (GtkWidget        *widget,
-					     GdkEventCrossing *event);
-static gboolean e_expander_focus          (GtkWidget        *widget,
-					     GtkDirectionType  direction);
-
-static void e_expander_add    (GtkContainer *container,
-				 GtkWidget    *widget);
-static void e_expander_remove (GtkContainer *container,
-				 GtkWidget    *widget);
-static void e_expander_forall (GtkContainer *container,
-				 gboolean        include_internals,
-				 GtkCallback     callback,
-				 gpointer        callback_data);
-
-static void e_expander_activate (EExpander *expander);
-
-static GtkBinClass *parent_class = NULL;
-
-GType
-e_expander_get_type (void)
-{
-  static GType expander_type = 0;
-
-  if (!expander_type)
-    {
-      static const GTypeInfo expander_info =
-      {
-	sizeof (EExpanderClass),
-	NULL,		/* base_init */
-	NULL,		/* base_finalize */
-	(GClassInitFunc) e_expander_class_init,
-	NULL,		/* class_finalize */
-	NULL,		/* class_data */
-	sizeof (EExpander),
-	0,		/* n_preallocs */
-	(GInstanceInitFunc) e_expander_init,
-      };
-
-      expander_type = g_type_register_static (GTK_TYPE_BIN,
-					      "EExpander",
-					      &expander_info, 0);
-    }
-
-  return expander_type;
-}
-
-static void
-e_expander_class_init (EExpanderClass *klass)
-{
-  GObjectClass *gobject_class;
-  GtkObjectClass *gtkobject_class;
-  GtkWidgetClass *widget_class;
-  GtkContainerClass *container_class;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_class    = (GObjectClass *) klass;
-  gtkobject_class  = (GtkObjectClass *) klass;
-  widget_class    = (GtkWidgetClass *) klass;
-  container_class = (GtkContainerClass *) klass;
-
-  gobject_class->set_property = e_expander_set_property;
-  gobject_class->get_property = e_expander_get_property;
-
-  gtkobject_class->destroy = e_expander_destroy;
-
-  widget_class->realize              = e_expander_realize;
-  widget_class->size_request         = e_expander_size_request;
-  widget_class->size_allocate        = e_expander_size_allocate;
-  widget_class->map                  = e_expander_map;
-  widget_class->expose_event         = e_expander_expose;
-  widget_class->button_press_event   = e_expander_button_press;
-  widget_class->button_release_event = e_expander_button_release;
-  widget_class->motion_notify_event  = e_expander_motion_notify;
-  widget_class->enter_notify_event   = e_expander_enter_notify;
-  widget_class->leave_notify_event   = e_expander_leave_notify;
-  widget_class->focus                = e_expander_focus;
-
-  container_class->add    = e_expander_add;
-  container_class->remove = e_expander_remove;
-  container_class->forall = e_expander_forall;
-
-  klass->activate = e_expander_activate;
-
-  /* ESTUFF  g_type_class_add_private (klass, sizeof (EExpanderPrivate)); */
-
-  g_object_class_install_property (gobject_class,
-				   PROP_EXPANDED,
-				   g_param_spec_boolean ("expanded",
-							 _("Expanded"),
-							 _("Whether or not the expander is expanded"),
-							 FALSE,
-							 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_LABEL,
-				   g_param_spec_string ("label",
-							_("Label"),
-							_("Text of the expander's label"),
-							NULL,
-							G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_USE_UNDERLINE,
-				   g_param_spec_boolean ("use_underline",
-							 _("Use underline"),
-							 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
-							 FALSE,
-							 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_PADDING,
-				   g_param_spec_int ("spacing",
-						     _("Spacing"),
-						     _("Space to put between the label and the child"),
-						     0,
-						     G_MAXINT,
-						     0,
-						     G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_LABEL_WIDGET,
-				   g_param_spec_object ("label_widget",
-							_("Label widget"),
-							_("A widget to display in place of the usual expander label"),
-							GTK_TYPE_WIDGET,
-							G_PARAM_READWRITE));
-
-  gtk_widget_class_install_style_property (widget_class,
-					   g_param_spec_int ("expander-size",
-							     _("Expander Size"),
-							     _("Size of the expander arrow"),
-							     0,
-							     G_MAXINT,
-							     DEFAULT_EXPANDER_SIZE,
-							     G_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-					   g_param_spec_int ("expander-spacing",
-							     _("Indicator Spacing"),
-							     _("Spacing around expander arrow"),
-							     0,
-							     G_MAXINT,
-							     DEFAULT_EXPANDER_SPACING,
-							     G_PARAM_READABLE));
-
-  widget_class->activate_signal =
-    g_signal_new ("activate",
-		  G_TYPE_FROM_CLASS (gobject_class),
-		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-		  G_STRUCT_OFFSET (EExpanderClass, activate),
-		  NULL, NULL,
-		  g_cclosure_marshal_VOID__VOID,
-		  G_TYPE_NONE, 0);
-
-  e_expander_a11y_init();
-}
-
-static void
-e_expander_init (EExpander *expander)
-{
-  EExpanderPrivate *priv;
-
-  /* ESTUFF */
-  priv = g_new0 (EExpanderPrivate, 1);
-  g_object_set_data_full (G_OBJECT (expander), "e-expander-priv", priv, g_free);
-
-  /* ESTUFF  priv = E_EXPANDER_GET_PRIVATE (expander); */
-
-  GTK_WIDGET_SET_FLAGS (expander, GTK_CAN_FOCUS);
-  GTK_WIDGET_UNSET_FLAGS (expander, GTK_NO_WINDOW);
-
-  priv->label_widget = NULL;
-  priv->spacing = 0;
-
-  priv->expander_style = GTK_EXPANDER_COLLAPSED;
-  priv->animation_timeout = 0;
-
-  priv->expanded = FALSE;
-  priv->use_underline = FALSE;
-  priv->button_down = FALSE;
-
-}
-
-static void
-e_expander_set_property (GObject      *object,
-			   guint         prop_id,
-			   const GValue *value,
-			   GParamSpec   *pspec)
-{
-  EExpander *expander = E_EXPANDER (object);
-
-  switch (prop_id)
-    {
-    case PROP_EXPANDED:
-      e_expander_set_expanded (expander, g_value_get_boolean (value));
-      break;
-    case PROP_LABEL:
-      e_expander_set_label (expander, g_value_get_string (value));
-      break;
-    case PROP_USE_UNDERLINE:
-      e_expander_set_use_underline (expander, g_value_get_boolean (value));
-      break;
-    case PROP_PADDING:
-      e_expander_set_spacing (expander, g_value_get_int (value));
-      break;
-    case PROP_LABEL_WIDGET:
-      e_expander_set_label_widget (expander, g_value_get_object (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-e_expander_get_property (GObject    *object,
-			   guint       prop_id,
-			   GValue     *value,
-			   GParamSpec *pspec)
-{
-  EExpander *expander = E_EXPANDER (object);
-  EExpanderPrivate *priv;
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  switch (prop_id)
-    {
-    case PROP_EXPANDED:
-      g_value_set_boolean (value, priv->expanded);
-      break;
-    case PROP_LABEL:
-      g_value_set_string (value, e_expander_get_label (expander));
-      break;
-    case PROP_USE_UNDERLINE:
-      g_value_set_boolean (value, priv->use_underline);
-      break;
-    case PROP_PADDING:
-      g_value_set_int (value, priv->spacing);
-      break;
-    case PROP_LABEL_WIDGET:
-      g_value_set_object (value,
-			  priv->label_widget ?
-			  G_OBJECT (priv->label_widget) : NULL);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-e_expander_destroy (GtkObject *object)
-{
-  EExpander *expander = E_EXPANDER (object);
-  EExpanderPrivate *priv;
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (priv->animation_timeout)
-    g_source_remove (priv->animation_timeout);
-  priv->animation_timeout = 0;
-
-  GTK_OBJECT_CLASS (parent_class)->destroy (object);
-}
-
-static void
-e_expander_realize (GtkWidget *widget)
-{
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  gint border_width;
-
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  attributes.x = widget->allocation.x + border_width;
-  attributes.y = widget->allocation.y + border_width;
-  attributes.width = widget->allocation.width - 2 * border_width;
-  attributes.height = widget->allocation.height - 2 * border_width;
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
-  attributes.event_mask = gtk_widget_get_events (widget)     |
-				GDK_POINTER_MOTION_MASK      |
-				GDK_POINTER_MOTION_HINT_MASK |
-				GDK_BUTTON_PRESS_MASK        |
-				GDK_BUTTON_RELEASE_MASK      |
-				GDK_EXPOSURE_MASK            |
-				GDK_ENTER_NOTIFY_MASK        |
-				GDK_LEAVE_NOTIFY_MASK;
-
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-
-  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
-				   &attributes, attributes_mask);
-  gdk_window_set_user_data (widget->window, widget);
-
-  widget->style = gtk_style_attach (widget->style, widget->window);
-  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
-}
-
-static void
-e_expander_size_request (GtkWidget      *widget,
-			   GtkRequisition *requisition)
-{
-  EExpander *expander;
-  GtkBin *bin;
-  EExpanderPrivate *priv;
-  gint border_width;
-  gint expander_size;
-  gint expander_spacing;
-  gboolean interior_focus;
-  gint focus_width;
-  gint focus_pad;
-
-  expander = E_EXPANDER (widget);
-  bin = GTK_BIN (widget);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  requisition->width = expander_size + 2 * expander_spacing +
-		       2 * focus_width + 2 * focus_pad;
-  requisition->height = interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
-
-  if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-    {
-      GtkRequisition label_requisition;
-
-      gtk_widget_size_request (priv->label_widget, &label_requisition);
-
-      requisition->width  += label_requisition.width;
-      requisition->height += label_requisition.height;
-    }
-
-  requisition->height = MAX (expander_size + 2 * expander_spacing, requisition->height);
-
-  if (!interior_focus)
-    requisition->height += 2 * focus_width + 2 * focus_pad;
-
-  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
-    {
-      GtkRequisition child_requisition;
-
-      gtk_widget_size_request (bin->child, &child_requisition);
-
-      if (!interior_focus)
-	child_requisition.width += 2 * focus_width + 2 * focus_pad;
-
-      requisition->width = MAX (requisition->width, child_requisition.width);
-      requisition->height += child_requisition.height + priv->spacing;
-    }
-
-  requisition->width  += 2 * border_width;
-  requisition->height += 2 * border_width + 2 * priv->spacing;
-}
-
-static void
-e_expander_size_allocate (GtkWidget     *widget,
-			    GtkAllocation *allocation)
-{
-  EExpander *expander;
-  GtkBin *bin;
-  EExpanderPrivate *priv;
-  GtkRequisition child_requisition;
-  gboolean child_visible = FALSE;
-  gint border_width;
-  gint expander_size;
-  gint expander_spacing;
-  gboolean interior_focus;
-  gint focus_width;
-  gint focus_pad;
-  gint label_height;
-
-  expander = E_EXPANDER (widget);
-  bin = GTK_BIN (widget);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  child_requisition.width = 0;
-  child_requisition.height = 0;
-  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
-    {
-      child_visible = TRUE;
-      gtk_widget_get_child_requisition (bin->child, &child_requisition);
-    }
-
-  widget->allocation = *allocation;
-
-  if (GTK_WIDGET_REALIZED (widget))
-    gdk_window_move_resize (widget->window,
-			    allocation->x + border_width,
-			    allocation->y + border_width,
-                            MAX (allocation->width - 2 * border_width, 0),
-                            MAX (allocation->height - 2 * border_width, 0));
-
-  if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-    {
-      GtkAllocation label_allocation;
-      GtkRequisition label_requisition;
-      gboolean ltr;
-
-      gtk_widget_get_child_requisition (priv->label_widget, &label_requisition);
-
-      ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
-      label_allocation.x = focus_width + focus_pad;
-      if (ltr)
-	label_allocation.x += expander_size + 2 * expander_spacing;
-      label_allocation.y = priv->spacing + focus_width + focus_pad;
-
-      label_allocation.width = MIN (label_requisition.width,
-				    allocation->width - 2 * border_width -
-				    expander_size - 2 * expander_spacing -
-				    2 * focus_width - 2 * focus_pad);
-      label_allocation.width = MAX (label_allocation.width, 1);
-
-      label_allocation.height = MIN (label_requisition.height,
-				     allocation->height - 2 * border_width -
-				     2 * priv->spacing -
-				     2 * focus_width - 2 * focus_pad -
-				     child_requisition.height -
-				     (child_visible ? priv->spacing : 0));
-      label_allocation.height = MAX (label_allocation.height, 1);
-
-      gtk_widget_size_allocate (priv->label_widget, &label_allocation);
-
-      label_height = label_allocation.height;
-    }
-  else
-    {
-      label_height = 0;
-    }
-
-  if (child_visible)
-    {
-      GtkAllocation child_allocation;
-      gint top_height;
-
-      top_height = MAX (2 * expander_spacing + expander_size,
-			label_height +
-			(interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
-
-      child_allocation.x = 0;
-      child_allocation.y = 2 * priv->spacing + top_height;
-
-      if (!interior_focus)
-	{
-	  child_allocation.x += focus_width + focus_pad;
-	  child_allocation.y += focus_width + focus_pad;
-	}
-
-      child_allocation.width = allocation->width - 2 * border_width -
-			       (!interior_focus ? 2 * focus_width + 2 * focus_pad : 0);
-      child_allocation.width = MAX (child_allocation.width, 1);
-
-      child_allocation.height = allocation->height - top_height -
-				2 * border_width -
-				3 * priv->spacing -
-				(!interior_focus ? 2 * focus_width + 2 * focus_pad : 0);
-      child_allocation.height = MAX (child_allocation.height, 1);
-
-      gtk_widget_size_allocate (bin->child, &child_allocation);
-    }
-}
-
-static void
-e_expander_map (GtkWidget *widget)
-{
-  EExpanderPrivate *priv;
-
-  priv = E_EXPANDER_GET_PRIVATE (widget);
-
-  if (priv->label_widget)
-    gtk_widget_map (priv->label_widget);
-
-  GTK_WIDGET_CLASS (parent_class)->map (widget);
-}
-
-static GdkRectangle
-get_expander_bounds (EExpander *expander)
-{
-  GtkWidget *widget;
-  EExpanderPrivate *priv;
-  GdkRectangle bounds;
-  gint border_width;
-  gint expander_size;
-  gint expander_spacing;
-  gboolean interior_focus;
-  gint focus_width;
-  gint focus_pad;
-  gboolean ltr;
-
-  widget = GTK_WIDGET (expander);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  border_width = GTK_CONTAINER (expander)->border_width;
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
-
-  if (ltr)
-    bounds.x = expander_spacing;
-  else
-    bounds.x = widget->allocation.width - 2 * border_width -
-	       expander_spacing - expander_size;
-
-  if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-    {
-      GtkAllocation label_allocation;
-
-      label_allocation = priv->label_widget->allocation;
-
-      if (expander_size < label_allocation.height)
-	bounds.y = label_allocation.y + (label_allocation.height - expander_size) / 2;
-      else
-	bounds.y = priv->spacing + expander_spacing;
-    }
-  else
-    {
-      bounds.y = priv->spacing + expander_spacing;
-    }
-
-  if (!interior_focus)
-    {
-      if (ltr)
-	bounds.x += focus_width + focus_pad;
-      else
-	bounds.x -= focus_width + focus_pad;
-      bounds.y += focus_width + focus_pad;
-    }
-
-  bounds.width = bounds.height = expander_size;
-
-  return bounds;
-}
-
-static void
-e_expander_paint (EExpander *expander)
-{
-  GtkWidget *widget;
-  EExpanderPrivate *priv;
-  gint x, y;
-  GtkStateType state;
-  GdkRectangle clip;
-
-  widget = GTK_WIDGET (expander);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  clip = get_expander_bounds (expander);
-
-  x = clip.x + clip.width / 2;
-  y = clip.y + clip.height / 2;
-
-  state = widget->state;
-  if (state != GTK_STATE_PRELIGHT)
-    state = GTK_STATE_NORMAL;
-
-  gtk_paint_expander (widget->style,
-		      widget->window,
-		      state,
-		      &clip,
-		      widget,
-		      "expander",
-		      x,
-		      y,
-		      priv->expander_style);
-}
-
-static void
-e_expander_paint_focus (EExpander  *expander,
-			  GdkRectangle *area)
-{
-  GtkWidget *widget;
-  EExpanderPrivate *priv;
-  gint x, y, width, height;
-  gboolean interior_focus;
-  gint focus_width;
-  gint focus_pad;
-  gint expander_size;
-  gint expander_spacing;
-  gboolean ltr;
-
-  widget = GTK_WIDGET (expander);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
-  if (interior_focus)
-    {
-      if (ltr)
-	x = expander_spacing * 2 + expander_size;
-      else
-	x = 0;
-      y = priv->spacing;
-
-      width = height = 2 * focus_pad + 2 * focus_width;
-
-      if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-	{
-	  GtkAllocation label_allocation = priv->label_widget->allocation;
-
-	  width  += label_allocation.width;
-	  height += label_allocation.height;
-	}
-    }
-  else
-    {
-      x = y = 0;
-      width = widget->allocation.width - 2 * GTK_CONTAINER (widget)->border_width;
-      height = widget->allocation.height - 2 * GTK_CONTAINER (widget)->border_width;
-    }
-
-  gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
-		   area, widget, "expander",
-		   x, y, width, height);
-}
-
-static gboolean
-e_expander_expose (GtkWidget      *widget,
-		     GdkEventExpose *event)
-{
-  if (GTK_WIDGET_DRAWABLE (widget))
-    {
-      EExpander *expander = E_EXPANDER (widget);
-
-      e_expander_paint (expander);
-
-      if (GTK_WIDGET_HAS_FOCUS (expander))
-	e_expander_paint_focus (expander, &event->area);
-
-      GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
-    }
-
-  return FALSE;
-}
-
-static gboolean
-is_in_expander_panel (EExpander *expander,
-		      GdkWindow   *window,
-		      gint         x,
-		      gint         y)
-{
-  GtkWidget *widget;
-  GdkRectangle area;
-
-  widget = GTK_WIDGET (expander);
-
-  area = get_expander_bounds (expander);
-
-  area.x = 0;
-  area.width = widget->allocation.width;
-
-  if (widget->window == window)
-    {
-      if (x >= area.x && x <= (area.x + area.width) &&
-	  y >= area.y && y <= (area.y + area.height))
-	return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-e_expander_button_press (GtkWidget      *widget,
-			   GdkEventButton *event)
-{
-  EExpander *expander = E_EXPANDER (widget);
-  EExpanderPrivate *priv;
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (event->button == 1 && !priv->button_down)
-    {
-      if (is_in_expander_panel (expander, event->window, event->x, event->y))
-	{
-	  priv->button_down = TRUE;
-	  return TRUE;
-	}
-    }
-
-  return FALSE;
-}
-
-static gboolean
-e_expander_button_release (GtkWidget      *widget,
-                           GdkEventButton *event)
-{
-  EExpander *expander = E_EXPANDER (widget);
-  EExpanderPrivate *priv;
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (event->button == 1 && priv->button_down)
-    {
-      g_signal_emit_by_name (expander, "activate");
-
-      priv->button_down = FALSE;
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static void
-e_expander_maybe_prelight (EExpander *expander)
-{
-  GtkWidget *widget;
-  EExpanderPrivate *priv;
-  GtkStateType state = GTK_STATE_NORMAL;
-
-  widget = GTK_WIDGET (expander);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (!priv->button_down)
-    {
-      gint x, y;
-
-      gdk_window_get_pointer (widget->window, &x, &y, NULL);
-
-      if (is_in_expander_panel (expander, widget->window, x, y))
-	state = GTK_STATE_PRELIGHT;
-    }
-
-  gtk_widget_set_state (widget, state);
-}
-
-static gboolean
-e_expander_motion_notify (GtkWidget      *widget,
-			    GdkEventMotion *event)
-{
-  e_expander_maybe_prelight (E_EXPANDER (widget));
-
-  return FALSE;
-}
-
-static gboolean
-e_expander_enter_notify (GtkWidget        *widget,
-			   GdkEventCrossing *event)
-{
-  e_expander_maybe_prelight (E_EXPANDER (widget));
-
-  return FALSE;
-}
-
-static gboolean
-e_expander_leave_notify (GtkWidget        *widget,
-			   GdkEventCrossing *event)
-{
-  gtk_widget_set_state (widget, GTK_STATE_NORMAL);
-
-  return FALSE;
-}
-
-static gboolean
-focus_child_in (GtkWidget        *widget,
-		GtkDirectionType  direction)
-{
-  GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
-
-  if (!child)
-    return FALSE;
-
-  return gtk_widget_child_focus (child, direction);
-}
-
-static gboolean
-e_expander_focus (GtkWidget        *widget,
-		    GtkDirectionType  direction)
-{
-  EExpanderPrivate *priv;
-  GtkWidget *old_focus_child;
-  gboolean widget_is_focus;
-  gboolean label_can_focus;
-
-  priv = E_EXPANDER_GET_PRIVATE (widget);
-
-  widget_is_focus = gtk_widget_is_focus (widget);
-  old_focus_child = GTK_CONTAINER (widget)->focus_child;
-  label_can_focus = priv->label_widget && GTK_WIDGET_CAN_FOCUS (priv->label_widget);
-
-  if (old_focus_child && old_focus_child == priv->label_widget)
-    {
-      switch (direction)
-	{
-	case GTK_DIR_TAB_BACKWARD:
-	case GTK_DIR_LEFT:
-	case GTK_DIR_UP:
-	  gtk_widget_grab_focus (widget);
-	  return TRUE;
-	case GTK_DIR_DOWN:
-	case GTK_DIR_TAB_FORWARD:
-	case GTK_DIR_RIGHT:
-	  return focus_child_in (widget, direction);
-	}
-    }
-  else if (old_focus_child)
-    {
-      if (gtk_widget_child_focus (old_focus_child, direction))
-	return TRUE;
-
-      switch (direction)
-	{
-	case GTK_DIR_TAB_BACKWARD:
-	case GTK_DIR_LEFT:
-	case GTK_DIR_UP:
-	  if (label_can_focus)
-	    gtk_widget_grab_focus (priv->label_widget);
-	  else
-	    gtk_widget_grab_focus (widget);
-	  return TRUE;
-	case GTK_DIR_DOWN:
-	case GTK_DIR_TAB_FORWARD:
-	case GTK_DIR_RIGHT:
-	  return FALSE;
-	}
-    }
-  else if (widget_is_focus)
-    {
-      switch (direction)
-	{
-	case GTK_DIR_TAB_BACKWARD:
-	case GTK_DIR_LEFT:
-	case GTK_DIR_UP:
-	  return FALSE;
-	case GTK_DIR_DOWN:
-	case GTK_DIR_TAB_FORWARD:
-	case GTK_DIR_RIGHT:
-	  if (label_can_focus)
-	    {
-	      gtk_widget_grab_focus (priv->label_widget);
-	      return TRUE;
-	    }
-
-	  return focus_child_in (widget, direction);
-	}
-    }
-  else
-    {
-      switch (direction)
-	{
-	case GTK_DIR_DOWN:
-	case GTK_DIR_TAB_FORWARD:
-	case GTK_DIR_TAB_BACKWARD:
-	  gtk_widget_grab_focus (widget);
-	  return TRUE;
-	case GTK_DIR_UP:
-	case GTK_DIR_LEFT:
-	case GTK_DIR_RIGHT:
-	  if (!focus_child_in (widget, direction))
-	    {
-	      gtk_widget_grab_focus (widget);
-	    }
-	  return TRUE;
-	}
-    }
-
-  g_return_val_if_reached(FALSE);
-}
-
-static void
-e_expander_add (GtkContainer *container,
-		  GtkWidget    *widget)
-{
-  GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
-
-  g_object_set (G_OBJECT (widget),
-		"visible", E_EXPANDER_GET_PRIVATE (container)->expanded,
-		NULL);
-}
-
-static void
-e_expander_remove (GtkContainer *container,
-		     GtkWidget    *widget)
-{
-  EExpander *expander = E_EXPANDER (container);
-
-  if (E_EXPANDER_GET_PRIVATE (expander)->label_widget == widget)
-    e_expander_set_label_widget (expander, NULL);
-  else
-    GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
-}
-
-static void
-e_expander_forall (GtkContainer *container,
-		     gboolean      include_internals,
-		     GtkCallback   callback,
-		     gpointer      callback_data)
-{
-  GtkBin *bin = GTK_BIN (container);
-  EExpanderPrivate *priv;
-
-  priv = E_EXPANDER_GET_PRIVATE (container);
-
-  if (bin->child)
-    (* callback) (bin->child, callback_data);
-
-  if (priv->label_widget)
-    (* callback) (priv->label_widget, callback_data);
-}
-
-static void
-e_expander_activate (EExpander *expander)
-{
-  e_expander_set_expanded (expander,
-			     !E_EXPANDER_GET_PRIVATE (expander)->expanded);
-}
-
-GtkWidget *
-e_expander_new (const gchar *label)
-{
-  return g_object_new (E_TYPE_EXPANDER, "label", label, NULL);
-}
-
-GtkWidget *
-e_expander_new_with_mnemonic (const gchar *label)
-{
-  return g_object_new (E_TYPE_EXPANDER,
-		       "label", label,
-		       "use_underline", TRUE,
-		       NULL);
-}
-
-static gboolean
-e_expander_animation_timeout (EExpander *expander)
-{
-  EExpanderPrivate *priv;
-  GdkRectangle area;
-  gboolean finish = FALSE;
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (GTK_WIDGET_REALIZED (expander))
-    {
-      area = get_expander_bounds (expander);
-      gdk_window_invalidate_rect (GTK_WIDGET (expander)->window, &area, TRUE);
-    }
-
-  if (priv->expanded)
-    {
-      if (priv->expander_style == GTK_EXPANDER_COLLAPSED)
-	{
-	  priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
-	}
-      else
-	{
-	  priv->expander_style = GTK_EXPANDER_EXPANDED;
-	  finish = TRUE;
-	}
-    }
-  else
-    {
-      if (priv->expander_style == GTK_EXPANDER_EXPANDED)
-	{
-	  priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
-	}
-      else
-	{
-	  priv->expander_style = GTK_EXPANDER_COLLAPSED;
-	  finish = TRUE;
-	}
-    }
-
-  if (finish)
-    {
-      priv->animation_timeout = 0;
-      g_object_set (G_OBJECT (GTK_BIN (expander)->child),
-		    "visible", priv->expanded,
-		    NULL);
-    }
-
-  return !finish;
-}
-
-static void
-e_expander_start_animation (EExpander *expander)
-{
-  EExpanderPrivate *priv;
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (priv->animation_timeout)
-    g_source_remove (priv->animation_timeout);
-
-  priv->animation_timeout =
-		g_timeout_add (50,
-			       (GSourceFunc) e_expander_animation_timeout,
-			       expander);
-}
-
-void
-e_expander_set_expanded (EExpander *expander,
-			   gboolean     expanded)
-{
-  EExpanderPrivate *priv;
-
-  g_return_if_fail (E_IS_EXPANDER (expander));
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  expanded = expanded != FALSE;
-
-  if (priv->expanded != expanded)
-    {
-      priv->expanded = expanded;
-
-      if (GTK_WIDGET_VISIBLE (expander))
-	e_expander_start_animation (expander);
-
-      else if (GTK_BIN (expander)->child)
-	{
-	  priv->expander_style = expanded ? GTK_EXPANDER_EXPANDED :
-					    GTK_EXPANDER_COLLAPSED;
-	  g_object_set (G_OBJECT (GTK_BIN (expander)->child),
-			"visible", priv->expanded,
-			NULL);
-	}
-
-      gtk_widget_queue_resize (GTK_WIDGET (expander));
-
-      g_object_notify (G_OBJECT (expander), "expanded");
-    }
-}
-
-gboolean
-e_expander_get_expanded (EExpander *expander)
-{
-  g_return_val_if_fail (E_IS_EXPANDER (expander), FALSE);
-
-  return E_EXPANDER_GET_PRIVATE (expander)->expanded;
-}
-
-void
-e_expander_set_spacing (EExpander *expander,
-			  gint         spacing)
-{
-  EExpanderPrivate *priv;
-
-  g_return_if_fail (E_IS_EXPANDER (expander));
-  g_return_if_fail (spacing >= 0);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (priv->spacing != spacing)
-    {
-      priv->spacing = spacing;
-
-      gtk_widget_queue_resize (GTK_WIDGET (expander));
-
-      g_object_notify (G_OBJECT (expander), "spacing");
-    }
-}
-
-gint
-e_expander_get_spacing (EExpander *expander)
-{
-  g_return_val_if_fail (E_IS_EXPANDER (expander), 0);
-
-  return E_EXPANDER_GET_PRIVATE (expander)->spacing;
-}
-
-void
-e_expander_set_label (EExpander *expander,
-			const gchar *label)
-{
-  g_return_if_fail (E_IS_EXPANDER (expander));
-
-  if (!label)
-    {
-      e_expander_set_label_widget (expander, NULL);
-    }
-  else
-    {
-      GtkWidget *child;
-
-      child = gtk_label_new (label);
-      gtk_label_set_use_underline (GTK_LABEL (child),
-				   E_EXPANDER_GET_PRIVATE (expander)->use_underline);
-      gtk_widget_show (child);
-
-      e_expander_set_label_widget (expander, child);
-    }
-
-  g_object_notify (G_OBJECT (expander), "label");
-}
-
-/**
- * e_expander_get_label:
- * @expander: a #EExpander
- *
- * If the expander's label widget is a #GtkLabel, return the
- * text in the label widget. (The frame will have a #GtkLabel
- * for the label widget if a non-%NULL argument was passed
- * to e_expander_new().)
- *
- * Return value: the text in the label, or %NULL if there
- *               was no label widget or the lable widget was not
- *               a #GtkLabel. This string is owned by GTK+ and
- *               must not be modified or freed.
- **/
-G_CONST_RETURN char *
-e_expander_get_label (EExpander *expander)
-{
-  EExpanderPrivate *priv;
-
-  g_return_val_if_fail (E_IS_EXPANDER (expander), NULL);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
-    return gtk_label_get_text (GTK_LABEL (priv->label_widget));
-  else
-    return NULL;
-}
-
-void
-e_expander_set_use_underline (EExpander *expander,
-				gboolean     use_underline)
-{
-  EExpanderPrivate *priv;
-
-  g_return_if_fail (E_IS_EXPANDER (expander));
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  use_underline = use_underline != FALSE;
-
-  if (priv->use_underline != use_underline)
-    {
-      priv->use_underline = use_underline;
-
-      if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
-	gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
-
-      g_object_notify (G_OBJECT (expander), "use_underline");
-    }
-}
-
-gboolean
-e_expander_get_use_underline (EExpander *expander)
-{
-  g_return_val_if_fail (E_IS_EXPANDER (expander), FALSE);
-
-  return E_EXPANDER_GET_PRIVATE (expander)->use_underline;
-}
-
-/**
- * e_expander_set_label_widget:
- * @expander: a #EExpander
- * @label_widget: the new label widget
- *
- * Set the label widget for the expander. This is the widget
- * that will appear embedded alongside the expander arrow.
- **/
-void
-e_expander_set_label_widget (EExpander *expander,
-			       GtkWidget   *label_widget)
-{
-  EExpanderPrivate *priv;
-  gboolean need_resize = FALSE;
-
-  g_return_if_fail (E_IS_EXPANDER (expander));
-  g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
-  g_return_if_fail (label_widget == NULL || label_widget->parent == NULL);
-
-  priv = E_EXPANDER_GET_PRIVATE (expander);
-
-  if (priv->label_widget == label_widget)
-    return;
-
-  if (priv->label_widget)
-    {
-      need_resize = GTK_WIDGET_VISIBLE (priv->label_widget);
-      gtk_widget_unparent (priv->label_widget);
-    }
-
-  priv->label_widget = label_widget;
-
-  if (label_widget)
-    {
-      priv->label_widget = label_widget;
-      gtk_widget_set_parent (label_widget, GTK_WIDGET (expander));
-      need_resize |= GTK_WIDGET_VISIBLE (label_widget);
-    }
-
-  if (GTK_WIDGET_VISIBLE (expander) && need_resize)
-    gtk_widget_queue_resize (GTK_WIDGET (expander));
-
-  g_object_notify (G_OBJECT (expander), "label_widget");
-}
-
-/**
- * e_expander_get_label_widget:
- * @expander: a #EExpander
- *
- * Retrieves the label widget for the frame. See
- * e_expander_set_label_widget().
- *
- * Return value: the label widget, or %NULL if there is none.
- **/
-GtkWidget *
-e_expander_get_label_widget (EExpander *expander)
-{
-  g_return_val_if_fail (E_IS_EXPANDER (expander), NULL);
-
-  return E_EXPANDER_GET_PRIVATE (expander)->label_widget;
-}
diff --git a/widgets/misc/e-expander.h b/widgets/misc/e-expander.h
deleted file mode 100644
index 6ddb680..0000000
--- a/widgets/misc/e-expander.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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/>  
- *
- *
- * Authors:
- *		Mark McLoughlin <mark skynet ie>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- * Copyright (C) 2003 Sun Microsystems, Inc.
- *
- */
-
-#ifndef _E_EXPANDER_H_
-#define _E_EXPANDER_H_
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define E_TYPE_EXPANDER            (e_expander_get_type ())
-#define E_EXPANDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_EXPANDER, EExpander))
-#define E_EXPANDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_EXPANDER, EExpanderClass))
-#define E_IS_EXPANDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_EXPANDER))
-#define E_IS_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_EXPANDER))
-#define E_EXPANDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_EXPANDER, EExpanderClass))
-/* ESTUFF #define E_EXPANDER_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_EXPANDER, EExpanderPrivate)) */
-
-typedef struct _EExpander      EExpander;
-typedef struct _EExpanderClass EExpanderClass;
-
-struct _EExpander
-{
-  GtkBin bin;
-};
-
-struct _EExpanderClass
-{
-  GtkBinClass parent_class;
-
-  void (* activate) (EExpander *expander);
-};
-
-GType                 e_expander_get_type          (void);
-
-GtkWidget            *e_expander_new               (const gchar *label);
-GtkWidget            *e_expander_new_with_mnemonic (const gchar *label);
-
-void                  e_expander_set_expanded      (EExpander   *expander,
-                                                    gboolean     expanded);
-gboolean              e_expander_get_expanded      (EExpander   *expander);
-
-/* Spacing between the expander/label and the child */
-void                  e_expander_set_spacing       (EExpander   *expander,
-						      gint       spacing);
-gint                  e_expander_get_spacing       (EExpander   *expander);
-
-void                  e_expander_set_label         (EExpander   *expander,
-                                                    const gchar *label);
-G_CONST_RETURN gchar *e_expander_get_label         (EExpander   *expander);
-
-void                  e_expander_set_use_underline (EExpander   *expander,
-                                                    gboolean     use_underline);
-gboolean              e_expander_get_use_underline (EExpander   *expander);
-
-void                  e_expander_set_label_widget  (EExpander   *expander,
-                                                    GtkWidget   *label_widget);
-GtkWidget            *e_expander_get_label_widget  (EExpander   *expander);
-
-G_END_DECLS
-
-#endif /* _E_EXPANDER_H_ */
diff --git a/widgets/text/Makefile.am b/widgets/text/Makefile.am
index df2b02c..565ec4e 100644
--- a/widgets/text/Makefile.am
+++ b/widgets/text/Makefile.am
@@ -5,6 +5,7 @@ endif
 INCLUDES =					\
 	-I$(top_srcdir)				\
 	-I$(top_srcdir)/widgets			\
+	$(E_UTIL_CFLAGS)			\
 	$(GNOME_PLATFORM_CFLAGS)		\
 	-DG_LOG_DOMAIN=\"e-text\"
 
@@ -30,5 +31,6 @@ libetext_la_LIBADD = 					\
 	$(top_builddir)/e-util/libeutil.la		\
 	$(top_builddir)/a11y/libevolution-a11y.la	\
 	$(top_builddir)/widgets/table/libetable.la	\
+	$(E_UTIL_LIBS)					\
 	$(GNOME_PLATFORM_LIBS)				\
 	$(REGEX_LIBS)



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