From c021214d752ea181fa026274faefee7ef7d66e91 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 10 Sep 2018 17:44:17 +0200 Subject: [PATCH] I#122 - Avoid delayed message send when editing the Outbox message Closes https://gitlab.gnome.org/GNOME/evolution/issues/122 --- src/libemail-engine/e-mail-session.c | 10 ++-- src/libemail-engine/mail-ops.c | 47 +++++++++++++++--- src/libemail-engine/mail-ops.h | 3 ++ src/mail/em-composer-utils.c | 74 +++++++++++++++++++++++----- 4 files changed, 110 insertions(+), 24 deletions(-) diff --git a/src/libemail-engine/e-mail-session.c b/src/libemail-engine/e-mail-session.c index 65c3420b2e..9dd93cea63 100644 --- a/src/libemail-engine/e-mail-session.c +++ b/src/libemail-engine/e-mail-session.c @@ -2568,13 +2568,11 @@ e_mail_session_schedule_outbox_flush (EMailSession *session, } g_mutex_lock (&session->priv->preparing_flush_lock); - if (session->priv->outbox_flush_id > 0) { - g_source_remove (session->priv->outbox_flush_id); - session->priv->outbox_flush_id = 0; + if (!session->priv->outbox_flush_id) { + /* Do not reschedule the timer, it will be rescheduled + when needed after the flush attempt */ + session->priv->outbox_flush_id = e_named_timeout_add_seconds (60 * delay_minutes, mail_session_flush_outbox_timeout_cb, session); } - - session->priv->outbox_flush_id = e_named_timeout_add_seconds (60 * delay_minutes, mail_session_flush_outbox_timeout_cb, session); - g_mutex_unlock (&session->priv->preparing_flush_lock); } diff --git a/src/libemail-engine/mail-ops.c b/src/libemail-engine/mail-ops.c index a1716bf7c8..28101e5e85 100644 --- a/src/libemail-engine/mail-ops.c +++ b/src/libemail-engine/mail-ops.c @@ -908,6 +908,27 @@ exit: /* ** SEND MAIL QUEUE ***************************************************** */ +static void +maybe_schedule_next_flush (EMailSession *session, + time_t nearest_next_flush) +{ + gint delay_seconds, delay_minutes; + + if (!session || nearest_next_flush <= 0) + return; + + delay_seconds = nearest_next_flush - time (NULL); + if (delay_seconds <= 0) + delay_seconds = 1; + + delay_minutes = delay_seconds / 60 + ((delay_seconds % 60) > 0 ? 1 : 0); + + if (!delay_minutes) + delay_minutes = 1; + + e_mail_session_schedule_outbox_flush (session, delay_minutes); +} + static void report_status (struct _send_queue_msg *m, enum camel_filter_status_t status, @@ -934,8 +955,8 @@ send_queue_exec (struct _send_queue_msg *m, { CamelFolder *sent_folder; GPtrArray *uids, *send_uids = NULL; - gint i, j; - time_t delay_send = 0; + gint i, j, delay_flush = 0; + time_t delay_send = 0, nearest_next_flush = 0; GError *local_error = NULL; d (printf ("sending queue\n")); @@ -945,7 +966,7 @@ send_queue_exec (struct _send_queue_msg *m, settings = e_util_ref_settings ("org.gnome.evolution.mail"); if (g_settings_get_boolean (settings, "composer-use-outbox")) { - gint delay_flush = g_settings_get_int (settings, "composer-delay-outbox-flush"); + delay_flush = g_settings_get_int (settings, "composer-delay-outbox-flush"); if (delay_flush > 0) delay_send = time (NULL) - (60 * delay_flush); @@ -966,15 +987,27 @@ send_queue_exec (struct _send_queue_msg *m, info = camel_folder_get_message_info (m->queue, uids->pdata[i]); if (info) { - if ((camel_message_info_get_flags (info) & CAMEL_MESSAGE_DELETED) == 0 && - (!delay_send || camel_message_info_get_date_sent (info) <= delay_send)) - send_uids->pdata[j++] = uids->pdata[i]; + if (!(camel_message_info_get_flags (info) & CAMEL_MESSAGE_DELETED)) { + gboolean is_editing = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (info), MAIL_USER_KEY_EDITING)) != 0; + + if (!delay_send || (!is_editing && camel_message_info_get_date_sent (info) <= delay_send)) { + send_uids->pdata[j++] = uids->pdata[i]; + } else if (!is_editing && (!nearest_next_flush || nearest_next_flush > camel_message_info_get_date_sent (info))) { + nearest_next_flush = camel_message_info_get_date_sent (info); + } + } + g_clear_object (&info); } } + if (nearest_next_flush > 0) + nearest_next_flush += (delay_flush * 60); + send_uids->len = j; if (send_uids->len == 0) { + maybe_schedule_next_flush (m->session, nearest_next_flush); + /* nothing to send */ camel_folder_free_uids (m->queue, uids); g_ptr_array_free (send_uids, TRUE); @@ -1077,6 +1110,8 @@ send_queue_exec (struct _send_queue_msg *m, camel_folder_synchronize_sync (sent_folder, FALSE, NULL, NULL); camel_operation_pop_message (cancellable); + + maybe_schedule_next_flush (m->session, nearest_next_flush); } static void diff --git a/src/libemail-engine/mail-ops.h b/src/libemail-engine/mail-ops.h index 7d7c744d5c..eafa8899e3 100644 --- a/src/libemail-engine/mail-ops.h +++ b/src/libemail-engine/mail-ops.h @@ -33,6 +33,9 @@ G_BEGIN_DECLS #include #include +/* Used to "tag" messages as being edited */ +#define MAIL_USER_KEY_EDITING "mail-user-key-editing" + void mail_transfer_messages (EMailSession *session, CamelFolder *source, GPtrArray *uids, diff --git a/src/mail/em-composer-utils.c b/src/mail/em-composer-utils.c index 7ffd82125b..19318299db 100644 --- a/src/mail/em-composer-utils.c +++ b/src/mail/em-composer-utils.c @@ -1173,6 +1173,26 @@ em_utils_composer_save_to_drafts_cb (EMsgComposer *composer, g_free (identity_uid); } +static void +emcu_manage_flush_outbox (EMailSession *session) +{ + GSettings *settings; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + + settings = e_util_ref_settings ("org.gnome.evolution.mail"); + if (g_settings_get_boolean (settings, "composer-use-outbox")) { + gint delay_flush = g_settings_get_int (settings, "composer-delay-outbox-flush"); + + if (delay_flush == 0) { + e_mail_session_flush_outbox (session); + } else if (delay_flush > 0) { + e_mail_session_schedule_outbox_flush (session, delay_flush); + } + } + g_object_unref (settings); +} + static void composer_save_to_outbox_completed (GObject *source_object, GAsyncResult *result, @@ -1183,7 +1203,6 @@ composer_save_to_outbox_completed (GObject *source_object, EAlertSink *alert_sink; GCancellable *cancellable; AsyncContext *async_context; - GSettings *settings; GError *local_error = NULL; session = E_MAIL_SESSION (source_object); @@ -1224,17 +1243,7 @@ composer_save_to_outbox_completed (GObject *source_object, G_OBJECT (activity), (GWeakNotify) gtk_widget_destroy, async_context->composer); - settings = e_util_ref_settings ("org.gnome.evolution.mail"); - if (g_settings_get_boolean (settings, "composer-use-outbox")) { - gint delay_flush = g_settings_get_int (settings, "composer-delay-outbox-flush"); - - if (delay_flush == 0) { - e_mail_session_flush_outbox (session); - } else if (delay_flush > 0) { - e_mail_session_schedule_outbox_flush (session, delay_flush); - } - } - g_object_unref (settings); + emcu_manage_flush_outbox (session); exit: async_context_free (async_context); @@ -2108,6 +2117,31 @@ emcu_message_references_existing_account (CamelMimeMessage *message, return res; } +typedef struct _OutboxData { + CamelSession *session; + CamelMessageInfo *info; +} OutboxData; + +static void +outbox_data_free (gpointer ptr) +{ + OutboxData *od = ptr; + + if (od) { + if (od->info) { + g_object_set_data (G_OBJECT (od->info), MAIL_USER_KEY_EDITING, NULL); + + if (od->session && !(camel_message_info_get_flags (od->info) & CAMEL_MESSAGE_DELETED)) { + emcu_manage_flush_outbox (E_MAIL_SESSION (od->session)); + } + } + + g_clear_object (&od->session); + g_clear_object (&od->info); + g_free (od); + } +} + /** * em_utils_edit_message: * @composer: an #EMsgComposer @@ -2237,9 +2271,25 @@ em_utils_edit_message (EMsgComposer *composer, g_free (folder_uri); } else if (message_uid != NULL && folder_is_outbox) { + CamelMessageInfo *info; + e_msg_composer_set_header ( composer, "X-Evolution-Replace-Outbox-UID", message_uid); + + info = camel_folder_get_message_info (folder, message_uid); + if (info) { + OutboxData *od; + + /* This makes the message not to send it while it's being edited */ + g_object_set_data (G_OBJECT (info), MAIL_USER_KEY_EDITING, GINT_TO_POINTER (1)); + + od = g_new0 (OutboxData, 1); + od->session = e_msg_composer_ref_session (composer); + od->info = info; /* takes ownership of it */ + + g_object_set_data_full (G_OBJECT (composer), MAIL_USER_KEY_EDITING, od, outbox_data_free); + } } composer_set_no_change (composer);