aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2011-03-02 22:12:02 +0800
committerMilan Crha <mcrha@redhat.com>2011-03-02 22:13:40 +0800
commit2533e52b8cf543eed874d220a3f039eebe67253e (patch)
tree20b018e5f1b86200982fd7bb324aef3358469070
parenta0854ec1a6591ea10ba7915f37684f78f476fcd4 (diff)
downloadgsoc2013-evolution-2533e52b8cf543eed874d220a3f039eebe67253e.tar.gz
gsoc2013-evolution-2533e52b8cf543eed874d220a3f039eebe67253e.tar.zst
gsoc2013-evolution-2533e52b8cf543eed874d220a3f039eebe67253e.zip
Do not leak attachments in a mail view
-rw-r--r--em-format/em-format.c10
-rw-r--r--em-format/em-format.h2
-rw-r--r--mail/e-mail-attachment-bar.c1
-rw-r--r--mail/em-format-html-display.c103
-rw-r--r--mail/em-format-html-display.h4
-rw-r--r--plugins/mail-to-task/mail-to-task.c1
-rw-r--r--widgets/misc/e-attachment-paned.c1
-rw-r--r--widgets/misc/e-attachment-store.c36
-rw-r--r--widgets/misc/e-attachment-store.h1
9 files changed, 145 insertions, 14 deletions
diff --git a/em-format/em-format.c b/em-format/em-format.c
index 23573331c0..59ae409912 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 64336a9aa8..b1f0746fed 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 22f27fac20..0a5a3271fe 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 fc1281cfc8..e654e87449 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 089b361592..ec29698d46 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 794badc969..558489578a 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 21d736b50b..73773f25a1 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 392dfe6fc7..e1794d653c 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 49980ea3b1..a7839aca71 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,