From 63a7f4d1ccd62b543a0b82a6d11c2d2b24ef1125 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Tue, 10 May 2011 17:27:49 -0400 Subject: 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(-) (limited to 'mail') diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c index 16964674b0..374bed0f0e 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 04b46b6257..f06d4db2d4 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 dc163bda06..ec667765e2 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 67b7e09961..df8f5f6abd 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 "{0}". + + <_primary>Failed to find duplicate messages. + <_secondary>The reported error was "{0}". + + -- cgit