diff -up evolution-data-server-3.8.5/camel/camel-folder-summary.c.imapx-message-flags evolution-data-server-3.8.5/camel/camel-folder-summary.c --- evolution-data-server-3.8.5/camel/camel-folder-summary.c.imapx-message-flags 2013-08-02 16:56:47.000000000 +0200 +++ evolution-data-server-3.8.5/camel/camel-folder-summary.c 2014-01-30 12:01:15.998935449 +0100 @@ -2011,12 +2011,29 @@ perform_content_info_load_from_db (Camel } static void -append_changed_uids (gchar *key, - CamelMessageInfoBase *info, - GPtrArray *array) +gather_dirty_uids (gpointer key, + gpointer value, + gpointer user_data) { - if (info->dirty || info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) - g_ptr_array_add (array, (gpointer) camel_pstring_strdup ((camel_message_info_uid (info)))); + const gchar *uid = key; + CamelMessageInfoBase *info = value; + GHashTable *hash = user_data; + + if (info->dirty) + g_hash_table_insert (hash, (gpointer) camel_pstring_strdup (uid), GINT_TO_POINTER (1)); +} + +static void +gather_changed_uids (gpointer key, + gpointer value, + gpointer user_data) +{ + const gchar *uid = key; + guint32 flags = GPOINTER_TO_UINT (value); + GHashTable *hash = user_data; + + if ((flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0) + g_hash_table_insert (hash, (gpointer) camel_pstring_strdup (uid), GINT_TO_POINTER (1)); } /** @@ -2027,16 +2044,21 @@ append_changed_uids (gchar *key, GPtrArray * camel_folder_summary_get_changed (CamelFolderSummary *summary) { - GPtrArray *res = g_ptr_array_new (); - - /* FIXME[disk-summary] sucks, this function returns from memory. - * We need to have collate or something to get the modified ones - * from DB and merge */ + GPtrArray *res; + GHashTable *hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) camel_pstring_free, NULL); camel_folder_summary_lock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK); - g_hash_table_foreach (summary->priv->loaded_infos, (GHFunc) append_changed_uids, res); + + g_hash_table_foreach (summary->priv->loaded_infos, gather_dirty_uids, hash); + g_hash_table_foreach (summary->priv->uids, gather_changed_uids, hash); + + res = g_ptr_array_sized_new (g_hash_table_size (hash)); + g_hash_table_foreach (hash, folder_summary_dupe_uids_to_array, res); + camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK); + g_hash_table_destroy (hash); + return res; } diff -up evolution-data-server-3.8.5/camel/camel-imapx-server.c.imapx-message-flags evolution-data-server-3.8.5/camel/camel-imapx-server.c --- evolution-data-server-3.8.5/camel/camel-imapx-server.c.imapx-message-flags 2014-01-30 12:01:15.989935450 +0100 +++ evolution-data-server-3.8.5/camel/camel-imapx-server.c 2014-01-30 12:02:29.616932482 +0100 @@ -6898,7 +6898,12 @@ imapx_parser_thread (gpointer d) GError *local_error = NULL; QUEUE_LOCK (is); - cancellable = camel_operation_new (); + /* Do not use CamelOperation here, because it can be cancelled at + an application end with camel_operation_cancel_all() call, which + is done too early, before any pending jobs are properly finished + (it can be IDLE job, or save of folder changes back to the server). + */ + cancellable = g_cancellable_new (); is->cancellable = g_object_ref (cancellable); QUEUE_UNLOCK (is); @@ -7715,6 +7720,40 @@ imapx_sync_free_user (GArray *user_set) g_array_free (user_set, TRUE); } +static void +imapx_unset_folder_flagged_flag (CamelFolderSummary *summary, + GPtrArray *changed_uids) +{ + CamelMessageInfo *info; + gboolean changed = FALSE; + gint ii; + + g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary)); + g_return_if_fail (changed_uids != NULL); + + for (ii = 0; ii < changed_uids->len; ii++) { + info = camel_folder_summary_get (summary, changed_uids->pdata[ii]); + + if (info) { + CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info; + + /* some infos could be only 'dirty' (needed to save into summary) */ + if ((mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0) { + mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; + mi->dirty = TRUE; + changed = TRUE; + } + + camel_message_info_free (info); + } + } + + if (changed) { + camel_folder_summary_touch (summary); + camel_folder_summary_save_to_db (summary, NULL); + } +} + static gboolean imapx_server_sync_changes (CamelIMAPXServer *is, CamelFolder *folder, @@ -7873,6 +7912,7 @@ imapx_server_sync_changes (CamelIMAPXSer if (nothing_to_do) { imapx_sync_free_user (on_user); imapx_sync_free_user (off_user); + imapx_unset_folder_flagged_flag (folder->summary, changed_uids); camel_folder_free_uids (folder, changed_uids); return TRUE; } diff -up evolution-data-server-3.8.5/camel/camel-imapx-utils.c.imapx-message-flags evolution-data-server-3.8.5/camel/camel-imapx-utils.c --- evolution-data-server-3.8.5/camel/camel-imapx-utils.c.imapx-message-flags 2014-01-30 12:01:15.996935450 +0100 +++ evolution-data-server-3.8.5/camel/camel-imapx-utils.c 2014-01-30 12:01:15.999935449 +0100 @@ -257,6 +257,15 @@ imapx_update_message_info_flags (CamelMe gboolean changed = FALSE; CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) info; + /* This makes sure that server flags has precedence from locally stored flags, + thus a user actually sees what is stored on the server, but only if the message + was not changed locally and is ready to be saved */ + if (!(camel_message_info_flags (info) & CAMEL_MESSAGE_FOLDER_FLAGGED) && + (camel_message_info_flags (info) & CAMEL_IMAPX_SERVER_FLAGS) != (server_flags & CAMEL_IMAPX_SERVER_FLAGS)) { + xinfo->server_flags = (xinfo->server_flags & ~CAMEL_IMAPX_SERVER_FLAGS) | + (camel_message_info_flags (info) & CAMEL_IMAPX_SERVER_FLAGS); + } + if (server_flags != xinfo->server_flags) { guint32 server_set, server_cleared;