[evolution/webkit] Do not leak attachments in a mail view



commit e9d35a108416b43abd9d3256215f12ecbff2748f
Author: Milan Crha <mcrha redhat com>
Date:   Wed Mar 2 15:12:02 2011 +0100

    Do not leak attachments in a mail view

 em-format/em-format.c               |   10 ++++
 em-format/em-format.h               |    2 +
 mail/e-mail-attachment-bar.c        |    1 +
 mail/em-format-html-display.c       |  103 ++++++++++++++++++++++++++++++++---
 mail/em-format-html-display.h       |    4 +-
 plugins/mail-to-task/mail-to-task.c |    1 +
 widgets/misc/e-attachment-paned.c   |    1 +
 widgets/misc/e-attachment-store.c   |   36 +++++++++++--
 widgets/misc/e-attachment-store.h   |    1 +
 9 files changed, 145 insertions(+), 14 deletions(-)
---
diff --git a/em-format/em-format.c b/em-format/em-format.c
index 2357333..59ae409 100644
--- a/em-format/em-format.c
+++ b/em-format/em-format.c
@@ -150,6 +150,7 @@ emf_finalize (GObject *object)
 	g_free (emf->charset);
 	g_free (emf->default_charset);
 	g_string_free (emf->part_id, TRUE);
+	g_free (emf->current_message_part_id);
 	g_free (emf->uid);
 
 	if (emf->pending_uri_table != NULL)
@@ -240,6 +241,7 @@ emf_format_clone (EMFormat *emf,
 		emf->message = msg;
 	}
 
+	emf->current_message_part_id = g_strdup ("root-message");
 	g_string_truncate (emf->part_id, 0);
 	if (folder != NULL)
 		/* TODO build some string based on the folder name/location? */
@@ -365,6 +367,7 @@ emf_init (EMFormat *emf)
 	g_queue_init (&emf->header_list);
 	em_format_default_headers (emf);
 	emf->part_id = g_string_new("");
+	emf->current_message_part_id = NULL;
 	emf->validity_found = 0;
 
 	shell = e_shell_get_default ();
@@ -2075,12 +2078,16 @@ emf_message_rfc822 (EMFormat *emf,
 	CamelDataWrapper *dw = camel_medium_get_content ((CamelMedium *)part);
 	const EMFormatHandler *handle;
 	gint len;
+	gchar *parent_message_part_id;
 
 	if (!CAMEL_IS_MIME_MESSAGE (dw)) {
 		em_format_format_source (emf, stream, part, cancellable);
 		return;
 	}
 
+	parent_message_part_id = emf->current_message_part_id;
+	emf->current_message_part_id = g_strdup (emf->part_id->str);
+
 	len = emf->part_id->len;
 	g_string_append_printf(emf->part_id, ".rfc822");
 
@@ -2091,6 +2098,9 @@ emf_message_rfc822 (EMFormat *emf,
 			handle, cancellable, FALSE);
 
 	g_string_truncate (emf->part_id, len);
+
+	g_free (emf->current_message_part_id);
+	emf->current_message_part_id = parent_message_part_id;
 }
 
 static void
