[evolution] Bug #632683 - Remove-duplicates should work on selection



commit 59da2bdfdc25d148c2bc13d8fa6281f2540ba87c
Author: Milan Crha <mcrha redhat com>
Date:   Wed Nov 10 13:38:22 2010 +0100

    Bug #632683 - Remove-duplicates should work on selection

 mail/e-mail-reader.c                     |  193 +++++++++++++++++++++---------
 mail/mail-ops.c                          |  139 +++++++++++++++++++++
 mail/mail-ops.h                          |    1 +
 modules/mail/e-mail-shell-view-actions.c |  134 ---------------------
 modules/mail/e-mail-shell-view-actions.h |    2 -
 ui/evolution-mail-reader.ui              |    2 +
 ui/evolution-mail.ui                     |    1 -
 7 files changed, 278 insertions(+), 194 deletions(-)
---
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 2c1bbb2..0649a43 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -406,81 +406,144 @@ action_mail_remove_attachments_cb (GtkAction *action, EMailReader *reader)
 {
 	CamelFolder *folder;
 	GPtrArray *uids;
-	gint i, j;
 
 	folder = e_mail_reader_get_folder (reader);
 	uids = e_mail_reader_get_selected_uids (reader);
 
-	camel_folder_freeze (folder);
-	for (i = 0; i < (uids ? uids->len : 0); i++) {
-		CamelMimeMessage *message;
-		CamelDataWrapper *containee;
-		gchar *uid;
+	mail_remove_attachments (folder, uids);
+}
 
-		uid = g_ptr_array_index (uids, i);
+static gchar *
+get_message_checksum (CamelFolder *folder, CamelMimeMessage *msg)
+{
+	static const GChecksumType duplicate_csum = G_CHECKSUM_SHA256;
 
-		/* retrieve the message from the CamelFolder */
-		message = camel_folder_get_message_sync (folder, uid, NULL, NULL);
-		if (!message) {
-			continue;
-		}
+	CamelDataWrapper *content;
+	CamelStream *mem;
+	GByteArray *buffer;
+	gchar *digest = NULL;
 
-		containee = camel_medium_get_content (CAMEL_MEDIUM (message));
-		if (containee == NULL) {
-			continue;
-		}
+	if (!msg)
+		return NULL;
 
-		if (CAMEL_IS_MULTIPART (containee)) {
-			gboolean deleted = FALSE;
-			gint parts;
-
-			parts = camel_multipart_get_number (CAMEL_MULTIPART (containee));
-			for (j = 0; j < parts; j++) {
-				CamelMimePart *mpart = camel_multipart_get_part (CAMEL_MULTIPART (containee), j);
-				const gchar *disposition = camel_mime_part_get_disposition (mpart);
-				if (disposition && (!strcmp (disposition, "attachment") || !strcmp (disposition, "inline"))) {
-					gchar *desc;
-					const gchar *filename;
-
-					filename = camel_mime_part_get_filename (mpart);
-					desc = g_strdup_printf (_("File \"%s\" has been removed."), filename ? filename : "");
-					camel_mime_part_set_disposition (mpart, "inline");
-					camel_mime_part_set_content (mpart, desc, strlen (desc), "text/plain");
-					camel_mime_part_set_content_type (mpart, "text/plain");
-					deleted = TRUE;
-				}
-			}
+	/* get message contents */
+	content = camel_medium_get_content ((CamelMedium *) msg);
+	if (!content)
+		return NULL;
 
-			if (deleted) {
-				/* copy the original message with the deleted attachment */
-				CamelMessageInfo *info, *newinfo;
-				guint32 flags;
-				GError *error = NULL;
+	/* calculate checksum */
+	mem = camel_stream_mem_new ();
+	camel_data_wrapper_decode_to_stream_sync (content, mem, NULL, NULL);
 
-				info = camel_folder_get_message_info (folder, uid);
-				newinfo = camel_message_info_new_from_header (NULL, CAMEL_MIME_PART (message)->headers);
-				flags = camel_folder_get_message_flags (folder, uid);
+	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);
 
-				/* make a copy of the message */
-				camel_message_info_set_flags (newinfo, flags, flags);
-				camel_folder_append_message_sync (folder, message, newinfo, NULL, NULL, &error);
+	g_object_unref (mem);
 
-				if (!error) {
-					/* marked the original message deleted */
-					camel_message_info_set_flags (info, CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED);
-				}
+	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 (folder != NULL);
+	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 (reader != NULL);
+	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 = camel_folder_get_message_info (folder, uids->pdata[ii]);
+		const CamelSummaryMessageID *mid = camel_message_info_message_id (msg_info);
+		guint32 flags = camel_message_info_flags (msg_info);
 
-				camel_folder_free_message_info (folder, info);
-				camel_message_info_free (newinfo);
+		if (!(flags & CAMEL_MESSAGE_DELETED)) {
+			gchar *digest = get_message_checksum (folder, msgs->pdata[ii]);
 
-				if (error)
-					g_error_free (error);
+			if (digest) {
+				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);
 	}
 
-	camel_folder_synchronize_sync (folder, FALSE, NULL, NULL);
-	camel_folder_thaw (folder);
+	if (dups->len == 0) {
+		em_utils_prompt_user (parent, NULL, "mail:info-no-remove-duplicates", camel_folder_get_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_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)
+{
+	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);
+	}
 }
 
 static void
@@ -2107,6 +2170,13 @@ static GtkActionEntry mail_reader_entries[] = {
 	  N_("Remove attachments"),
 	  G_CALLBACK (action_mail_remove_attachments_cb) },
 
+	{ "mail-remove-duplicates",
+	   NULL,
+	   N_("Remove Du_plicate Messages"),
+	   NULL,
+	   N_("Checks selected messages for duplicates"),
+	   G_CALLBACK (action_mail_remove_duplicates) },
+
 	{ "mail-reply-all",
 	  NULL,
 	  N_("Reply to _All"),
@@ -2330,6 +2400,10 @@ static EPopupActionEntry mail_reader_popup_entries[] = {
 	  NULL,
 	  "mail-remove-attachments" },
 
+	{ "mail-popup-remove-duplicates",
+	  NULL,
+	  "mail-remove-duplicates" },
+
 	{ "mail-popup-reply-all",
 	  NULL,
 	  "mail-reply-all" },
@@ -3165,6 +3239,11 @@ mail_reader_update_actions (EMailReader *reader,
 	action = e_mail_reader_get_action (reader, action_name);
 	gtk_action_set_sensitive (action, sensitive);
 
+	action_name = "mail-remove-duplicates";
+	sensitive = multiple_messages_selected;
+	action = e_mail_reader_get_action (reader, action_name);
+	gtk_action_set_sensitive (action, sensitive);
+
 	action_name = "mail-reply-all";
 	sensitive = have_enabled_account && single_message_selected;
 	action = e_mail_reader_get_action (reader, action_name);
diff --git a/mail/mail-ops.c b/mail/mail-ops.c
index 24826af..28cd77a 100644
--- a/mail/mail-ops.c
+++ b/mail/mail-ops.c
@@ -2599,3 +2599,142 @@ mail_disconnect_store (CamelStore *store)
 
 	return id;
 }
+
+/* ---------------------------------------------------------------------------------- */
+
+struct _remove_attachments_msg {
+	MailMsg base;
+
+	CamelFolder *folder;
+	GPtrArray *uids;
+};
+
+static gchar *
+remove_attachments_desc (struct _remove_attachments_msg *m)
+{
+	return g_strdup_printf (_("Removing attachments"));
+}
+
+static void
+remove_attachments_exec (struct _remove_attachments_msg *m,
+                    GCancellable *cancellable,
+                    GError **error)
+{
+	CamelFolder *folder = m->folder;
+	GPtrArray *uids = m->uids;
+	gint ii, jj;
+
+	camel_folder_freeze (folder);
+	for (ii = 0; ii < (uids ? uids->len : 0); ii++) {
+		gint pc = ((ii + 1) * 100) / uids->len;
+		CamelMimeMessage *message;
+		CamelDataWrapper *containee;
+		gchar *uid;
+
+		uid = g_ptr_array_index (uids, ii);
+
+		/* retrieve the message from the CamelFolder */
+		message = camel_folder_get_message_sync (folder, uid, cancellable, NULL);
+		if (!message) {
+			camel_operation_progress (cancellable, pc);
+			continue;
+		}
+
+		containee = camel_medium_get_content (CAMEL_MEDIUM (message));
+		if (containee == NULL) {
+			camel_operation_progress (cancellable, pc);
+			continue;
+		}
+
+		if (CAMEL_IS_MULTIPART (containee)) {
+			gboolean deleted = FALSE;
+			gint parts;
+
+			parts = camel_multipart_get_number (CAMEL_MULTIPART (containee));
+			for (jj = 0; jj < parts; jj++) {
+				CamelMimePart *mpart = camel_multipart_get_part (CAMEL_MULTIPART (containee), jj);
+				const gchar *disposition = camel_mime_part_get_disposition (mpart);
+				if (disposition && (!strcmp (disposition, "attachment") || !strcmp (disposition, "inline"))) {
+					gchar *desc;
+					const gchar *filename;
+
+					filename = camel_mime_part_get_filename (mpart);
+					desc = g_strdup_printf (_("File \"%s\" has been removed."), filename ? filename : "");
+					camel_mime_part_set_disposition (mpart, "inline");
+					camel_mime_part_set_content (mpart, desc, strlen (desc), "text/plain");
+					camel_mime_part_set_content_type (mpart, "text/plain");
+					deleted = TRUE;
+				}
+			}
+
+			if (deleted) {
+				/* copy the original message with the deleted attachment */
+				CamelMessageInfo *info, *newinfo;
+				guint32 flags;
+				GError *local_error = NULL;
+
+				info = camel_folder_get_message_info (folder, uid);
+				newinfo = camel_message_info_new_from_header (NULL, CAMEL_MIME_PART (message)->headers);
+				flags = camel_folder_get_message_flags (folder, uid);
+
+				/* make a copy of the message */
+				camel_message_info_set_flags (newinfo, flags, flags);
+				camel_folder_append_message_sync (folder, message, newinfo, NULL, cancellable, &local_error);
+
+				if (!local_error) {
+					/* marked the original message deleted */
+					camel_message_info_set_flags (info, CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED);
+				}
+
+				camel_folder_free_message_info (folder, info);
+				camel_message_info_free (newinfo);
+
+				if (local_error) {
+					g_propagate_error (error, local_error);
+					break;
+				}
+			}
+		}
+
+		camel_operation_progress (cancellable, pc);
+	}
+
+	if (!error || !*error)
+		camel_folder_synchronize_sync (folder, FALSE, cancellable, error);
+	camel_folder_thaw (folder);
+}
+
+static void
+remove_attachments_free (struct _remove_attachments_msg *m)
+{
+	g_object_unref (m->folder);
+	em_utils_uids_free (m->uids);
+}
+
+static MailMsgInfo remove_attachments_info = {
+	sizeof (struct _remove_attachments_msg),
+	(MailMsgDescFunc) remove_attachments_desc,
+	(MailMsgExecFunc) remove_attachments_exec,
+	(MailMsgDoneFunc) NULL,
+	(MailMsgFreeFunc) remove_attachments_free
+};
+
+/* it takes ownership of 'uids' array */
+gint
+mail_remove_attachments (CamelFolder *folder, GPtrArray *uids)
+{
+	struct _remove_attachments_msg *m;
+	gint id;
+
+	g_return_val_if_fail (folder != NULL, -1);
+	g_return_val_if_fail (uids != NULL, -1);
+
+	m = mail_msg_new (&remove_attachments_info);
+	m->folder = g_object_ref (folder);
+	m->uids = uids;
+
+	id = m->base.seq;
+	mail_msg_unordered_push (m);
+
+	return id;
+}
diff --git a/mail/mail-ops.h b/mail/mail-ops.h
index 77ce991..98f9125 100644
--- a/mail/mail-ops.h
+++ b/mail/mail-ops.h
@@ -164,6 +164,7 @@ gint		mail_check_service		(EMailSession *session,
 						 gpointer data);
 
 gint mail_disconnect_store (CamelStore *store);
+gint mail_remove_attachments (CamelFolder *folder, GPtrArray *uids);
 
 G_END_DECLS
 
diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c
index 0c82778..b2c5b8d 100644
--- a/modules/mail/e-mail-shell-view-actions.c
+++ b/modules/mail/e-mail-shell-view-actions.c
@@ -447,133 +447,6 @@ action_mail_folder_rename_cb (GtkAction *action,
 	em_folder_tree_edit_selected (folder_tree);
 }
 
-static gchar *
-get_message_checksum (CamelFolder *folder, const gchar *uid)
-{
-	static const GChecksumType duplicate_csum = G_CHECKSUM_SHA256;
-
-	CamelMimeMessage *msg;
-	GError *error = NULL;
-	CamelDataWrapper *content;
-	CamelStream *mem;
-	GByteArray *buffer;
-	gchar *digest = NULL;
-
-	msg = camel_folder_get_message_sync (folder, uid, NULL, &error);
-
-	if (error || !msg) {
-		if (error)
-			g_error_free (error);;
-		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);
-	g_object_unref (msg);
-
-	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
-action_mail_folder_remove_duplicates (GtkAction *action, EMailShellView *mail_shell_view)
-{
-	EShellView *shell_view;
-	EShellContent *shell_content;
-	GtkWindow *parent;
-	EMailReader *reader;
-	MessageList *message_list;
-	CamelFolder *folder;
-	GHashTable *messages;
-	GPtrArray *uids, *dups;
-	gint i;
-
-	shell_view = E_SHELL_VIEW (mail_shell_view);
-	shell_content = e_shell_view_get_shell_content (shell_view);
-	parent = GTK_WINDOW (e_shell_view_get_shell_window (shell_view));
-
-	reader = E_MAIL_READER (shell_content);
-	message_list = MESSAGE_LIST (e_mail_reader_get_message_list (reader));
-	uids = message_list_get_uids (message_list);
-	folder = message_list->folder;
-
-	messages = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, g_free);
-	dups = g_ptr_array_new ();
-
-	for (i = 0; i < uids->len; i++) {
-		CamelMessageInfo *msg_info = camel_folder_get_message_info (folder, uids->pdata[i]);
-		const CamelSummaryMessageID *mid = camel_message_info_message_id (msg_info);
-		guint32 flags = camel_message_info_flags (msg_info);
-
-		if (!(flags & CAMEL_MESSAGE_DELETED)) {
-			gchar *digest = get_message_checksum (folder, uids->pdata[i]);
-
-			if (digest) {
-				if (message_is_duplicated (messages, mid->id.id, digest)) {
-					g_ptr_array_add (dups, uids->pdata[i]);
-					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_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_name (folder), dups->len);
-
-		if (em_utils_prompt_user (parent, NULL, "mail:ask-remove-duplicates", msg, NULL)) {
-			gint ii;
-
-			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);
-	em_utils_uids_free (uids);
-	g_ptr_array_free (dups, TRUE);
-}
-
 static void
 action_mail_folder_select_thread_cb (GtkAction *action,
                                      EMailShellView *mail_shell_view)
@@ -1249,13 +1122,6 @@ static GtkActionEntry mail_entries[] = {
 	  N_("Change the name of this folder"),
 	  G_CALLBACK (action_mail_folder_rename_cb) },
 
-	{ "mail-folder-remove-duplicates",
-	   NULL,
-	   N_("Remo_ve Duplicate Messages"),
-	   "",
-	   N_("Remove all duplicate messages"),
-	   G_CALLBACK (action_mail_folder_remove_duplicates) },
-
 	{ "mail-folder-select-thread",
 	  NULL,
 	  N_("Select Message _Thread"),
diff --git a/modules/mail/e-mail-shell-view-actions.h b/modules/mail/e-mail-shell-view-actions.h
index accabc0..5eb015b 100644
--- a/modules/mail/e-mail-shell-view-actions.h
+++ b/modules/mail/e-mail-shell-view-actions.h
@@ -85,8 +85,6 @@
 	E_SHELL_WINDOW_ACTION ((window), "mail-folder-rename")
 #define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_ALL(window) \
 	E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-all")
-#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_REMOVE_DUPLICATES(window) \
-	E_SHELL_WINDOW_ACTION ((window), "mail-folder-remove-duplicates")
 #define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_THREAD(window) \
 	E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-thread")
 #define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_SUBTHREAD(window) \
diff --git a/ui/evolution-mail-reader.ui b/ui/evolution-mail-reader.ui
index 7120147..ffc16a9 100644
--- a/ui/evolution-mail-reader.ui
+++ b/ui/evolution-mail-reader.ui
@@ -97,6 +97,7 @@
         <menuitem action='mail-filters-apply'/>
         <menuitem action='mail-check-for-junk'/>
 	<menuitem action='mail-remove-attachments'/>
+        <menuitem action='mail-remove-duplicates'/>
         <separator/>
         <menu action='mail-create-rule-menu'>
           <menuitem action='mail-filter-on-subject'/>
@@ -159,6 +160,7 @@
       <menuitem action='mail-popup-save-as'/>
       <menuitem action='mail-popup-print'/>
       <menuitem action='mail-popup-remove-attachments'/>
+      <menuitem action='mail-popup-remove-duplicates'/>
     </placeholder>
   </popup>
   <popup name='mail-preview-popup'>
diff --git a/ui/evolution-mail.ui b/ui/evolution-mail.ui
index 4589dc6..d158cf8 100644
--- a/ui/evolution-mail.ui
+++ b/ui/evolution-mail.ui
@@ -45,7 +45,6 @@
         <menuitem action='mail-folder-select-thread'/>
         <menuitem action='mail-folder-select-subthread'/>
         <menuitem action='mail-folder-mark-all-as-read'/>
-        <menuitem action='mail-folder-remove-duplicates'/>
         <menuitem action='mail-folder-expunge'/>
         <separator/>
         <menuitem action='mail-folder-rename'/>



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