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/mail-ops.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 161 insertions(+), 4 deletions(-) (limited to 'mail/mail-ops.c') 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); } } -- cgit v1.2.3