diff --git a/em-format/em-format.h b/em-format/em-format.h
index 64336a9..b1f0746 100644
--- a/em-format/em-format.h
+++ b/em-format/em-format.h
@@ -198,6 +198,8 @@ struct _EMFormat {
 
 	/* Current part ID prefix for identifying parts directly. */
 	GString *part_id;
+	/* part_id of the currently processing message (when the message has message-attachments) */
+	gchar *current_message_part_id;
 
 	/* If empty, then all. */
 	GQueue header_list;
diff --git a/mail/e-mail-attachment-bar.c b/mail/e-mail-attachment-bar.c
index 22f27fa..0a5a327 100644
--- a/mail/e-mail-attachment-bar.c
+++ b/mail/e-mail-attachment-bar.c
@@ -185,6 +185,7 @@ mail_attachment_bar_dispose (GObject *object)
 	priv = E_MAIL_ATTACHMENT_BAR (object)->priv;
 
 	if (priv->model != NULL) {
+		e_attachment_store_remove_all (E_ATTACHMENT_STORE (priv->model));
 		g_object_unref (priv->model);
 		priv->model = NULL;
 	}
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index fc1281c..e654e87 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -65,7 +65,7 @@
 #define d(x)
 
 struct _EMFormatHTMLDisplayPrivate {
-	GtkWidget *attachment_view;  /* weak reference */
+	GHashTable *attachment_views;  /* weak reference; message_part_id->EAttachmentView */
 };
 
 struct _smime_pobject {
@@ -106,6 +106,7 @@ static void efhd_attachment_frame (EMFormat *emf, CamelStream *stream, EMFormatP
 static void efhd_message_add_bar (EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
 static gboolean efhd_attachment_button (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject);
 static gboolean efhd_attachment_optional (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *object);
+static void efhd_free_attach_puri_data (EMFormatPURI *puri);
 
 struct _attach_puri {
 	EMFormatPURI puri;
@@ -125,6 +126,7 @@ struct _attach_puri {
 
 	/* Attachment */
 	EAttachment *attachment;
+	gchar *attachment_view_part_id;
 
 	/* image stuff */
 	gint fit_width;
@@ -378,6 +380,28 @@ efhd_xpkcs7mime_button (EMFormatHTML *efh,
 	return TRUE;
 }
 
+static gboolean
+remove_attachment_view_cb (gpointer message_part_id, gpointer attachment_view, gpointer gone_attachment_view)
+{
+	return attachment_view == gone_attachment_view;
+}
+
+static void
+efhd_attachment_view_gone_cb (gpointer efh, GObject *gone_attachment_view)
+{
+	EMFormatHTMLDisplay *efhd = EM_FORMAT_HTML_DISPLAY (efh);
+
+	g_return_if_fail (efhd != NULL);
+
+	g_hash_table_foreach_remove (efhd->priv->attachment_views, remove_attachment_view_cb, gone_attachment_view);
+}
+
+static void
+weak_unref_attachment_view_cb (gpointer message_part_id, gpointer attachment_view, gpointer efh)
+{
+	g_object_weak_unref (G_OBJECT (attachment_view), efhd_attachment_view_gone_cb, efh);
+}
+
 static void
 efhd_format_clone (EMFormat *emf,
                    CamelFolder *folder,
@@ -386,6 +410,14 @@ efhd_format_clone (EMFormat *emf,
                    EMFormat *src,
                    GCancellable *cancellable)
 {
+	EMFormatHTMLDisplay *efhd;
+
+	efhd = EM_FORMAT_HTML_DISPLAY (emf);
+	g_return_if_fail (efhd != NULL);
+
+	g_hash_table_foreach (efhd->priv->attachment_views, weak_unref_attachment_view_cb, efhd);
+	g_hash_table_remove_all (efhd->priv->attachment_views);
+
 	if (emf != src)
 		EM_FORMAT_HTML (emf)->header_wrap_flags = 0;
 
@@ -408,6 +440,8 @@ efhd_format_attachment (EMFormat *emf,
 	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);
+	info->puri.free = efhd_free_attach_puri_data;
+	info->attachment_view_part_id = g_strdup (emf->current_message_part_id);
 	em_format_html_add_pobject (
 		EM_FORMAT_HTML (emf), sizeof (EMFormatHTMLPObject),
 		classid, part, efhd_attachment_button);
@@ -479,6 +513,8 @@ efhd_format_optional (EMFormat *emf,
 	classid = g_strdup_printf ("optional%s", emf->part_id->str);
 	info = (struct _attach_puri *) em_format_add_puri (
 		emf, sizeof (*info), classid, part, efhd_attachment_frame);
+	info->puri.free = efhd_free_attach_puri_data;
+	info->attachment_view_part_id = g_strdup (emf->current_message_part_id);
 	em_format_html_add_pobject (
 		EM_FORMAT_HTML (emf), sizeof (EMFormatHTMLPObject),
 		classid, part, efhd_attachment_optional);
@@ -595,14 +631,35 @@ efhd_format_secure (EMFormat *emf,
 }
 
 static void
+efhd_finalize (GObject *object)
+{
+	EMFormatHTMLDisplay *efhd;
+
+	efhd = EM_FORMAT_HTML_DISPLAY (object);
+	g_return_if_fail (efhd != NULL);
+
+	if (efhd->priv->attachment_views) {
+		g_hash_table_foreach (efhd->priv->attachment_views, weak_unref_attachment_view_cb, efhd);
+		g_hash_table_destroy (efhd->priv->attachment_views);
+		efhd->priv->attachment_views = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
 efhd_class_init (EMFormatHTMLDisplayClass *class)
 {
+	GObjectClass *object_class;
 	EMFormatClass *format_class;
 	EMFormatHTMLClass *format_html_class;
 
 	parent_class = g_type_class_peek_parent (class);
 	g_type_class_add_private (class, sizeof (EMFormatHTMLDisplayPrivate));
 
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = efhd_finalize;
+
 	format_class = EM_FORMAT_CLASS (class);
 	format_class->format_clone = efhd_format_clone;
 	format_class->format_attachment = efhd_format_attachment;
@@ -623,6 +680,7 @@ efhd_init (EMFormatHTMLDisplay *efhd)
 	web_view = em_format_html_get_web_view (EM_FORMAT_HTML (efhd));
 
 	efhd->priv = G_TYPE_INSTANCE_GET_PRIVATE (efhd, EM_TYPE_FORMAT_HTML_DISPLAY, EMFormatHTMLDisplayPrivate);
+	efhd->priv->attachment_views = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
 	e_mail_display_set_formatter (
 		E_MAIL_DISPLAY (web_view), EM_FORMAT_HTML (efhd));
@@ -841,7 +899,7 @@ efhd_attachment_button (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObj
 	parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 
-	view = em_format_html_display_get_attachment_view (efhd);
+	view = em_format_html_display_get_attachment_view (efhd, info->attachment_view_part_id);
 	gtk_widget_show (GTK_WIDGET (view));
 
 	store = e_attachment_view_get_store (view);
@@ -894,6 +952,12 @@ efhd_attachment_frame (EMFormat *emf,
 }
 
 static void
+set_size_request_cb (gpointer message_part_id, gpointer widget, gpointer width)
+{
+	gtk_widget_set_size_request (widget, GPOINTER_TO_INT (width), -1);
+}
+
+static void
 efhd_bar_resize (EMFormatHTML *efh,
                  GtkAllocation *event)
 {
@@ -912,8 +976,7 @@ efhd_bar_resize (EMFormatHTML *efh,
 	width = allocation.width - 12;
 
 	if (width > 0) {
-		widget = priv->attachment_view;
-		gtk_widget_set_size_request (widget, width, -1);
+		g_hash_table_foreach (priv->attachment_views, set_size_request_cb, GINT_TO_POINTER (width));
 	}
 }
 
@@ -933,7 +996,9 @@ efhd_add_bar (EMFormatHTML *efh,
 
 	widget = e_mail_attachment_bar_new ();
 	gtk_container_add (GTK_CONTAINER (eb), widget);
-	priv->attachment_view = widget;
+
+	g_hash_table_insert (priv->attachment_views, g_strdup (EM_FORMAT (efh)->current_message_part_id), widget);
+	g_object_weak_ref (G_OBJECT (widget), efhd_attachment_view_gone_cb, efh);
 	gtk_widget_hide (widget);
 
 	g_signal_connect_swapped (
@@ -1086,10 +1151,34 @@ efhd_attachment_optional (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPO
 	return TRUE;
 }
 
+static void
+efhd_free_attach_puri_data (EMFormatPURI *puri)
+{
+	struct _attach_puri *info = (struct _attach_puri *) puri;
+
+	g_return_if_fail (puri != NULL);
+
+	if (info->attachment) {
+		g_object_unref (info->attachment);
+		info->attachment = NULL;
+	}
+
+	g_free (info->attachment_view_part_id);
+	info->attachment_view_part_id = NULL;
+}
+
+/* returned object owned by html_display, thus do not unref it */
 EAttachmentView *
-em_format_html_display_get_attachment_view (EMFormatHTMLDisplay *html_display)
+em_format_html_display_get_attachment_view (EMFormatHTMLDisplay *html_display, const gchar *message_part_id)
 {
+	gpointer aview;
+
 	g_return_val_if_fail (EM_IS_FORMAT_HTML_DISPLAY (html_display), NULL);
+	g_return_val_if_fail (message_part_id != NULL, NULL);
+
+	/* it should be added in efhd_add_bar() with this message_part_id */
+	aview = g_hash_table_lookup (html_display->priv->attachment_views, message_part_id);
+	g_return_val_if_fail (aview != NULL, NULL);
 
-	return E_ATTACHMENT_VIEW (html_display->priv->attachment_view);
+	return E_ATTACHMENT_VIEW (aview);
 }
diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h
index 089b361..ec29698 100644
--- a/mail/em-format-html-display.h
+++ b/mail/em-format-html-display.h
@@ -69,8 +69,8 @@ EMFormatHTMLDisplay *
 		em_format_html_display_new	(void);
 EAttachmentView *
 		em_format_html_display_get_attachment_view
-						(EMFormatHTMLDisplay *html_display);
-
+						(EMFormatHTMLDisplay *html_display,
+						 const gchar *message_part_id);
 G_END_DECLS
 
 #endif /* EM_FORMAT_HTML_DISPLAY_H */
diff --git a/plugins/mail-to-task/mail-to-task.c b/plugins/mail-to-task/mail-to-task.c
index 794badc..5584895 100644
--- a/plugins/mail-to-task/mail-to-task.c
+++ b/plugins/mail-to-task/mail-to-task.c
@@ -384,6 +384,7 @@ set_attachments (ECal *client, ECalComponent *comp, CamelMimeMessage *message)
 	/* XXX Does this take ownership of the list? */
 	e_cal_component_set_attachment_list (comp, uri_list);
 
+	e_attachment_store_remove_all (store);
 	g_object_unref (destination);
 	g_object_unref (store);
 }
diff --git a/widgets/misc/e-attachment-paned.c b/widgets/misc/e-attachment-paned.c
index 21d736b..73773f2 100644
--- a/widgets/misc/e-attachment-paned.c
+++ b/widgets/misc/e-attachment-paned.c
@@ -221,6 +221,7 @@ attachment_paned_dispose (GObject *object)
 	priv = E_ATTACHMENT_PANED (object)->priv;
 
 	if (priv->model != NULL) {
+		e_attachment_store_remove_all (E_ATTACHMENT_STORE (priv->model));
 		g_object_unref (priv->model);
 		priv->model = NULL;
 	}
diff --git a/widgets/misc/e-attachment-store.c b/widgets/misc/e-attachment-store.c
index 392dfe6..e1794d6 100644
--- a/widgets/misc/e-attachment-store.c
+++ b/widgets/misc/e-attachment-store.c
@@ -108,11 +108,7 @@ attachment_store_get_property (GObject *object,
 static void
 attachment_store_dispose (GObject *object)
 {
-	EAttachmentStorePrivate *priv;
-
-	priv = E_ATTACHMENT_STORE (object)->priv;
-
-	g_hash_table_remove_all (priv->attachment_index);
+	e_attachment_store_remove_all (E_ATTACHMENT_STORE (object));
 
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_attachment_store_parent_class)->dispose (object);
@@ -327,6 +323,36 @@ e_attachment_store_remove_attachment (EAttachmentStore *store,
 }
 
 void
+e_attachment_store_remove_all (EAttachmentStore *store)
+{
+	GList *list, *iter;
+
+	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+	if (!g_hash_table_size (store->priv->attachment_index))
+		return;
+
+	g_object_freeze_notify (G_OBJECT (store));
+
+	list = e_attachment_store_get_attachments (store);
+	for (iter = list; iter; iter = iter->next) {
+		EAttachment *attachment = iter->data;
+
+		e_attachment_cancel (attachment);
+		g_hash_table_remove (store->priv->attachment_index, iter->data);
+	}
+
+	g_list_foreach (list, (GFunc) g_object_unref, NULL);
+	g_list_free (list);
+
+	gtk_list_store_clear (GTK_LIST_STORE (store));
+
+	g_object_notify (G_OBJECT (store), "num-attachments");
+	g_object_notify (G_OBJECT (store), "total-size");
+	g_object_thaw_notify (G_OBJECT (store));
+}
+
+void
 e_attachment_store_add_to_multipart (EAttachmentStore *store,
                                      CamelMultipart *multipart,
                                      const gchar *default_charset)
diff --git a/widgets/misc/e-attachment-store.h b/widgets/misc/e-attachment-store.h
index 49980ea..a7839ac 100644
--- a/widgets/misc/e-attachment-store.h
+++ b/widgets/misc/e-attachment-store.h
@@ -80,6 +80,7 @@ void		e_attachment_store_add_attachment
 gboolean	e_attachment_store_remove_attachment
 						(EAttachmentStore *store,
 						 EAttachment *attachment);
+void		e_attachment_store_remove_all	(EAttachmentStore *store);
 void		e_attachment_store_add_to_multipart
 						(EAttachmentStore *store,
 						 CamelMultipart *multipart,



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