Commit df6f8dc0 authored by Milan Crha's avatar Milan Crha

Bug #587011 - Integrate remove-duplicates into evolution

parent b277e14a
......@@ -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 id="ask-remove-duplicates" type="question" default="GTK_RESPONSE_YES">
<_primary>Remove duplicate messages?</_primary>
<button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
<button stock="gtk-delete" response="GTK_RESPONSE_YES"/>
<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"/>
......@@ -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->, digest)) {
g_ptr_array_add (dups, uids->pdata[i]);
g_free (digest);
} else {
guint64 *id;
id = g_new0 (guint64, 1);
*id = mid->;
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?"),
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",
N_("Remo_ve duplicate messages"),
N_("Remove all duplicate messages"),
G_CALLBACK (action_mail_folder_remove_duplicates) },
{ "mail-folder-select-thread",
N_("Select Message _Thread"),
......@@ -85,6 +85,8 @@
E_SHELL_WINDOW_ACTION ((window), "mail-folder-rename")
E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-all")
E_SHELL_WINDOW_ACTION ((window), "mail-folder-remove-duplicates")
E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-thread")
......@@ -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'/>
<menuitem action='mail-folder-rename'/>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment