[evolution] Bug #674887 - Hang on sender's photo lookup



commit 4f47f662f6daa7b9a3daed77d66b2022ae8398ab
Author: Dan VrÃtil <dvratil redhat com>
Date:   Thu Jun 14 12:01:41 2012 +0200

    Bug #674887 - Hang on sender's photo lookup

 em-format/e-mail-formatter-headers.c |   38 +++++------
 em-format/e-mail-parser-headers.c    |   26 +++++++
 libemail-engine/e-mail-utils.c       |   44 ++----------
 libemail-engine/e-mail-utils.h       |    3 +-
 mail/e-mail-display.c                |   11 ++-
 mail/e-mail-request.c                |  125 +++++++++++++++++++++++++++++++++-
 6 files changed, 181 insertions(+), 66 deletions(-)
---
diff --git a/em-format/e-mail-formatter-headers.c b/em-format/e-mail-formatter-headers.c
index 24d2713..8971adf 100644
--- a/em-format/e-mail-formatter-headers.c
+++ b/em-format/e-mail-formatter-headers.c
@@ -248,9 +248,6 @@ format_full_headers (EMailFormatter *formatter,
 	struct _camel_header_raw *header;
 	gboolean have_icon = FALSE;
 	const gchar *photo_name = NULL;
-	CamelInternetAddress *cia = NULL;
-	EShell *shell;
-	ESourceRegistry *registry;
 	gboolean face_decoded  = FALSE, contact_has_photo = FALSE;
 	guchar *face_header_value = NULL;
 	gsize face_header_len = 0;
@@ -262,9 +259,6 @@ format_full_headers (EMailFormatter *formatter,
 	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
-	shell = e_shell_get_default ();
-	registry = e_shell_get_registry (shell);
-
 	ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
 	charset = camel_content_type_param (ct, "charset");
 	charset = camel_iconv_charset_name (charset);
@@ -327,7 +321,7 @@ format_full_headers (EMailFormatter *formatter,
 
 		g_string_append (
 			buffer,
-			"<tr><td><table border=1 width=\"100%%\" "
+			"<tr valign=\"top\"><td><table border=1 width=\"100%%\" "
 			"cellspacing=2 cellpadding=2><tr>");
 		if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
 			g_string_append (
@@ -352,7 +346,10 @@ format_full_headers (EMailFormatter *formatter,
 	g_free (header_sender);
 	g_free (header_from);
 
-	g_string_append (buffer, "<tr><td width=\"100%%\"><table border=0 cellpadding=\"0\">\n");
+	g_string_append (
+		buffer,
+		"<tr valign=\"top\"><td width=\"100%%\">"
+		"<table border=0 cellpadding=\"0\">\n");
 
 	g_free (evolution_imagesdir);
 
@@ -446,22 +443,20 @@ format_full_headers (EMailFormatter *formatter,
 	g_string_append (buffer, "</table></td>");
 
 	if (photo_name) {
-		CamelMimePart *photopart;
 		gboolean only_local_photo;
+		gchar *name;
 
-		cia = camel_internet_address_new ();
-		camel_address_decode ((CamelAddress *) cia, (const gchar *) photo_name);
+		name = g_uri_escape_string (photo_name, NULL, FALSE);
 		only_local_photo = e_mail_formatter_get_only_local_photos (formatter);
-		photopart = em_utils_contact_photo (
-			registry, cia, only_local_photo);
+		g_string_append (buffer, "<td align=\"right\" valign=\"top\">");
 
-		if (photopart) {
-			g_string_append (buffer, "<td align=\"right\" valign=\"top\">");
-			write_contact_picture (photopart, -1, buffer);
-			g_string_append (buffer, "</td>");
-			g_object_unref (photopart);
-		}
-		g_object_unref (cia);
+		g_string_append_printf (buffer,
+			"<img src=\"mail://contact-photo?mailaddr=&only-local-photo=1\" "
+			"data-mailaddr=\"%s\" %s id=\"__evo-contact-photo\"/>",
+			name, only_local_photo ? "data-onlylocal=1" : "");
+		g_string_append (buffer, "</td>");
+
+		g_free (name);
 	}
 
 	if (!contact_has_photo && face_decoded) {
@@ -536,10 +531,11 @@ emfe_headers_format (EMailFormatterExtension *extension,
 
 	g_string_append_printf (
 		buffer,
-		"<div class=\"headers\" style=\"background: #%06x;\">"
+		"<div class=\"headers\" style=\"background: #%06x;\" id=\"%s\">"
 		"<table border=\"0\" width=\"100%%\" style=\"color: #%06x;\">\n"
 		"<tr><td valign=\"top\" width=\"16\">\n",
 		bg_color,
+		part->id,
 		e_color_to_value ((GdkColor *)
 			e_mail_formatter_get_color (
 				formatter,
diff --git a/em-format/e-mail-parser-headers.c b/em-format/e-mail-parser-headers.c
index 06f2874..0a2c2bd 100644
--- a/em-format/e-mail-parser-headers.c
+++ b/em-format/e-mail-parser-headers.c
@@ -58,6 +58,31 @@ G_DEFINE_TYPE_EXTENDED (
 
 static const gchar *parser_mime_types[] = { "application/vnd.evolution.headers", NULL };
 
+static void
+empe_headers_bind_dom (EMailPart *part,
+		       WebKitDOMElement *element)
+{
+	WebKitDOMDocument *document;
+	WebKitDOMElement *photo;
+	gchar *addr, *uri;
+	gboolean only_local;
+
+	document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
+	photo = webkit_dom_document_get_element_by_id (document, "__evo-contact-photo");
+
+	addr = webkit_dom_element_get_attribute (photo, "data-mailaddr");
+	only_local = webkit_dom_element_has_attribute (photo, "data-onlylocal");
+
+	uri = g_strdup_printf ("mail://contact-photo?mailaddr=%s%s",
+		addr, only_local ? "&only-local-photo=1" : "");
+
+	webkit_dom_html_image_element_set_src (
+		WEBKIT_DOM_HTML_IMAGE_ELEMENT (photo), uri);
+
+	g_free (addr);
+	g_free (uri);
+}
+
 static GSList *
 empe_headers_parse (EMailParserExtension *extension,
                     EMailParser *parser,
@@ -76,6 +101,7 @@ empe_headers_parse (EMailParserExtension *extension,
 
 	mail_part = e_mail_part_new (part, part_id->str);
 	mail_part->mime_type = g_strdup ("application/vnd.evolution.headers");
+	mail_part->bind_func = empe_headers_bind_dom;
 	g_string_truncate (part_id, len);
 
 	return g_slist_append (NULL, mail_part);
diff --git a/libemail-engine/e-mail-utils.c b/libemail-engine/e-mail-utils.c
index 9e13a74..7fca5eb 100644
--- a/libemail-engine/e-mail-utils.c
+++ b/libemail-engine/e-mail-utils.c
@@ -278,26 +278,6 @@ em_utils_folder_is_outbox (ESourceRegistry *registry,
 
 /* ********************************************************************** */
 
-static void
-emu_addr_cancel_stop (gpointer data)
-{
-	gboolean *stop = data;
-
-	g_return_if_fail (stop != NULL);
-
-	*stop = TRUE;
-}
-
-static void
-emu_addr_cancel_cancellable (gpointer data)
-{
-	GCancellable *cancellable = data;
-
-	g_return_if_fail (cancellable != NULL);
-
-	g_cancellable_cancel (cancellable);
-}
-
 struct TryOpenEBookStruct {
 	GError **error;
 	EFlag *flag;
@@ -399,7 +379,8 @@ search_address_in_addressbooks (ESourceRegistry *registry,
                                 gboolean local_only,
                                 gboolean (*check_contact) (EContact *contact,
                                                            gpointer user_data),
-                                gpointer user_data)
+                                gpointer user_data,
+				GCancellable *cancellable)
 {
 	GList *list, *link;
 	GList *addr_sources = NULL;
@@ -408,8 +389,6 @@ search_address_in_addressbooks (ESourceRegistry *registry,
 	gpointer ptr;
 	EBookQuery *book_query;
 	gchar *query;
-	GHook *hook_cancellable;
-	GCancellable *cancellable;
 	const gchar *extension_name;
 
 	if (!address || !*address)
@@ -474,15 +453,10 @@ search_address_in_addressbooks (ESourceRegistry *registry,
 
 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
 
-	cancellable = g_cancellable_new ();
-	hook_cancellable = mail_cancel_hook_add (
-		emu_addr_cancel_cancellable, cancellable);
-
 	for (link = addr_sources; !stop && !found && link != NULL; link = g_list_next (link)) {
 		ESource *source = E_SOURCE (link->data);
 		GSList *contacts;
 		EBookClient *book_client = NULL;
-		GHook *hook_stop;
 		gboolean cached_book = FALSE;
 		const gchar *display_name;
 		const gchar *uid;
@@ -500,8 +474,6 @@ search_address_in_addressbooks (ESourceRegistry *registry,
 
 		d(printf(" checking '%s'\n", e_source_get_uri(source)));
 
-		hook_stop = mail_cancel_hook_add (emu_addr_cancel_stop, &stop);
-
 		book_client = g_hash_table_lookup (emu_books_hash, uid);
 		if (!book_client) {
 			book_client = e_book_client_new (source, &err);
@@ -601,8 +573,6 @@ search_address_in_addressbooks (ESourceRegistry *registry,
 			g_clear_error (&err);
 		}
 
-		mail_cancel_hook_remove (hook_stop);
-
 		if (stop && !cached_book && book_client) {
 			g_object_unref (book_client);
 		} else if (!stop && book_client && !cached_book) {
@@ -611,9 +581,6 @@ search_address_in_addressbooks (ESourceRegistry *registry,
 		}
 	}
 
-	mail_cancel_hook_remove (hook_cancellable);
-	g_object_unref (cancellable);
-
 	g_list_free_full (addr_sources, (GDestroyNotify) g_object_unref);
 
 	g_free (query);
@@ -644,7 +611,7 @@ em_utils_in_addressbook (ESourceRegistry *registry,
 		return FALSE;
 
 	return search_address_in_addressbooks (
-		registry, addr, local_only, NULL, NULL);
+		registry, addr, local_only, NULL, NULL, NULL);
 }
 
 static gboolean
@@ -687,7 +654,8 @@ static GSList *photos_cache = NULL; /* list of PhotoInfo-s */
 CamelMimePart *
 em_utils_contact_photo (ESourceRegistry *registry,
                         CamelInternetAddress *cia,
-                        gboolean local_only)
+                        gboolean local_only,
+			GCancellable *cancellable)
 {
 	const gchar *addr = NULL;
 	CamelMimePart *part = NULL;
@@ -723,7 +691,7 @@ em_utils_contact_photo (ESourceRegistry *registry,
 
 	/* !p means the address had not been found in the cache */
 	if (!p && search_address_in_addressbooks (
-		registry, addr, local_only, extract_photo_data, &photo)) {
+		registry, addr, local_only, extract_photo_data, &photo, cancellable)) {
 
 		PhotoInfo *pi;
 
diff --git a/libemail-engine/e-mail-utils.h b/libemail-engine/e-mail-utils.h
index 505249a..8898204 100644
--- a/libemail-engine/e-mail-utils.h
+++ b/libemail-engine/e-mail-utils.h
@@ -38,7 +38,8 @@ gboolean	em_utils_in_addressbook		(ESourceRegistry *registry,
 						 gboolean local_only);
 CamelMimePart *	em_utils_contact_photo		(ESourceRegistry *registry,
 						 CamelInternetAddress *addr,
-						 gboolean local);
+						 gboolean local,
+						 GCancellable *cancellable);
 ESource *	em_utils_guess_mail_account	(ESourceRegistry *registry,
 						 CamelMimeMessage *message,
 						 CamelFolder *folder);
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 33922d8..1ca8bcc 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -1048,6 +1048,7 @@ toggle_headers_visibility (WebKitDOMElement *button,
 	WebKitDOMCSSStyleDeclaration *css_short, *css_full;
 	gboolean expanded;
 	const gchar *path;
+	gchar *css_value;
 
 	document = webkit_web_view_get_dom_document (web_view);
 
@@ -1064,9 +1065,10 @@ toggle_headers_visibility (WebKitDOMElement *button,
 		return;
 
 	css_full = webkit_dom_element_get_style (full_headers);
-
-	expanded = (g_strcmp0 (webkit_dom_css_style_declaration_get_property_value (
-			css_full, "display"), "block") == 0);
+	css_value = webkit_dom_css_style_declaration_get_property_value (
+			css_full, "display");
+	expanded = (g_strcmp0 (css_value, "block") == 0);
+	g_free (css_value);
 
 	webkit_dom_css_style_declaration_set_property (css_full, "display",
 		expanded ? "none" : "block", "", NULL);
@@ -1233,6 +1235,9 @@ mail_parts_bind_dom (GObject *object,
 		return;
 
 	frame_name = webkit_web_frame_get_name (frame);
+	if (!frame_name || !*frame_name)
+		frame_name = ".message.headers";
+
 	for (iter = display->priv->part_list->list; iter; iter = iter->next) {
 
 		EMailPart *part = iter->data;
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index 01c1144..5805a10 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -19,6 +19,7 @@
 #define LIBSOUP_USE_UNSTABLE_REQUEST_API
 
 #include "e-mail-request.h"
+#include "em-utils.h"
 
 #include <libsoup/soup.h>
 #include <libsoup/soup-requester.h>
@@ -36,6 +37,8 @@
 #include <e-util/e-icon-factory.h>
 #include <e-util/e-util.h>
 
+#include <shell/e-shell.h>
+
 #define d(x)
 #define dd(x)
 
@@ -164,6 +167,116 @@ handle_mail_request (GSimpleAsyncResult *res,
 	g_simple_async_result_set_op_res_gpointer (res, stream, NULL);
 }
 
+static GInputStream *
+get_empty_image_stream (gsize *len)
+{
+	GdkPixbuf *p;
+	gchar *buff;
+	GInputStream *stream;
+
+	p = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
+	gdk_pixbuf_fill (p, 0x00000000);	/* transparent black */
+	gdk_pixbuf_save_to_buffer (p, &buff, len, "png", NULL, NULL);
+
+	stream = g_memory_input_stream_new_from_data (buff, *len, g_free);
+
+	g_object_unref (p);
+
+	return stream;
+}
+
+static void
+handle_contact_photo_request (GSimpleAsyncResult *res,
+			      GObject *object,
+			      GCancellable *cancellable)
+{
+	EMailRequest *request = E_MAIL_REQUEST (object);
+	const gchar *email;
+	gchar *photo_name;
+	gboolean only_local_photo;
+	CamelMimePart *photopart;
+	EShell *shell;
+	ESourceRegistry *registry;
+	CamelInternetAddress *cia;
+	CamelDataWrapper *dw;
+	GByteArray *ba;
+	GInputStream *stream = NULL;
+
+	shell = e_shell_get_default ();
+	registry = e_shell_get_registry (shell);
+
+	request->priv->mime_type = g_strdup ("image/*");
+
+	email = g_hash_table_lookup (
+			request->priv->uri_query, "mailaddr");
+	if (!email || !*email) {
+		gsize len;
+
+		stream = get_empty_image_stream (&len);
+		request->priv->content_length = len;
+
+		g_simple_async_result_set_op_res_gpointer (res, stream, NULL);
+		return;
+	}
+
+	photo_name = g_uri_unescape_string (email, NULL);
+	only_local_photo = g_hash_table_lookup_extended (
+				request->priv->uri_query, "only-local-photo",
+				NULL, NULL);
+
+	cia = camel_internet_address_new ();
+	camel_address_decode ((CamelAddress *) cia, (const gchar *) photo_name);
+	photopart = em_utils_contact_photo (
+			registry, cia, only_local_photo, cancellable);
+	if (!photopart) {
+		gsize len;
+
+		stream = get_empty_image_stream (&len);
+		request->priv->content_length = len;
+
+		g_simple_async_result_set_op_res_gpointer (res, stream, NULL);
+		g_free (photo_name);
+		return;
+	}
+
+	ba = NULL;
+	dw = camel_medium_get_content (CAMEL_MEDIUM (photopart));
+	if (dw) {
+		ba = camel_data_wrapper_get_byte_array (dw);
+	}
+
+	if (!ba || ba->len == 0) {
+
+		const gchar *filename = camel_mime_part_get_filename (photopart);
+
+		if (filename && *filename &&
+		    g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+			gchar *data;
+			gsize len;
+
+			if (!g_file_get_contents (filename, &data, &len, NULL)) {
+				stream = get_empty_image_stream (&len);
+			} else {
+				stream = g_memory_input_stream_new_from_data (
+					(gchar *) data, len, g_free);
+			}
+
+			request->priv->content_length = len;
+		}
+
+	} else {
+
+		stream = g_memory_input_stream_new_from_data (
+				(gchar *) ba->data, ba->len, NULL);
+
+		request->priv->content_length = ba->len;
+
+	}
+
+	g_free (photo_name);
+	g_simple_async_result_set_op_res_gpointer (res, stream, NULL);
+}
+
 static void
 mail_request_finalize (GObject *object)
 {
@@ -233,9 +346,15 @@ mail_request_send_async (SoupRequest *request,
 
 	g_simple_async_result_set_check_cancellable (simple, cancellable);
 
-	g_simple_async_result_run_in_thread (
-		simple, handle_mail_request,
-		G_PRIORITY_DEFAULT, cancellable);
+	if (g_strcmp0 (uri->host, "contact-photo") == 0) {
+		g_simple_async_result_run_in_thread (
+			simple, handle_contact_photo_request,
+			G_PRIORITY_DEFAULT, cancellable);
+	} else {
+		g_simple_async_result_run_in_thread (
+			simple, handle_mail_request,
+			G_PRIORITY_DEFAULT, cancellable);
+	}
 
 	g_object_unref (simple);
 }



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