[evolution-ews/gnome-3-20] Bug 764976 - Failed message move processed as successful



commit b3e211ea907899476a062470e78b26311d232a17
Author: Milan Crha <mcrha redhat com>
Date:   Thu Apr 14 14:26:17 2016 +0200

    Bug 764976 - Failed message move processed as successful

 src/camel/camel-ews-folder.c  |   53 +++++++++++++++++++++---------
 src/server/e-ews-connection.c |   72 +++++++++++++++++++++++++++++++++++++++++
 src/server/e-ews-connection.h |    9 +++++
 3 files changed, 118 insertions(+), 16 deletions(-)
---
diff --git a/src/camel/camel-ews-folder.c b/src/camel/camel-ews-folder.c
index 9c9d528..c1a2ce2 100644
--- a/src/camel/camel-ews-folder.c
+++ b/src/camel/camel-ews-folder.c
@@ -1166,7 +1166,7 @@ ews_move_to_junk_folder (CamelFolder *folder,
                folder_id = camel_ews_store_summary_get_folder_id_from_folder_type (
                        ews_store->summary, CAMEL_FOLDER_TYPE_JUNK);
 
-               status = e_ews_connection_move_items_sync (
+               status = e_ews_connection_move_items_in_chunks_sync (
                        cnc, EWS_PRIORITY_MEDIUM, folder_id, FALSE,
                        junk_uids, &moved_items, cancellable, &local_error);
 
@@ -1178,17 +1178,20 @@ ews_move_to_junk_folder (CamelFolder *folder,
                        status = ews_refresh_info_sync (folder, cancellable, &local_error);
                }
 
-               g_slist_free_full (moved_items, g_object_unref);
-               g_free (folder_id);
-
-               if (status) {
+               /* Messages could be moved partially only, like when
+                  the user cancels the operation in the middle */
+               if (status || moved_items) {
                        CamelFolderChangeInfo *changes;
-                       const GSList *iter;
+                       const GSList *iter, *items_iter;
 
                        changes = camel_folder_change_info_new ();
 
-                       for (iter = junk_uids; iter; iter = g_slist_next (iter)) {
+                       for (iter = junk_uids, items_iter = moved_items; iter && items_iter; iter = 
g_slist_next (iter), items_iter = g_slist_next (items_iter)) {
                                const gchar *uid = iter->data;
+                               EEwsItem *item = items_iter->data;
+
+                               if (!item || e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR)
+                                       continue;
 
                                camel_folder_summary_lock (folder->summary);
 
@@ -1206,6 +1209,9 @@ ews_move_to_junk_folder (CamelFolder *folder,
                        camel_folder_change_info_free (changes);
                }
 
+               g_slist_free_full (moved_items, g_object_unref);
+               g_free (folder_id);
+
                if (local_error) {
                        camel_ews_store_maybe_disconnect (ews_store, local_error);
                        g_propagate_error (error, local_error);
@@ -2047,13 +2053,17 @@ ews_transfer_messages_to_sync (CamelFolder *source,
 
        ids = g_slist_reverse (ids);
 
-       if (success && e_ews_connection_move_items_sync (
+       success = success && e_ews_connection_move_items_in_chunks_sync (
                cnc, EWS_PRIORITY_MEDIUM,
                dst_id, !delete_originals,
                ids, &ret_items,
-               cancellable, &local_error)) {
+               cancellable, &local_error);
+
+       /* Messages could be copied/moved partially only, like when
+          the user cancels the operation in the middle */
+       if (success || ret_items) {
                CamelFolderChangeInfo *changes;
-               GSList *l;
+               GSList *l, *processed_items = NULL;
 
                changes = camel_folder_change_info_new ();
 
@@ -2064,10 +2074,14 @@ ews_transfer_messages_to_sync (CamelFolder *source,
                        CamelMessageInfo *clone;
                        const EwsId *id;
 
-                       if (e_ews_item_get_item_type (l->data) == E_EWS_ITEM_TYPE_ERROR)
+                       if (e_ews_item_get_item_type (l->data) == E_EWS_ITEM_TYPE_ERROR) {
+                               if (!local_error)
+                                       local_error = g_error_copy (e_ews_item_get_error (l->data));
                                continue;
+                       }
 
                        id = e_ews_item_get_id (l->data);
+                       processed_items = g_slist_prepend (processed_items, uids->pdata[i]);
 
                        message = ews_folder_get_message_cached (source, uids->pdata[i], cancellable);
                        if (message == NULL)
@@ -2111,10 +2125,12 @@ ews_transfer_messages_to_sync (CamelFolder *source,
                if (delete_originals) {
                        changes = camel_folder_change_info_new ();
 
-                       for (i = 0; i < uids->len; i++) {
-                               camel_folder_summary_remove_uid (source->summary, uids->pdata[i]);
-                               camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
-                               ews_data_cache_remove (CAMEL_EWS_FOLDER (source)->cache, "cur", 
uids->pdata[i], NULL);
+                       for (l = processed_items; l; l = g_slist_next (l)) {
+                               const gchar *uid = l->data;
+
+                               camel_folder_summary_remove_uid (source->summary, uid);
+                               camel_folder_change_info_remove_uid (changes, uid);
+                               ews_data_cache_remove (CAMEL_EWS_FOLDER (source)->cache, "cur", uid, NULL);
                        }
                        if (camel_folder_change_info_changed (changes)) {
                                camel_folder_summary_touch (source->summary);
@@ -2127,8 +2143,13 @@ ews_transfer_messages_to_sync (CamelFolder *source,
                /* update destination folder only if not frozen, to not update
                   for each single message transfer during filtering
                 */
-               if (!camel_folder_is_frozen (destination))
+               if (!camel_folder_is_frozen (destination)) {
+                       camel_operation_progress (cancellable, -1);
+
                        ews_refresh_info_sync (destination, cancellable, NULL);
+               }
+
+               g_slist_free (processed_items);
        }
        g_free (dst_id);
 
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index 76befcf..550bc10 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -57,6 +57,9 @@
 /* For the number of connections */
 #define EWS_CONNECTION_MAX_REQUESTS 1
 
+/* A chunk size limit when moving items in chunks. */
+#define EWS_MOVE_ITEMS_CHUNK_SIZE 500
+
 #define QUEUE_LOCK(x) (g_rec_mutex_lock(&(x)->priv->queue_lock))
 #define QUEUE_UNLOCK(x) (g_rec_mutex_unlock(&(x)->priv->queue_lock))
 
@@ -6214,6 +6217,75 @@ e_ews_connection_move_items_sync (EEwsConnection *cnc,
        return success;
 }
 
+gboolean
+e_ews_connection_move_items_in_chunks_sync (EEwsConnection *cnc,
+                                           gint pri,
+                                           const gchar *folder_id,
+                                           gboolean docopy,
+                                           const GSList *ids,
+                                           GSList **items,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       const GSList *iter;
+       guint total_ids = 0, done_ids = 0;
+       gboolean success = TRUE;
+
+       g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (items != NULL, FALSE);
+
+       g_object_ref (cnc);
+
+       *items = NULL;
+       iter = ids;
+
+       while (success && iter) {
+               guint n_ids;
+               const GSList *tmp_iter;
+               GSList *processed_items = NULL;
+
+               for (tmp_iter = iter, n_ids = 0; tmp_iter && n_ids < EWS_MOVE_ITEMS_CHUNK_SIZE; tmp_iter = 
g_slist_next (tmp_iter), n_ids++) {
+                       /* Only check bounds first, to avoid unnecessary allocations */
+               }
+
+               if (tmp_iter) {
+                       GSList *shorter = NULL;
+
+                       if (total_ids == 0)
+                               total_ids = g_slist_length ((GSList *) ids);
+
+                       for (n_ids = 0; iter && n_ids < EWS_MOVE_ITEMS_CHUNK_SIZE; iter = g_slist_next 
(iter), n_ids++) {
+                               shorter = g_slist_prepend (shorter, iter->data);
+                       }
+
+                       shorter = g_slist_reverse (shorter);
+
+                       success = e_ews_connection_move_items_sync (cnc, pri, folder_id, docopy,
+                               shorter, &processed_items, cancellable, error);
+
+                       g_slist_free (shorter);
+
+                       done_ids += n_ids;
+               } else {
+                       success = e_ews_connection_move_items_sync (cnc, pri, folder_id, docopy,
+                               iter, &processed_items, cancellable, error);
+
+                       iter = NULL;
+                       done_ids = total_ids;
+               }
+
+               if (processed_items)
+                       *items = g_slist_concat (*items, processed_items);
+
+               if (total_ids > 0)
+                       camel_operation_progress (cancellable, 100 * (gdouble) done_ids / (gdouble) 
total_ids);
+       }
+
+       g_object_unref (cnc);
+
+       return success;
+}
+
 static void
 delete_folder_response_cb (ESoapResponse *response,
                            GSimpleAsyncResult *simple)
diff --git a/src/server/e-ews-connection.h b/src/server/e-ews-connection.h
index c759856..f46bb54 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -908,6 +908,15 @@ gboolean   e_ews_connection_move_items_sync
                                                 GSList **items_ret,
                                                 GCancellable *cancellable,
                                                 GError **error);
+gboolean       e_ews_connection_move_items_in_chunks_sync
+                                               (EEwsConnection *cnc,
+                                                gint pri,
+                                                const gchar *folder_id,
+                                                gboolean docopy,
+                                                const GSList *ids,
+                                                GSList **items,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
 void           e_ews_connection_create_attachments
                                                (EEwsConnection *cnc,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]