[evolution-ews] Bug 764976 - Failed message move processed as successful



commit d88d6b39711762e1e1d5de178407d7807906d299
Author: Milan Crha <mcrha redhat com>
Date:   Thu Apr 14 14:18:23 2016 +0200

    Bug 764976 - Failed message move processed as successful

 src/camel/camel-ews-folder.c  |   57 +++++++++++++++++++++++---------
 src/server/e-ews-connection.c |   72 +++++++++++++++++++++++++++++++++++++++++
 src/server/e-ews-connection.h |    9 +++++
 3 files changed, 122 insertions(+), 16 deletions(-)
---
diff --git a/src/camel/camel-ews-folder.c b/src/camel/camel-ews-folder.c
index 9c82222..5b770ea 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);
@@ -1801,6 +1807,8 @@ ews_refresh_info_sync (CamelFolder *folder,
        id = camel_ews_store_summary_get_folder_id_from_name (
                ews_store->summary, full_name);
 
+       camel_operation_push_message (cancellable, _("Refreshing folder '%s'"), camel_folder_get_display_name 
(folder));
+
        /* Sync folder items does not return the fields ToRecipients,
         * CCRecipients. With the item_type unknown, its not possible
         * to fetch the right properties which are valid for an item type.
@@ -1877,6 +1885,8 @@ ews_refresh_info_sync (CamelFolder *folder,
                }
        } while (!local_error && !includes_last_item && !g_cancellable_is_cancelled (cancellable));
 
+       camel_operation_pop_message (cancellable);
+
        if (camel_folder_change_info_changed (change_info)) {
                camel_folder_summary_touch (folder->summary);
                camel_folder_summary_save_to_db (folder->summary, NULL);
@@ -2046,13 +2056,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 ();
 
@@ -2063,10 +2077,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)
@@ -2110,10 +2128,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);
@@ -2126,8 +2146,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 3c11a3e..41116ca 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))
 
@@ -6229,6 +6232,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]