From d6d0d1050aa72fd757eec127cba605844584dc11 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Wed, 27 Oct 2010 10:06:57 +0200 Subject: Bug #445439 - Delete mail from pop-server when deleted from Inbox/Trash --- mail/em-utils.c | 5 +- mail/em-utils.h | 2 +- mail/mail-ops.c | 165 ++++++++++++++++++++++++++++++- mail/mail-ops.h | 2 +- modules/mail/e-mail-shell-view-actions.c | 2 +- 5 files changed, 167 insertions(+), 9 deletions(-) diff --git a/mail/em-utils.c b/mail/em-utils.c index 06b1713628..779e1a79e0 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -1337,12 +1337,13 @@ em_utils_message_to_html (CamelMimeMessage *message, /** * em_utils_expunge_folder: * @parent: parent window + * @session: #EMailSession * @folder: folder to expunge * * Expunges @folder. **/ void -em_utils_expunge_folder (GtkWidget *parent, CamelFolder *folder) +em_utils_expunge_folder (GtkWidget *parent, EMailSession *session, CamelFolder *folder) { const gchar *description; @@ -1354,7 +1355,7 @@ em_utils_expunge_folder (GtkWidget *parent, CamelFolder *folder) "mail:ask-expunge", description, NULL)) return; - mail_expunge_folder (folder, NULL, NULL); + mail_expunge_folder (session, folder, NULL, NULL); } /** diff --git a/mail/em-utils.h b/mail/em-utils.h index 2229d26653..698ff3f0e6 100644 --- a/mail/em-utils.h +++ b/mail/em-utils.h @@ -72,7 +72,7 @@ gchar *em_utils_get_proxy_uri (const gchar *uri); /* FIXME: should this have an override charset? */ gchar *em_utils_message_to_html (CamelMimeMessage *msg, const gchar *credits, guint32 flags, gssize *len, struct _EMFormat *source, const gchar *append, guint32 *validity_found); -void em_utils_expunge_folder (GtkWidget *parent, CamelFolder *folder); +void em_utils_expunge_folder (GtkWidget *parent, EMailSession *session, CamelFolder *folder); void em_utils_empty_trash (GtkWidget *parent, EMailSession *session); /* returns the folder name portion of an URI */ diff --git a/mail/mail-ops.c b/mail/mail-ops.c index d10473606b..88e327bbf4 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -1659,6 +1659,7 @@ mail_remove_folder (CamelFolder *folder, void (*done) (CamelFolder *folder, gboo struct _sync_folder_msg { MailMsg base; + EMailSession *session; CamelFolder *folder; void (*done) (CamelFolder *folder, gpointer data); gpointer data; @@ -1690,7 +1691,10 @@ sync_folder_done (struct _sync_folder_msg *m) static void sync_folder_free (struct _sync_folder_msg *m) { - g_object_unref ((CamelObject *)m->folder); + g_object_unref (m->folder); + + if (m->session) + g_object_unref (m->session); } static MailMsgInfo sync_folder_info = { @@ -1829,6 +1833,130 @@ mail_refresh_folder (CamelFolder *folder, void (*done) (CamelFolder *folder, gpo /* ******************************************************************************** */ +static gboolean +folder_is_from_source_url (CamelFolder *folder, const gchar *source_url) +{ + CamelStore *store; + CamelService *service; + CamelURL *url; + gboolean res = FALSE; + + g_return_val_if_fail (folder != NULL, FALSE); + g_return_val_if_fail (source_url != NULL, FALSE); + + store = camel_folder_get_parent_store (folder); + g_return_val_if_fail (store != NULL, FALSE); + + service = CAMEL_SERVICE (store); + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (service->provider != NULL, FALSE); + g_return_val_if_fail (service->provider->url_equal != NULL, FALSE); + + url = camel_url_new (source_url, NULL); + g_return_val_if_fail (url != NULL, FALSE); + + res = service->provider->url_equal (service->url, url); + + camel_url_free (url); + + return res; +} + +/* This is because pop3 accounts are hidden under local Inbox, thus whenever an expunge + is done on a local trash or Inbox, then also all active pop3 accounts should be expunged. */ +static void +expunge_pop3_stores (CamelFolder *expunging, EMailSession *session, GCancellable *cancellable, GError **error) +{ + GPtrArray *uids; + CamelFolder *folder; + EAccount *account; + EIterator *iter; + guint i; + GHashTable *expunging_uids = NULL; + + uids = camel_folder_get_uids (expunging); + if (!uids) + return; + + for (i = 0; i < uids->len; i++) { + CamelMessageInfo *info = camel_folder_get_message_info (expunging, uids->pdata[i]); + + if (!info) + continue; + + if ((camel_message_info_flags (info) & CAMEL_MESSAGE_DELETED) != 0) { + CamelMimeMessage *msg; + GError *local_error = NULL; + + /* because the UID in the local store doesn't match with the UID in the pop3 store */ + msg = camel_folder_get_message_sync (expunging, uids->pdata[i], cancellable, &local_error); + if (msg) { + const gchar *pop3_uid; + + pop3_uid = camel_medium_get_header (CAMEL_MEDIUM (msg), "X-Evolution-POP3-UID"); + if (pop3_uid) { + gchar *duped = g_strstrip (g_strdup (pop3_uid)); + + if (!expunging_uids) + expunging_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + g_hash_table_insert (expunging_uids, duped, g_strdup (camel_mime_message_get_source (msg))); + } + + g_object_unref (msg); + } + + if (local_error) + g_clear_error (&local_error); + } + + camel_folder_free_message_info (expunging, info); + } + + camel_folder_free_uids (expunging, uids); + uids = NULL; + + if (!expunging_uids) + return; + + for (iter = e_list_get_iterator ((EList *)e_get_account_list ()); + e_iterator_is_valid (iter) && (!error || !*error); + e_iterator_next (iter)) { + account = (EAccount *) e_iterator_get (iter); + + if (account->enabled && account->source && account->source->url && g_str_has_prefix (account->source->url, "pop://")) { + gboolean any_found = FALSE; + + folder = e_mail_session_get_inbox_sync (session, account->source->url, cancellable, error); + if (!folder || (error && *error)) + continue; + + uids = camel_folder_get_uids (folder); + if (uids) { + for (i = 0; i < uids->len; i++) { + /* ensure the ID is from this account, as it's generated by evolution */ + const gchar *source_url = g_hash_table_lookup (expunging_uids, uids->pdata[i]); + if (source_url && folder_is_from_source_url (folder, source_url)) { + any_found = TRUE; + camel_folder_delete_message (folder, uids->pdata[i]); + } + } + camel_folder_free_uids (folder, uids); + } + + if (any_found) + camel_folder_synchronize_sync (folder, TRUE, cancellable, error); + + g_object_unref (folder); + } + } + + if (iter) + g_object_unref (iter); + + g_hash_table_destroy (expunging_uids); +} + static gchar * expunge_folder_desc (struct _sync_folder_msg *m) { @@ -1840,7 +1968,30 @@ expunge_folder_exec (struct _sync_folder_msg *m, GCancellable *cancellable, GError **error) { - camel_folder_expunge_sync (m->folder, cancellable, error); + gboolean is_local_inbox_or_trash = m->folder == e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_INBOX); + + if (!is_local_inbox_or_trash && e_mail_local_get_store () == camel_folder_get_parent_store (m->folder)) { + const gchar *data_dir; + CamelFolder *trash; + gchar *uri; + + data_dir = mail_session_get_data_dir (); + uri = g_strdup_printf ("mbox:%s/local", data_dir); + trash = e_mail_session_get_trash_sync ( + m->session, uri, cancellable, error); + g_free (uri); + + is_local_inbox_or_trash = m->folder == trash; + + g_object_unref (trash); + } + + /* do this before expunge, to know which messages will be expunged */ + if (is_local_inbox_or_trash && (!error || !*error)) + expunge_pop3_stores (m->folder, m->session, cancellable, error); + + if (!error || !*error) + camel_folder_expunge_sync (m->folder, cancellable, error); } /* we just use the sync stuff where we can, since it would be the same */ @@ -1853,11 +2004,12 @@ static MailMsgInfo expunge_folder_info = { }; void -mail_expunge_folder (CamelFolder *folder, void (*done) (CamelFolder *folder, gpointer data), gpointer data) +mail_expunge_folder (EMailSession *session, CamelFolder *folder, void (*done) (CamelFolder *folder, gpointer data), gpointer data) { struct _sync_folder_msg *m; m = mail_msg_new (&expunge_folder_info); + m->session = g_object_ref (session); m->folder = folder; g_object_ref (folder); m->data = data; @@ -1906,7 +2058,12 @@ empty_trash_exec (struct _empty_trash_msg *m, } if (trash) { - camel_folder_expunge_sync (trash, cancellable, error); + /* do this before expunge, to know which messages will be expunged */ + if (!m->account && (!error || !*error)) + expunge_pop3_stores (trash, m->session, cancellable, error); + + if (!error || !*error) + camel_folder_expunge_sync (trash, cancellable, error); g_object_unref (trash); } } diff --git a/mail/mail-ops.h b/mail/mail-ops.h index ea9e9f7d0b..fbcf6bf826 100644 --- a/mail/mail-ops.h +++ b/mail/mail-ops.h @@ -99,7 +99,7 @@ void mail_refresh_folder (CamelFolder *folder, void (*done) (CamelFolder *folder, gpointer data), gpointer data); -void mail_expunge_folder (CamelFolder *folder, +void mail_expunge_folder (EMailSession *session, CamelFolder *folder, void (*done) (CamelFolder *folder, gpointer data), gpointer data); diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c index d323992440..467afa5ff9 100644 --- a/modules/mail/e-mail-shell-view-actions.c +++ b/modules/mail/e-mail-shell-view-actions.c @@ -247,7 +247,7 @@ action_mail_folder_expunge_cb (GtkAction *action, folder = em_folder_tree_get_selected_folder (folder_tree); g_return_if_fail (folder != NULL); - em_utils_expunge_folder (GTK_WIDGET (shell_window), folder); + em_utils_expunge_folder (GTK_WIDGET (shell_window), e_mail_backend_get_session (E_MAIL_BACKEND (e_shell_view_get_shell_backend (shell_view))), folder); } static void -- cgit