[evolution] EMailReader: Reimplement "mail-remove-duplicates" action.



commit 63a7f4d1ccd62b543a0b82a6d11c2d2b24ef1125
Author: Matthew Barnes <mbarnes redhat com>
Date:   Tue May 10 17:27:49 2011 -0400

    EMailReader: Reimplement "mail-remove-duplicates" action.
    
    Now uses e_mail_folder_find_duplicate_messages().

 mail/e-mail-reader-utils.c |  157 ++++++++++++++++++++++++++++++++++++++++++++
 mail/e-mail-reader-utils.h |    1 +
 mail/e-mail-reader.c       |  154 +------------------------------------------
 mail/mail.error.xml        |    5 ++
 4 files changed, 166 insertions(+), 151 deletions(-)
---
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index 1696467..374bed0 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -34,6 +34,7 @@
 
 #include "mail/e-mail-backend.h"
 #include "mail/e-mail-browser.h"
+#include "mail/e-mail-folder-utils.h"
 #include "mail/em-composer-utils.h"
 #include "mail/em-format-html-print.h"
 #include "mail/em-utils.h"
@@ -43,6 +44,25 @@
 #include "mail/mail-vfolder.h"
 #include "mail/message-list.h"
 
+typedef struct _AsyncContext AsyncContext;
+
+struct _AsyncContext {
+	EActivity *activity;
+	EMailReader *reader;
+};
+
+static void
+async_context_free (AsyncContext *context)
+{
+	if (context->activity != NULL)
+		g_object_unref (context->activity);
+
+	if (context->reader != NULL)
+		g_object_unref (context->reader);
+
+	g_slice_free (AsyncContext, context);
+}
+
 void
 e_mail_reader_activate (EMailReader *reader,
                         const gchar *action_name)
@@ -337,6 +357,143 @@ exit:
 	em_utils_uids_free (uids);
 }
 
+static void
+mail_reader_remove_duplicates_cb (CamelFolder *folder,
+                                  GAsyncResult *result,
+                                  AsyncContext *context)
+{
+	EAlertSink *alert_sink;
+	GHashTable *duplicates;
+	GtkWindow *parent_window;
+	guint n_duplicates;
+	GError *error = NULL;
+
+	alert_sink = e_mail_reader_get_alert_sink (context->reader);
+	parent_window = e_mail_reader_get_window (context->reader);
+
+	duplicates = e_mail_folder_find_duplicate_messages_finish (
+		folder, result, &error);
+
+	/* Ignore cancellations. */
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_warn_if_fail (duplicates == NULL);
+		e_activity_set_state (context->activity, E_ACTIVITY_CANCELLED);
+		async_context_free (context);
+		g_error_free (error);
+		return;
+
+	} else if (error != NULL) {
+		g_warn_if_fail (duplicates == NULL);
+		e_alert_submit (
+			alert_sink,
+			"mail:find-duplicate-messages",
+			error->message, NULL);
+		async_context_free (context);
+		g_error_free (error);
+		return;
+	}
+
+	g_return_if_fail (duplicates != NULL);
+
+	/* Finalize the activity here so we don't leave a message in
+	 * the task bar while prompting the user for confirmation. */
+	e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED);
+	g_object_unref (context->activity);
+	context->activity = NULL;
+
+	n_duplicates = g_hash_table_size (duplicates);
+
+	if (n_duplicates == 0) {
+		em_utils_prompt_user (
+			parent_window, NULL,
+			"mail:info-no-remove-duplicates",
+			camel_folder_get_display_name (folder), NULL);
+	} else {
+		gchar *confirmation;
+		gboolean proceed;
+
+		confirmation = g_strdup_printf (ngettext (
+			/* Translators: %s is replaced with a folder
+			 * name %u with count of duplicate messages. */
+			"Folder '%s' contains %u duplicate message. "
+			"Are you sure you want to delete it?",
+			"Folder '%s' contains %u duplicate messages. "
+			"Are you sure you want to delete them?",
+			n_duplicates),
+			camel_folder_get_display_name (folder),
+			n_duplicates);
+
+		proceed = em_utils_prompt_user (
+			parent_window, NULL,
+			"mail:ask-remove-duplicates",
+			confirmation, NULL);
+
+		if (proceed) {
+			GHashTableIter iter;
+			gpointer key;
+
+			camel_folder_freeze (folder);
+
+			g_hash_table_iter_init (&iter, duplicates);
+
+			/* Mark duplicate messages for deletion. */
+			while (g_hash_table_iter_next (&iter, &key, NULL))
+				camel_folder_delete_message (folder, key);
+
+			camel_folder_thaw (folder);
+		}
+
+		g_free (confirmation);
+	}
+
+	g_hash_table_destroy (duplicates);
+
+	async_context_free (context);
+}
+
+void
+e_mail_reader_remove_duplicates (EMailReader *reader)
+{
+	AsyncContext *context;
+	GCancellable *cancellable;
+	EMailBackend *backend;
+	CamelFolder *folder;
+	GPtrArray *uids;
+
+	g_return_if_fail (E_IS_MAIL_READER (reader));
+
+	folder = e_mail_reader_get_folder (reader);
+	uids = e_mail_reader_get_selected_uids (reader);
+	g_return_if_fail (uids != NULL);
+
+	/* XXX Either e_mail_reader_get_selected_uids()
+	 *     or MessageList should do this itself. */
+	g_ptr_array_set_free_func (uids, (GDestroyNotify) g_free);
+
+	/* Find duplicate messages asynchronously. */
+
+	context = g_slice_new0 (AsyncContext);
+	context->activity = e_activity_new ();
+	context->reader = g_object_ref (reader);
+
+	cancellable = camel_operation_new ();
+	e_activity_set_cancellable (context->activity, cancellable);
+
+	backend = e_mail_reader_get_backend (reader);
+	e_shell_backend_add_activity (
+		E_SHELL_BACKEND (backend), context->activity);
+
+	e_mail_folder_find_duplicate_messages (
+		folder, uids, G_PRIORITY_DEFAULT,
+		cancellable, (GAsyncReadyCallback)
+		mail_reader_remove_duplicates_cb,
+		context);
+
+	g_object_unref (cancellable);
+
+	g_ptr_array_unref (uids);
+}
+
 /* Helper for e_mail_reader_reply_to_message()
  * XXX This function belongs in e-html-utils.c */
 static gboolean
diff --git a/mail/e-mail-reader-utils.h b/mail/e-mail-reader-utils.h
index 04b46b6..f06d4db 100644
--- a/mail/e-mail-reader-utils.h
+++ b/mail/e-mail-reader-utils.h
@@ -47,6 +47,7 @@ guint		e_mail_reader_mark_selected	(EMailReader *reader,
 guint		e_mail_reader_open_selected	(EMailReader *reader);
 void		e_mail_reader_print		(EMailReader *reader,
 						 GtkPrintOperationAction action);
+void		e_mail_reader_remove_duplicates	(EMailReader *reader);
 void		e_mail_reader_reply_to_message	(EMailReader *reader,
 						 CamelMimeMessage *message,
 						 EMailReplyType reply_type);
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index dc163bd..ec66776 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -410,159 +410,11 @@ action_mail_remove_attachments_cb (GtkAction *action, EMailReader *reader)
 	mail_remove_attachments (folder, uids);
 }
 
-static gchar *
-get_message_checksum (CamelFolder *folder, CamelMimeMessage *msg)
-{
-	static const GChecksumType duplicate_csum = G_CHECKSUM_SHA256;
-
-	CamelDataWrapper *content;
-	CamelStream *mem;
-	GByteArray *buffer;
-	gchar *digest = NULL;
-
-	if (!msg)
-		return NULL;
-
-	/* get message contents */
-	content = camel_medium_get_content ((CamelMedium *) msg);
-	if (!content)
-		return NULL;
-
-	/* calculate checksum */
-	mem = camel_stream_mem_new ();
-	camel_data_wrapper_decode_to_stream_sync (content, mem, NULL, NULL);
-
-	buffer = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem));
-	if (buffer)
-		digest = g_compute_checksum_for_data (
-			duplicate_csum, buffer->data, buffer->len);
-
-	g_object_unref (mem);
-
-	return digest;
-}
-
-static gboolean
-message_is_duplicated (GHashTable *messages, guint64 id, gchar *digest)
-{
-	gchar *hash_digest = g_hash_table_lookup (messages, &id);
-
-	if (!hash_digest)
-		return FALSE;
-
-	return g_str_equal (digest, hash_digest);
-}
-
 static void
