diff options
-rw-r--r-- | mail/mail.error.xml | 14 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-view-actions.c | 134 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-view-actions.h | 2 | ||||
-rw-r--r-- | ui/evolution-mail.ui | 1 |
4 files changed, 151 insertions, 0 deletions
diff --git a/mail/mail.error.xml b/mail/mail.error.xml index dbbb84d04f..60e4d5670c 100644 --- a/mail/mail.error.xml +++ b/mail/mail.error.xml @@ -472,5 +472,19 @@ You can choose to ignore this folder, overwrite or append its contents, or quit. <_primary>"Report Not Junk" Failed</_primary> <secondary xml:space="preserve">{0}</secondary> </error> + + <error id="ask-remove-duplicates" type="question" default="GTK_RESPONSE_YES"> + <_primary>Remove duplicate messages?</_primary> + <secondary>{0}</secondary> + <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/> + <button stock="gtk-delete" response="GTK_RESPONSE_YES"/> + </error> + + <error id="info-no-remove-duplicates" type="info" default="GTK_RESPONSE_OK"> + <_primary>No duplicate messages found.</_primary> + <!-- Translators: {0} is replaced with a folder name --> + <_secondary>Folder '{0}' doesn't contain any duplicate message.</_secondary> + <button stock="gtk-ok" response="GTK_RESPONSE_OK"/> + </error> </error-list> diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c index b62e7c1a00..fa083bf6f2 100644 --- a/modules/mail/e-mail-shell-view-actions.c +++ b/modules/mail/e-mail-shell-view-actions.c @@ -413,6 +413,133 @@ 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) @@ -1074,6 +1201,13 @@ 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 5eb015bd47..accabc023f 100644 --- a/modules/mail/e-mail-shell-view-actions.h +++ b/modules/mail/e-mail-shell-view-actions.h @@ -85,6 +85,8 @@ 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.ui b/ui/evolution-mail.ui index d158cf862b..4589dc6b46 100644 --- a/ui/evolution-mail.ui +++ b/ui/evolution-mail.ui @@ -45,6 +45,7 @@ <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'/> |