diff --git a/camel/camel-provider.h b/camel/camel-provider.h index 46c352c..61f917d 100644 --- a/camel/camel-provider.h +++ b/camel/camel-provider.h @@ -66,6 +66,8 @@ extern gchar *camel_provider_type_name[CAMEL_NUM_PROVIDER_TYPES]; #define CAMEL_PROVIDER_SUPPORTS_SSL (1 << 5) #define CAMEL_PROVIDER_HAS_LICENSE (1 << 6) #define CAMEL_PROVIDER_DISABLE_SENT_FOLDER (1 << 7) +#define CAMEL_PROVIDER_ALLOW_REAL_TRASH_FOLDER (1 << 8) +#define CAMEL_PROVIDER_ALLOW_REAL_JUNK_FOLDER (1 << 9) /* Flags for url_flags. "ALLOW" means the config dialog will let the diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index b2395d2..8d1d113 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -294,6 +294,14 @@ camel_imap_folder_new (CamelStore *parent, const gchar *folder_name, } else { if ((imap_store->parameters & (IMAP_PARAM_FILTER_JUNK|IMAP_PARAM_FILTER_JUNK_INBOX)) == (IMAP_PARAM_FILTER_JUNK)) folder->folder_flags |= CAMEL_FOLDER_FILTER_JUNK; + + if (!(parent->flags & CAMEL_STORE_VTRASH) && imap_store->real_trash_path && g_ascii_strcasecmp (imap_store->real_trash_path, folder->full_name) == 0) { + folder->folder_flags |= CAMEL_FOLDER_IS_TRASH; + } + + if (!(parent->flags & CAMEL_STORE_VJUNK) && imap_store->real_junk_path && g_ascii_strcasecmp (imap_store->real_junk_path, folder->full_name) == 0) { + folder->folder_flags |= CAMEL_FOLDER_IS_JUNK; + } } imap_folder->search = camel_imap_search_new(folder_dir); @@ -1635,10 +1643,28 @@ static void imap_expunge (CamelFolder *folder, CamelException *ex) { CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - GPtrArray *uids; + GPtrArray *uids = NULL; camel_folder_summary_save_to_db (folder->summary, ex); - uids = camel_db_get_folder_deleted_uids (folder->parent_store->cdb_r, folder->full_name, ex); + + if ((folder->parent_store->flags & CAMEL_STORE_VTRASH) == 0) { + CamelFolder *trash; + CamelException ex2; + + camel_exception_init (&ex2); + trash = camel_store_get_trash (folder->parent_store, &ex2); + + if (!camel_exception_is_set (&ex2) && trash && (folder == trash || g_ascii_strcasecmp (folder->full_name, trash->full_name) == 0)) { + /* it's a real trash folder, thus get all mails from there */ + uids = camel_folder_summary_array (folder->summary); + } + + camel_exception_clear (&ex2); + } + + if (!uids) + uids = camel_db_get_folder_deleted_uids (folder->parent_store->cdb_r, folder->full_name, ex); + if (!uids) return; @@ -1817,6 +1843,19 @@ imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelExceptio CAMEL_SERVICE_REC_UNLOCK (store, connect_lock); } +void +imap_expunge_uids_only (CamelFolder *folder, GPtrArray *uids, CamelException *ex) +{ + g_return_if_fail (folder != NULL); + g_return_if_fail (folder->parent_store != NULL); + g_return_if_fail (uids != NULL); + + if (CAMEL_OFFLINE_STORE (folder->parent_store)->state == CAMEL_OFFLINE_STORE_NETWORK_AVAIL) + imap_expunge_uids_resyncing (folder, uids, ex); + else + imap_expunge_uids_offline (folder, uids, ex); +} + static gchar * get_temp_uid (void) { diff --git a/camel/providers/imap/camel-imap-folder.h b/camel/providers/imap/camel-imap-folder.h index 246bc34..04130f1 100644 --- a/camel/providers/imap/camel-imap-folder.h +++ b/camel/providers/imap/camel-imap-folder.h @@ -104,6 +104,7 @@ imap_transfer_resyncing (CamelFolder *source, GPtrArray *uids, gboolean delete_originals, CamelException *ex); void imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex); +void imap_expunge_uids_only (CamelFolder *folder, GPtrArray *uids, CamelException *ex); /* Standard Camel function */ CamelType camel_imap_folder_get_type (void); diff --git a/camel/providers/imap/camel-imap-provider.c b/camel/providers/imap/camel-imap-provider.c index 6413717..5339666 100644 --- a/camel/providers/imap/camel-imap-provider.c +++ b/camel/providers/imap/camel-imap-provider.c @@ -87,7 +87,8 @@ static CamelProvider imap_provider = { "mail", CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE | - CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_SUPPORTS_SSL, + CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_SUPPORTS_SSL | + CAMEL_PROVIDER_ALLOW_REAL_TRASH_FOLDER | CAMEL_PROVIDER_ALLOW_REAL_JUNK_FOLDER, CAMEL_URL_NEED_USER | CAMEL_URL_NEED_HOST | CAMEL_URL_ALLOW_AUTH, diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index d89a4a8..49813f6 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -189,6 +189,12 @@ camel_imap_store_finalize (CamelObject *object) imap_store->namespace = NULL; g_free (imap_store->custom_headers); + + g_free (imap_store->real_trash_path); + imap_store->real_trash_path = NULL; + + g_free (imap_store->real_junk_path); + imap_store->real_junk_path = NULL; } static void @@ -284,6 +290,25 @@ construct (CamelService *service, CamelSession *session, imap_store->custom_headers = g_strdup(camel_url_get_param (url, "imap_custom_headers")); } + imap_store->real_trash_path = g_strdup (camel_url_get_param (url, "real_trash_path")); + imap_store->real_junk_path = g_strdup (camel_url_get_param (url, "real_junk_path")); + + if (imap_store->real_trash_path && !*imap_store->real_trash_path) { + g_free (imap_store->real_trash_path); + imap_store->real_trash_path = NULL; + } + + if (imap_store->real_trash_path && *imap_store->real_trash_path) + store->flags &= ~CAMEL_STORE_VTRASH; + + if (imap_store->real_junk_path && !*imap_store->real_junk_path) { + g_free (imap_store->real_junk_path); + imap_store->real_junk_path = NULL; + } + + if (imap_store->real_junk_path && *imap_store->real_junk_path) + store->flags &= ~CAMEL_STORE_VJUNK; + /* setup/load the store summary */ tmp = alloca(strlen(imap_store->storage_path)+32); sprintf(tmp, "%s/.ev-store-summary", imap_store->storage_path); @@ -1633,8 +1658,29 @@ done: static CamelFolder * imap_get_trash(CamelStore *store, CamelException *ex) { - CamelFolder *folder = CAMEL_STORE_CLASS(parent_class)->get_trash(store, ex); + CamelFolder *folder = NULL; + CamelImapStore *imap_store = (CamelImapStore *)store; + + if (imap_store->real_trash_path && *imap_store->real_trash_path) { + CamelException ex2; + + camel_exception_init (&ex2); + folder = get_folder (store, imap_store->real_trash_path, 0, &ex2); + if (!folder) { + /* cannot find configured folder, just report on console and unset in a store structure to not try again */ + g_print ("%s: Cannot open '%s': %s", G_STRFUNC, imap_store->real_trash_path, camel_exception_get_description (&ex2) ? camel_exception_get_description (&ex2) : "Unknown error."); + g_free (imap_store->real_trash_path); + imap_store->real_trash_path = NULL; + } + + camel_exception_clear (&ex2); + } + + if (folder) + return folder; + + folder = CAMEL_STORE_CLASS(parent_class)->get_trash (store, ex); if (folder) { gchar *state = g_build_filename(((CamelImapStore *)store)->storage_path, "system", "Trash.cmeta", NULL); @@ -1650,8 +1696,29 @@ imap_get_trash(CamelStore *store, CamelException *ex) static CamelFolder * imap_get_junk(CamelStore *store, CamelException *ex) { - CamelFolder *folder = CAMEL_STORE_CLASS(parent_class)->get_junk(store, ex); + CamelFolder *folder = NULL; + CamelImapStore *imap_store = (CamelImapStore *)store; + + if (imap_store->real_junk_path && *imap_store->real_junk_path) { + CamelException ex2; + + camel_exception_init (&ex2); + folder = get_folder (store, imap_store->real_junk_path, 0, &ex2); + if (!folder) { + /* cannot find configured folder, just report on console and unset in a store structure to not try again */ + g_print ("%s: Cannot open '%s': %s", G_STRFUNC, imap_store->real_junk_path, camel_exception_get_description (&ex2) ? camel_exception_get_description (&ex2) : "Unknown error."); + g_free (imap_store->real_junk_path); + imap_store->real_junk_path = NULL; + } + + camel_exception_clear (&ex2); + } + + if (folder) + return folder; + + folder = CAMEL_STORE_CLASS(parent_class)->get_junk (store, ex); if (folder) { gchar *state = g_build_filename(((CamelImapStore *)store)->storage_path, "system", "Junk.cmeta", NULL); @@ -2860,6 +2927,18 @@ get_folder_info_offline (CamelStore *store, const gchar *top, if (!g_ascii_strcasecmp(fi->full_name, "inbox")) fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_INBOX; + if ((fi->flags & CAMEL_FOLDER_TYPE_MASK) == 0 && + imap_store->real_trash_path && *imap_store->real_trash_path && + g_ascii_strcasecmp (fi->full_name, imap_store->real_trash_path) == 0) { + fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_TRASH; + } + + if ((fi->flags & CAMEL_FOLDER_TYPE_MASK) == 0 && + imap_store->real_junk_path && *imap_store->real_junk_path && + g_ascii_strcasecmp (fi->full_name, imap_store->real_junk_path) == 0) { + fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_JUNK; + } + if (si->flags & CAMEL_FOLDER_NOSELECT) { CamelURL *url = camel_url_new(fi->uri, NULL); diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index f34f9f8..56f6089 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -147,6 +147,8 @@ struct _CamelImapStore { guint32 headers; gchar *custom_headers; + + gchar *real_trash_path, *real_junk_path; }; typedef struct { diff --git a/camel/providers/imap/camel-imap-summary.c b/camel/providers/imap/camel-imap-summary.c index f95e2ff..b8933e6 100644 --- a/camel/providers/imap/camel-imap-summary.c +++ b/camel/providers/imap/camel-imap-summary.c @@ -38,6 +38,7 @@ #include "camel-store.h" #include "camel-imap-summary.h" +#include "camel-imap-folder.h" #include "camel-imap-utils.h" #define CAMEL_IMAP_SUMMARY_VERSION (3) @@ -51,6 +52,7 @@ static gint summary_header_save (CamelFolderSummary *, FILE *); static CamelMessageInfo *message_info_load (CamelFolderSummary *s, FILE *in); static gint message_info_save (CamelFolderSummary *s, FILE *out, CamelMessageInfo *info); +static gboolean info_set_flags (CamelMessageInfo *info, guint32 flags, guint32 set); static gboolean info_set_user_flag (CamelMessageInfo *info, const gchar *id, gboolean state); static CamelMessageContentInfo *content_info_load (CamelFolderSummary *s, FILE *in); static gint content_info_save (CamelFolderSummary *s, FILE *out, @@ -126,6 +128,7 @@ camel_imap_summary_class_init (CamelImapSummaryClass *klass) cfs_class->content_info_to_db = content_info_to_db; cfs_class->content_info_from_db = content_info_from_db; + cfs_class->info_set_flags = info_set_flags; cfs_class->info_set_user_flag = info_set_user_flag; } @@ -375,6 +378,140 @@ message_info_save (CamelFolderSummary *s, FILE *out, CamelMessageInfo *info) } static gboolean +check_folder_is_trash (CamelStore *store, CamelFolder *folder, CamelFolder **trash) +{ + CamelException ex; + + g_return_val_if_fail (store != NULL, FALSE); + g_return_val_if_fail (folder != NULL, FALSE); + g_return_val_if_fail (trash != NULL, FALSE); + + camel_exception_init (&ex); + *trash = camel_store_get_trash (store, &ex); + + if (camel_exception_is_set (&ex) || !*trash) { + camel_exception_clear (&ex); + return FALSE; + } + + return folder == (*trash) || g_ascii_strcasecmp (folder->full_name, (*trash)->full_name) == 0; +} + +static gboolean +check_folder_is_junk (CamelStore *store, CamelFolder *folder, CamelFolder **junk) +{ + CamelException ex; + + g_return_val_if_fail (store != NULL, FALSE); + g_return_val_if_fail (folder != NULL, FALSE); + g_return_val_if_fail (junk != NULL, FALSE); + + camel_exception_init (&ex); + *junk = camel_store_get_junk (store, &ex); + + if (camel_exception_is_set (&ex) || !*junk) { + camel_exception_clear (&ex); + return FALSE; + } + + return folder == (*junk) || g_ascii_strcasecmp (folder->full_name, (*junk)->full_name) == 0; +} + +static gboolean +transfer_message (CamelFolder *from, CamelFolder *to, const gchar *uid) +{ + GPtrArray *uids; + gboolean res; + CamelException ex; + + g_return_val_if_fail (from != NULL, FALSE); + g_return_val_if_fail (to != NULL, FALSE); + g_return_val_if_fail (from != to, FALSE); + g_return_val_if_fail (uid != NULL, FALSE); + + uids = g_ptr_array_new (); + g_ptr_array_add (uids, (gpointer)uid); + + camel_exception_init (&ex); + + /* do 'copy' to not be called with CAMEL_MESSAGE_DELETED recursively */ + camel_folder_transfer_messages_to (from, uids, to, NULL, FALSE, &ex); + + res = !camel_exception_is_set (&ex); + if (!res) + g_print ("%s: cannot transfer message: %s", G_STRFUNC, camel_exception_get_description (&ex) ? camel_exception_get_description (&ex) : "Unknown error"); + + camel_exception_clear (&ex); + g_ptr_array_free (uids, TRUE); + + return res; +} + +static void +expunge_one_message (CamelFolder *folder, const gchar *uid) +{ + GPtrArray *uids; + CamelException ex; + + g_return_if_fail (folder != NULL); + g_return_if_fail (uid != NULL); + + uids = g_ptr_array_new (); + g_ptr_array_add (uids, (gpointer)uid); + + camel_exception_init (&ex); + + imap_expunge_uids_only (folder, uids, &ex); + + if (camel_exception_is_set (&ex)) { + g_print ("%s: cannot expunge message: %s", G_STRFUNC, camel_exception_get_description (&ex) ? camel_exception_get_description (&ex) : "Unknown error"); + } + + camel_exception_clear (&ex); + g_ptr_array_free (uids, TRUE); +} + +static gboolean +info_set_flags (CamelMessageInfo *info, guint32 flags, guint32 set) +{ + CamelFolder *folder; + CamelStore *store; + gboolean res = FALSE; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (info->summary != NULL, FALSE); + + folder = (CamelFolder *) info->summary->folder; + store = folder->parent_store; + + if ((flags & set & CAMEL_MESSAGE_DELETED) != 0 && (store->flags & CAMEL_STORE_VTRASH) == 0 && (camel_message_info_flags (info) & CAMEL_MESSAGE_DELETED) == 0) { + CamelFolder *trash = NULL; + + if (check_folder_is_trash (store, folder, &trash)) { + res = CAMEL_FOLDER_SUMMARY_CLASS (camel_imap_summary_parent)->info_set_flags (info, flags, set); + expunge_one_message (trash, camel_message_info_uid (info)); + } else { + res = CAMEL_FOLDER_SUMMARY_CLASS (camel_imap_summary_parent)->info_set_flags (info, flags, set & (~CAMEL_MESSAGE_DELETED)); + if (transfer_message (folder, trash, camel_message_info_uid (info))) + expunge_one_message (folder, camel_message_info_uid (info)); + } + } else if ((flags & set & CAMEL_MESSAGE_JUNK) != 0 && (store->flags & CAMEL_STORE_VJUNK) == 0 && (camel_message_info_flags (info) & CAMEL_MESSAGE_JUNK) == 0) { + CamelFolder *junk = NULL; + + res = CAMEL_FOLDER_SUMMARY_CLASS (camel_imap_summary_parent)->info_set_flags (info, flags, set/* & (~CAMEL_MESSAGE_JUNK)*/); + + if (!check_folder_is_junk (store, folder, &junk)) { + if (transfer_message (folder, junk, camel_message_info_uid (info))) + expunge_one_message (folder, camel_message_info_uid (info)); + } + } else { + res = CAMEL_FOLDER_SUMMARY_CLASS (camel_imap_summary_parent)->info_set_flags (info, flags, set); + } + + return res; +} + +static gboolean info_set_user_flag (CamelMessageInfo *info, const gchar *id, gboolean state) { gboolean res;