-remove_duplicates_got_messages_cb (CamelFolder *folder,
-                                   GPtrArray *uids,
-                                   GPtrArray *msgs,
-                                   gpointer data)
-{
-	EMailReader *reader = data;
-	GtkWindow *parent;
-	GHashTable *messages;
-	GPtrArray *dups;
-	gint ii;
-
-	g_return_if_fail (CAMEL_IS_FOLDER (folder));
-	g_return_if_fail (uids != NULL);
-	g_return_if_fail (msgs != NULL);
-	g_return_if_fail (msgs->len <= uids->len);
-	g_return_if_fail (E_IS_MAIL_READER (reader));
-
-	parent = e_mail_reader_get_window (reader);
-
-	messages = g_hash_table_new_full (
-		g_int_hash, g_int_equal, g_free, g_free);
-	dups = g_ptr_array_new ();
-
-	for (ii = 0; ii < msgs->len; ii++) {
-		CamelMessageInfo *msg_info;
-		const CamelSummaryMessageID *mid;
-		guint32 flags;
-
-		msg_info = camel_folder_get_message_info (
-			folder, uids->pdata[ii]);
-		mid = camel_message_info_message_id (msg_info);
-		flags = camel_message_info_flags (msg_info);
-
-		if (!(flags & CAMEL_MESSAGE_DELETED)) {
-			gchar *digest;
-
-			digest = get_message_checksum (folder, msgs->pdata[ii]);
-
-			if (digest != NULL) {
-				if (message_is_duplicated (
-					messages, mid->id.id, digest)) {
-					g_ptr_array_add (dups, uids->pdata[ii]);
-					g_free (digest);
-				} else {
-					guint64 *id;
-
-					id = g_new0 (guint64, 1);
-					*id = mid->id.id;
-
-					g_hash_table_insert (
-						messages, id, digest);
-				}
-			}
-		}
-
-		camel_message_info_free (msg_info);
-	}
-
-	if (dups->len == 0) {
-		em_utils_prompt_user (
-			parent, NULL, "mail:info-no-remove-duplicates",
-			camel_folder_get_display_name (folder), NULL);
-	} else {
-		gchar *msg = g_strdup_printf (ngettext (
-			/* Translators: %s is replaced with a folder name
-			   %d with count of duplicate messages. */
-			"Folder '%s' contains %d duplicate message. "
-			"Are you sure you want to delete it?",
-			"Folder '%s' contains %d duplicate messages. "
-			"Are you sure you want to delete them?",
-			dups->len),
-			camel_folder_get_display_name (folder), dups->len);
-
-		if (em_utils_prompt_user (
-			parent, NULL, "mail:ask-remove-duplicates", msg, NULL)) {
-			camel_folder_freeze (folder);
-			for (ii = 0; ii < dups->len; ii++)
-				camel_folder_delete_message (
-					folder, g_ptr_array_index (dups, ii));
-			camel_folder_thaw (folder);
-		}
-
-		g_free (msg);
-	}
-
-	g_hash_table_destroy (messages);
-	g_ptr_array_free (dups, TRUE);
-}
-
-static void
-action_mail_remove_duplicates (GtkAction *action, EMailReader *reader)
+action_mail_remove_duplicates (GtkAction *action,
+                               EMailReader *reader)
 {
-	MessageList *message_list;
-	CamelFolder *folder;
-	GPtrArray *uids;
-
-	message_list = MESSAGE_LIST (e_mail_reader_get_message_list (reader));
-	uids = message_list_get_selected (message_list);
-	folder = message_list->folder;
-
-	if (!uids || uids->len <= 1) {
-		if (uids)
-			em_utils_uids_free (uids);
-	} else {
-		/* the function itself is freeing uids */
-		mail_get_messages (
-			folder, uids,
-			remove_duplicates_got_messages_cb, reader);
-	}
+	e_mail_reader_remove_duplicates (reader);
 }
 
 static void
diff --git a/mail/mail.error.xml b/mail/mail.error.xml
index 67b7e09..df8f5f6 100644
--- a/mail/mail.error.xml
+++ b/mail/mail.error.xml
@@ -510,5 +510,10 @@ An mbox account will be created to preserve the old mbox folders. You can delete
     <_secondary>The reported error was &quot;{0}&quot;.</_secondary>
   </error>
 
+  <error id="find-duplicate-messages" type="warning">
+    <_primary>Failed to find duplicate messages.</_primary>
+    <_secondary>The reported error was &quot;{0}&quot;.</_secondary>
+  </error>
+
 </error-list>
 



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