aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap/camel-imap-folder.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/imap/camel-imap-folder.c')
-rw-r--r--camel/providers/imap/camel-imap-folder.c483
1 files changed, 427 insertions, 56 deletions
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index b8e53c604a..abced473f6 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -46,21 +46,22 @@
#include "camel-imap-summary.h"
#include "camel-imap-utils.h"
#include "camel-imap-wrapper.h"
-#include "string-utils.h"
-#include "camel-session.h"
-#include "camel-stream.h"
-#include "camel-stream-mem.h"
-#include "camel-stream-buffer.h"
#include "camel-data-wrapper.h"
-#include "camel-mime-message.h"
-#include "camel-stream-filter.h"
-#include "camel-mime-filter-from.h"
-#include "camel-mime-filter-crlf.h"
+#include "camel-disco-diary.h"
#include "camel-exception.h"
-#include "camel-mime-utils.h"
#include "camel-imap-private.h"
+#include "camel-mime-filter-crlf.h"
+#include "camel-mime-filter-from.h"
+#include "camel-mime-message.h"
+#include "camel-mime-utils.h"
#include "camel-multipart.h"
#include "camel-operation.h"
+#include "camel-session.h"
+#include "camel-stream-buffer.h"
+#include "camel-stream-filter.h"
+#include "camel-stream-mem.h"
+#include "camel-stream.h"
+#include "string-utils.h"
#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o)))
static CamelDiscoFolderClass *disco_folder_class = NULL;
@@ -73,19 +74,25 @@ static void imap_sync_offline (CamelFolder *folder, CamelException *ex);
static const char *imap_get_full_name (CamelFolder *folder);
static void imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *ex);
static void imap_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex);
+static void imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex);
static void imap_cache_message (CamelDiscoFolder *disco_folder, const char *uid, CamelException *ex);
/* message manipulation */
static CamelMimeMessage *imap_get_message (CamelFolder *folder, const gchar *uid,
CamelException *ex);
-static char *imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
+static void imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
const CamelMessageInfo *info, CamelException *ex);
-static char *imap_append_offline (CamelFolder *folder, CamelMimeMessage *message,
+static void imap_append_offline (CamelFolder *folder, CamelMimeMessage *message,
const CamelMessageInfo *info, CamelException *ex);
+static void imap_append_resyncing (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, CamelException *ex);
+
static void imap_copy_online (CamelFolder *source, GPtrArray *uids,
CamelFolder *destination, CamelException *ex);
static void imap_copy_offline (CamelFolder *source, GPtrArray *uids,
CamelFolder *destination, CamelException *ex);
+static void imap_copy_resyncing (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *destination, CamelException *ex);
static void imap_move_messages_to (CamelFolder *source, GPtrArray *uids,
CamelFolder *destination, CamelException *ex);
@@ -113,12 +120,19 @@ camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class)
camel_disco_folder_class->refresh_info_online = imap_refresh_info;
camel_disco_folder_class->sync_online = imap_sync_online;
camel_disco_folder_class->sync_offline = imap_sync_offline;
+ /* We don't sync flags at resync time: the online code will
+ * deal with it eventually.
+ */
+ camel_disco_folder_class->sync_resyncing = imap_sync_offline;
camel_disco_folder_class->expunge_uids_online = imap_expunge_uids_online;
camel_disco_folder_class->expunge_uids_offline = imap_expunge_uids_offline;
+ camel_disco_folder_class->expunge_uids_resyncing = imap_expunge_uids_resyncing;
camel_disco_folder_class->append_online = imap_append_online;
camel_disco_folder_class->append_offline = imap_append_offline;
+ camel_disco_folder_class->append_resyncing = imap_append_resyncing;
camel_disco_folder_class->copy_online = imap_copy_online;
camel_disco_folder_class->copy_offline = imap_copy_offline;
+ camel_disco_folder_class->copy_resyncing = imap_copy_resyncing;
camel_disco_folder_class->cache_message = imap_cache_message;
}
@@ -247,6 +261,17 @@ camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response,
}
}
+ if (camel_disco_store_status (CAMEL_DISCO_STORE (folder->parent_store)) == CAMEL_DISCO_STORE_RESYNCING) {
+ if (validity != imap_summary->validity) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_SUMMARY_INVALID,
+ _("Folder was destroyed and recreated on server."));
+ return;
+ }
+
+ /* FIXME: find missing UIDs ? */
+ return;
+ }
+
if (!imap_summary->validity)
imap_summary->validity = validity;
else if (validity != imap_summary->validity) {
@@ -414,8 +439,11 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
}
/* If we find a UID in the summary that doesn't correspond to
- * the UID in the folder, that it means the message was
- * deleted on the server, so we remove it from the summary.
+ * the UID in the folder, then either: (a) it's a real UID,
+ * but the message was deleted on the server, or (b) it's a
+ * fake UID, and needs to be removed from the summary in order
+ * to sync up with the server. So either way, we remove it
+ * from the summary.
*/
removed = g_array_new (FALSE, FALSE, sizeof (int));
summary_len = camel_folder_summary_count (folder->summary);
@@ -432,6 +460,7 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
iinfo = (CamelImapMessageInfo *)info;
if (strcmp (camel_message_info_uid (info), new[i].uid) != 0) {
+ camel_folder_summary_info_free(folder->summary, info);
seq = i + 1;
g_array_append_val (removed, seq);
i--;
@@ -609,8 +638,18 @@ imap_sync_online (CamelFolder *folder, CamelException *ex)
static void
imap_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
{
- /* Fail */
- camel_disco_store_check_online (CAMEL_DISCO_STORE (folder->parent_store), ex);
+ int i;
+
+ for (i = 0; i < uids->len; i++) {
+ camel_folder_summary_remove_uid (folder->summary, uids->pdata[i]);
+ /* We intentionally don't remove it from the cache because
+ * the cached data may be useful in replaying a COPY later.
+ */
+ }
+ camel_folder_summary_save (folder->summary);
+
+ camel_disco_diary_log (CAMEL_DISCO_STORE (folder->parent_store)->diary,
+ CAMEL_DISCO_DIARY_FOLDER_EXPUNGE, folder, uids);
}
static void
@@ -643,6 +682,148 @@ imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *
CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
}
+static int
+uid_compar (const void *va, const void *vb)
+{
+ const char **sa = (const char **)va, **sb = (const char **)vb;
+ unsigned long a, b;
+
+ a = strtoul (*sa, NULL, 10);
+ b = strtoul (*sb, NULL, 10);
+ if (a < b)
+ return -1;
+ else if (a == b)
+ return 0;
+ else
+ return 1;
+}
+
+static void
+imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
+ char *result, *keep_uidset, *mark_uidset;
+
+ if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) {
+ imap_expunge_uids_online (folder, uids, ex);
+ return;
+ }
+
+ /* If we don't have UID EXPUNGE we need to avoid expunging any
+ * of the wrong messages. So we search for deleted messages,
+ * and any that aren't in our to-expunge list get temporarily
+ * marked un-deleted.
+ */
+
+ CAMEL_IMAP_STORE_LOCK (store, command_lock);
+ response = camel_imap_command (store, folder, ex, "UID SEARCH DELETED");
+ if (!response) {
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ return;
+ }
+ result = camel_imap_response_extract (store, response, "SEARCH", ex);
+ if (!result) {
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ return;
+ }
+
+ keep_uidset = mark_uidset = NULL;
+ if (result[8] == ' ') {
+ GPtrArray *keep_uids, *mark_uids;
+ char *uid, *lasts = NULL;
+ unsigned long euid, kuid;
+ int ei, ki;
+
+ keep_uids = g_ptr_array_new ();
+ mark_uids = g_ptr_array_new ();
+
+ /* Parse SEARCH response */
+ for (uid = strtok_r (result + 9, " ", &lasts); uid; uid = strtok_r (NULL, " ", &lasts))
+ g_ptr_array_add (keep_uids, uid);
+ qsort (keep_uids->pdata, keep_uids->len,
+ sizeof (void *), uid_compar);
+
+ /* Fill in "mark_uids", empty out "keep_uids" as needed */
+ for (ei = ki = 0; ei < uids->len; ei++) {
+ euid = strtoul (uids->pdata[ei], NULL, 10);
+
+ for (; ki < keep_uids->len; ki++) {
+ kuid = strtoul (keep_uids->pdata[ki], NULL, 10);
+
+ if (kuid >= euid)
+ break;
+ }
+
+ if (euid == kuid)
+ g_ptr_array_remove_index (keep_uids, ki);
+ else
+ g_ptr_array_add (mark_uids, uids->pdata[ei]);
+ }
+
+ if (keep_uids->len)
+ keep_uidset = imap_uid_array_to_set (folder->summary, keep_uids);
+ g_ptr_array_free (keep_uids, TRUE);
+
+ if (mark_uids->len)
+ mark_uidset = imap_uid_array_to_set (folder->summary, mark_uids);
+ g_ptr_array_free (mark_uids, TRUE);
+ } else {
+ /* Empty SEARCH result, meaning nothing is marked deleted
+ * on server.
+ */
+ mark_uidset = imap_uid_array_to_set (folder->summary, uids);
+ }
+ g_free (result);
+
+ /* Unmark messages to be kept */
+ if (keep_uidset) {
+ response = camel_imap_command (store, folder, ex,
+ "UID STORE %s -FLAGS.SILENT \\Deleted",
+ keep_uidset);
+ if (!response) {
+ g_free (keep_uidset);
+ g_free (mark_uidset);
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ return;
+ }
+ camel_imap_response_free (store, response);
+ }
+
+ /* Mark any messages that still need to be marked */
+ if (mark_uidset) {
+ response = camel_imap_command (store, folder, ex,
+ "UID STORE %s +FLAGS.SILENT \\Deleted",
+ mark_uidset);
+ g_free (mark_uidset);
+ if (!response) {
+ g_free (keep_uidset);
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ return;
+ }
+ camel_imap_response_free (store, response);
+ }
+
+ /* Do the actual expunging */
+ response = camel_imap_command (store, folder, ex, "EXPUNGE");
+ if (response)
+ camel_imap_response_free (store, response);
+
+ /* And fix the remaining messages if we mangled them */
+ if (keep_uidset) {
+ /* Don't pass ex if it's already been set */
+ response = camel_imap_command (store, folder,
+ camel_exception_is_set (ex) ? NULL : ex,
+ "UID STORE %s +FLAGS.SILENT \\Deleted",
+ keep_uidset);
+ g_free (keep_uidset);
+ if (response)
+ camel_imap_response_free (store, response);
+ }
+
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+}
+
static const char *
imap_get_full_name (CamelFolder *folder)
{
@@ -662,18 +843,39 @@ imap_get_full_name (CamelFolder *folder)
return name;
}
-static char *
+static void
imap_append_offline (CamelFolder *folder, CamelMimeMessage *message,
const CamelMessageInfo *info, CamelException *ex)
{
- /* Fail */
- camel_disco_store_check_online (CAMEL_DISCO_STORE (folder->parent_store), ex);
- return NULL;
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapMessageCache *cache = CAMEL_IMAP_FOLDER (folder)->cache;
+ CamelFolderChangeInfo *changes;
+ char *uid;
+
+ /* We could keep a separate counter, but this one works fine. */
+ CAMEL_IMAP_STORE_LOCK (imap_store, command_lock);
+ uid = g_strdup_printf ("append-%d", imap_store->command++);
+ CAMEL_IMAP_STORE_UNLOCK (imap_store, command_lock);
+
+ camel_imap_summary_add_offline (folder->summary, uid, message, info);
+ camel_imap_message_cache_insert_wrapper (cache, uid, "",
+ CAMEL_DATA_WRAPPER (message));
+
+ changes = camel_folder_change_info_new ();
+ camel_folder_change_info_add_uid (changes, uid);
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed",
+ changes);
+ camel_folder_change_info_free (changes);
+
+ camel_disco_diary_log (CAMEL_DISCO_STORE (imap_store)->diary,
+ CAMEL_DISCO_DIARY_FOLDER_APPEND, folder, uid);
+ g_free (uid);
}
-static char *
-imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
- const CamelMessageInfo *info, CamelException *ex)
+static CamelImapResponse *
+do_append (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **uid,
+ CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
CamelImapResponse *response;
@@ -681,7 +883,7 @@ imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
CamelMimeFilter *crlf_filter;
CamelStreamFilter *streamfilter;
GByteArray *ba;
- char *flagstr, *result, *uid = NULL;
+ char *flagstr, *result, *end;
/* create flag string param */
if (info && info->flags)
@@ -725,39 +927,133 @@ imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
g_byte_array_append (ba, "\0", 3);
response = camel_imap_command_continuation (store, ex, ba->data);
g_byte_array_free (ba, TRUE);
- if (!response)
- return NULL;
if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) {
- uid = strstrcase (response->status, "[APPENDUID ");
- if (uid)
- uid = strchr (uid + 11, ' ');
- if (uid)
- uid = g_strndup (uid + 1, strcspn (uid + 1, "]"));
- if (uid) {
- /* Make sure it's a number */
- if (strtoul (uid, &result, 10) != 0 && !*result) {
- /* OK. Cache the data. */
- camel_imap_message_cache_insert_wrapper (
- CAMEL_IMAP_FOLDER (folder)->cache,
- uid, "", CAMEL_DATA_WRAPPER (message));
- } else {
- g_free (uid);
- uid = NULL;
+ *uid = strstrcase (response->status, "[APPENDUID ");
+ if (*uid)
+ *uid = strchr (*uid + 11, ' ');
+ if (*uid) {
+ *uid = g_strndup (*uid + 1, strcspn (*uid + 1, "]"));
+ /* Make sure it's a number */
+ if (strtoul (*uid, &end, 10) == 0 || *end) {
+ g_free (*uid);
+ *uid = NULL;
}
}
+ } else
+ *uid = NULL;
+
+ return response;
+}
+
+static void
+imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
+ char *uid;
+
+ response = do_append (folder, message, info, &uid, ex);
+ if (!response)
+ return;
+
+ if (uid) {
+ /* Cache first, since freeing response may trigger a
+ * summary update that will want this information.
+ */
+ camel_imap_message_cache_insert_wrapper (
+ CAMEL_IMAP_FOLDER (folder)->cache,
+ uid, "", CAMEL_DATA_WRAPPER (message));
+ g_free (uid);
+ }
+
+ camel_imap_response_free (store, response);
+}
+
+static void
+imap_append_resyncing (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
+ char *uid;
+
+ response = do_append (folder, message, info, &uid, ex);
+ if (!response)
+ return;
+
+ if (uid) {
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ const char *olduid = camel_message_info_uid (info);
+
+ CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+ camel_imap_message_cache_copy (imap_folder->cache, olduid,
+ imap_folder->cache, uid);
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+
+ camel_disco_diary_uidmap_add (CAMEL_DISCO_STORE (store)->diary,
+ olduid, uid);
}
camel_imap_response_free (store, response);
- return uid;
}
+
static void
imap_copy_offline (CamelFolder *source, GPtrArray *uids,
CamelFolder *destination, CamelException *ex)
{
- /* Fail */
- camel_disco_store_check_online (CAMEL_DISCO_STORE (source->parent_store), ex);
+ CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
+ CamelImapMessageCache *sc = CAMEL_IMAP_FOLDER (source)->cache;
+ CamelImapMessageCache *dc = CAMEL_IMAP_FOLDER (destination)->cache;
+ CamelFolderChangeInfo *changes;
+ CamelMimeMessage *message;
+ CamelMessageInfo *mi;
+ char *uid, *destuid;
+ int i;
+
+ /* We grab the store's command lock first, and then grab the
+ * source and destination cache_locks. This way we can't
+ * deadlock in the case where we're simultaneously also trying
+ * to copy messages in the other direction from another thread.
+ */
+ CAMEL_IMAP_STORE_LOCK (store, command_lock);
+ CAMEL_IMAP_FOLDER_LOCK (source, cache_lock);
+ CAMEL_IMAP_FOLDER_LOCK (destination, cache_lock);
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+
+ changes = camel_folder_change_info_new ();
+ for (i = 0; i < uids->len; i++) {
+ uid = uids->pdata[i];
+
+ message = camel_folder_get_message (source, uid, NULL);
+ if (!message)
+ continue;
+ mi = camel_folder_summary_uid (source->summary, uid);
+ g_return_if_fail (mi != NULL);
+
+ destuid = g_strdup_printf ("copy-%s:%s", source->full_name, uid);
+ camel_imap_summary_add_offline (destination->summary, destuid, message, mi);
+
+ camel_imap_message_cache_copy (sc, uid, dc, destuid);
+ camel_folder_summary_info_free (source->summary, mi);
+ camel_object_unref (CAMEL_OBJECT (message));
+
+ camel_folder_change_info_add_uid (changes, destuid);
+ g_free (destuid);
+ }
+
+ CAMEL_IMAP_FOLDER_UNLOCK (destination, cache_lock);
+ CAMEL_IMAP_FOLDER_UNLOCK (source, cache_lock);
+
+ camel_object_trigger_event (CAMEL_OBJECT (destination),
+ "folder_changed", changes);
+ camel_folder_change_info_free (changes);
+
+ camel_disco_diary_log (CAMEL_DISCO_STORE (store)->diary,
+ CAMEL_DISCO_DIARY_FOLDER_COPY,
+ source, destination, uids);
}
static void
@@ -814,19 +1110,13 @@ handle_copyuid (CamelImapResponse *response, CamelFolder *source,
}
static void
-imap_copy_online (CamelFolder *source, GPtrArray *uids,
- CamelFolder *destination, CamelException *ex)
+do_copy (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *destination, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
CamelImapResponse *response;
char *set;
-
- /* Sync message flags if needed. */
- imap_sync_online (source, ex);
- if (camel_exception_is_set (ex))
- return;
-
- /* Now copy the messages */
+
set = imap_uid_array_to_set (source->summary, uids);
response = camel_imap_command (store, source, ex, "UID COPY %s %S",
set, destination->full_name);
@@ -835,16 +1125,95 @@ imap_copy_online (CamelFolder *source, GPtrArray *uids,
camel_imap_response_free (store, response);
g_free (set);
-
+}
+
+static void
+imap_copy_online (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *destination, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
+ CamelImapResponse *response;
+
+ /* Sync message flags if needed. */
+ imap_sync_online (source, ex);
if (camel_exception_is_set (ex))
return;
-
+
+ /* Now copy the messages */
+ do_copy (source, uids, destination, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
/* Force the destination folder to notice its new messages. */
response = camel_imap_command (store, destination, NULL, "NOOP");
camel_imap_response_free (store, response);
}
static void
+imap_copy_resyncing (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *destination, CamelException *ex)
+{
+ CamelDiscoDiary *diary = CAMEL_DISCO_STORE (source->parent_store)->diary;
+ GPtrArray *realuids;
+ int first, i;
+ const char *uid;
+ CamelMimeMessage *message;
+ CamelMessageInfo *info;
+
+ /* This is trickier than append_resyncing, because some of
+ * the messages we are copying may have been copied or
+ * appended into @source while we were offline, in which case
+ * if we don't have UIDPLUS, we won't know their real UIDs,
+ * so we'll have to append them rather than copying.
+ */
+
+ realuids = g_ptr_array_new ();
+
+ i = 0;
+ while (i < uids->len) {
+ /* Skip past real UIDs */
+ for (first = i; i < uids->len; i++) {
+ uid = uids->pdata[i];
+
+ if (!isdigit ((unsigned char)*uid)) {
+ uid = camel_disco_diary_uidmap_lookup (diary, uid);
+ if (!uid)
+ break;
+ }
+ g_ptr_array_add (realuids, (char *)uid);
+ }
+
+ /* If we saw any real UIDs, do a COPY */
+ if (i != first) {
+ do_copy (source, realuids, destination, ex);
+ g_ptr_array_set_size (realuids, 0);
+ if (i == uids->len || camel_exception_is_set (ex))
+ break;
+ }
+
+ /* Deal with fake UIDs */
+ while (i < uids->len &&
+ !isdigit (*(unsigned char *)(uids->pdata[i])) &&
+ !camel_exception_is_set (ex)) {
+ message = camel_folder_get_message (source, uids->pdata[i], NULL);
+ if (!message) {
+ /* Message must have been expunged */
+ continue;
+ }
+ info = camel_folder_get_message_info (source, uids->pdata[i]);
+ g_return_if_fail (info != NULL);
+
+ imap_append_online (destination, message, info, ex);
+ camel_folder_free_message_info (source, info);
+ camel_object_unref (CAMEL_OBJECT (message));
+ i++;
+ }
+ }
+
+ g_ptr_array_free (realuids, FALSE);
+}
+
+static void
imap_move_messages_to (CamelFolder *source, GPtrArray *uids,
CamelFolder *destination, CamelException *ex)
{
@@ -1288,10 +1657,12 @@ camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid,
CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
stream = camel_imap_message_cache_get (imap_folder->cache, uid, section_text);
+ if (!stream && (!strcmp (section_text, "HEADER") || !strcmp (section_text, "0")))
+ stream = camel_imap_message_cache_get (imap_folder->cache, uid, "");
if (stream || cache_only) {
CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
return stream;
- }
+ }
if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) {
camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,