From a6a451ab876d491d7db593340e07a22f64db8965 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Fri, 24 Nov 2017 12:25:54 +0100 Subject: [PATCH] Bug 790020 - Use original location when composing new message in Search Folder --- src/mail/e-mail-display.c | 7 +- src/mail/e-mail-reader.c | 24 +++- src/mail/em-composer-utils.c | 160 ++++++++++++++++++++- src/mail/em-composer-utils.h | 9 ++ src/modules/mail/e-mail-shell-backend.c | 58 +++++--- .../mailing-list-actions/mailing-list-actions.c | 6 +- 6 files changed, 230 insertions(+), 34 deletions(-) diff --git a/src/mail/e-mail-display.c b/src/mail/e-mail-display.c index f9befc85d1..0e68e8df50 100644 --- a/src/mail/e-mail-display.c +++ b/src/mail/e-mail-display.c @@ -322,14 +322,13 @@ mail_display_process_mailto (EWebView *web_view, if (g_ascii_strncasecmp (mailto_uri, "mailto:", 7) == 0) { EShell *shell; EMailPartList *part_list; - CamelFolder *folder; part_list = E_MAIL_DISPLAY (web_view)->priv->part_list; - folder = e_mail_part_list_get_folder (part_list); shell = e_shell_get_default (); - em_utils_compose_new_message_with_mailto ( - shell, mailto_uri, folder); + em_utils_compose_new_message_with_mailto_and_selection (shell, mailto_uri, + e_mail_part_list_get_folder (part_list), + e_mail_part_list_get_message_uid (part_list)); handled = TRUE; } diff --git a/src/mail/e-mail-reader.c b/src/mail/e-mail-reader.c index 733d91a93d..2de0eb2aee 100644 --- a/src/mail/e-mail-reader.c +++ b/src/mail/e-mail-reader.c @@ -965,6 +965,7 @@ typedef struct _CreateComposerData { EMailReader *reader; CamelMimeMessage *message; CamelFolder *folder; + const gchar *message_uid; /* In the Camel string pool */ gboolean is_redirect; } CreateComposerData; @@ -987,7 +988,7 @@ mail_reader_new_composer_created_cb (GObject *source_object, if (ccd->is_redirect) em_utils_redirect_message (composer, ccd->message); else - em_utils_compose_new_message (composer, ccd->folder); + em_utils_compose_new_message_with_selection (composer, ccd->folder, ccd->message_uid); e_mail_reader_composer_created (ccd->reader, composer, ccd->message); } @@ -995,6 +996,7 @@ mail_reader_new_composer_created_cb (GObject *source_object, g_clear_object (&ccd->reader); g_clear_object (&ccd->message); g_clear_object (&ccd->folder); + camel_pstring_free (ccd->message_uid); g_free (ccd); } @@ -1007,19 +1009,37 @@ action_mail_message_new_cb (GtkAction *action, EShellBackend *shell_backend; CamelFolder *folder; CreateComposerData *ccd; + GPtrArray *selected_uids = NULL; + const gchar *selected_uid = NULL; folder = e_mail_reader_ref_folder (reader); backend = e_mail_reader_get_backend (reader); + selected_uids = e_mail_reader_get_selected_uids (reader); + if (selected_uids && selected_uids->len > 0) + selected_uid = g_ptr_array_index (selected_uids, 0); + + if (!selected_uid) { + GtkWidget *message_list; + + message_list = e_mail_reader_get_message_list (reader); + if (message_list) + selected_uid = MESSAGE_LIST (message_list)->cursor_uid; + } + shell_backend = E_SHELL_BACKEND (backend); shell = e_shell_backend_get_shell (shell_backend); ccd = g_new0 (CreateComposerData, 1); ccd->reader = g_object_ref (reader); ccd->folder = folder; + ccd->message_uid = camel_pstring_strdup (selected_uid); ccd->is_redirect = FALSE; e_msg_composer_new (shell, mail_reader_new_composer_created_cb, ccd); + + if (selected_uids) + g_ptr_array_unref (selected_uids); } static void @@ -1255,6 +1275,7 @@ mail_reader_redirect_cb (CamelFolder *folder, ccd = g_new0 (CreateComposerData, 1); ccd->reader = g_object_ref (closure->reader); ccd->message = message; + ccd->message_uid = camel_pstring_strdup (closure->message_uid); ccd->is_redirect = TRUE; e_msg_composer_new (shell, mail_reader_new_composer_created_cb, ccd); @@ -1285,6 +1306,7 @@ action_mail_redirect_cb (GtkAction *action, closure = g_slice_new0 (EMailReaderClosure); closure->activity = activity; closure->reader = g_object_ref (reader); + closure->message_uid = g_strdup (message_uid); folder = e_mail_reader_ref_folder (reader); diff --git a/src/mail/em-composer-utils.c b/src/mail/em-composer-utils.c index d48eb55df7..02969764e9 100644 --- a/src/mail/em-composer-utils.c +++ b/src/mail/em-composer-utils.c @@ -1402,6 +1402,8 @@ sort_sources_by_ui (GList **psources, /* Composing messages... */ +static CamelMimeMessage *em_utils_get_composer_recipients_as_message (EMsgComposer *composer); + static void set_up_new_composer (EMsgComposer *composer, const gchar *subject, @@ -1425,15 +1427,107 @@ set_up_new_composer (EMsgComposer *composer, GList *list; if (message) { + g_object_ref (message); + } else if (message_uid) { + message = em_utils_get_composer_recipients_as_message (composer); + } + + if (message) { EShell *shell; shell = e_msg_composer_get_shell (composer); + + /* Check send account override for the passed-in folder */ source = em_utils_check_send_account_override (shell, message, folder, &identity_name, &identity_address); - if (!source) + + /* If not set and it's a search folder, then check the original folder */ + if (!source && message_uid && CAMEL_IS_VEE_FOLDER (folder)) { + CamelMessageInfo *mi = camel_folder_get_message_info (folder, message_uid); + if (mi) { + CamelFolder *location; + + location = camel_vee_folder_get_location (CAMEL_VEE_FOLDER (folder), (CamelVeeMessageInfo *) mi, NULL); + if (location) + source = em_utils_check_send_account_override (shell, message, location, &identity_name, &identity_address); + g_clear_object (&mi); + } + } + + /* If no send account override, then guess */ + if (!source) { source = em_utils_guess_mail_identity_with_recipients_and_sort ( registry, message, folder, message_uid, &identity_name, &identity_address, sort_sources_by_ui, shell); + } + } + + /* In case of search folder, try to guess the store from + the internal folders of it. If they are all from the same + store, then use that store. */ + if (!source && CAMEL_IS_VEE_FOLDER (folder)) { + GHashTable *stores, *done_folders; + GSList *todo; + + stores = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); + done_folders = g_hash_table_new (g_direct_hash, g_direct_equal); + + todo = g_slist_prepend (NULL, g_object_ref (folder)); + + while (todo) { + CamelVeeFolder *vfolder = todo->data; + + todo = g_slist_remove (todo, vfolder); + if (!g_hash_table_contains (done_folders, vfolder)) { + GList *folders, *llink; + + g_hash_table_insert (done_folders, vfolder, NULL); + + folders = camel_vee_folder_ref_folders (vfolder); + for (llink = folders; llink; llink = g_list_next (llink)) { + CamelFolder *subfolder = llink->data; + + if (!g_hash_table_contains (done_folders, subfolder)) { + if (CAMEL_IS_VEE_FOLDER (subfolder)) { + todo = g_slist_prepend (todo, g_object_ref (subfolder)); + } else { + CamelStore *store = camel_folder_get_parent_store (subfolder); + + g_hash_table_insert (done_folders, subfolder, NULL); + + if (store) { + g_hash_table_insert (stores, g_object_ref (store), NULL); + + if (g_hash_table_size (stores) > 1) { + g_slist_free_full (todo, g_object_unref); + todo = NULL; + break; + } + } + } + } + } + + g_list_free_full (folders, g_object_unref); + } + + g_object_unref (vfolder); + } + + if (g_hash_table_size (stores) == 1) { + GHashTableIter iter; + gpointer store; + + g_hash_table_iter_init (&iter, stores); + if (g_hash_table_iter_next (&iter, &store, NULL) && store) + source = em_utils_ref_mail_identity_for_store (registry, store); + } + + g_slist_free_full (todo, g_object_unref); + g_hash_table_destroy (done_folders); + g_hash_table_destroy (stores); } + g_clear_object (&message); + if (!source) { CamelStore *store; @@ -1455,7 +1549,8 @@ set_up_new_composer (EMsgComposer *composer, g_object_unref (source); } - e_composer_header_table_set_subject (table, subject); + if (subject) + e_composer_header_table_set_subject (table, subject); e_composer_header_table_set_identity_uid (table, identity, identity_name, identity_address); em_utils_apply_send_account_override_to_composer (composer, folder); @@ -1475,18 +1570,40 @@ set_up_new_composer (EMsgComposer *composer, * * Sets up a new @composer window. * + * See: em_utils_compose_new_message_with_selection() + * * Since: 3.22 **/ void em_utils_compose_new_message (EMsgComposer *composer, CamelFolder *folder) { + em_utils_compose_new_message_with_selection (composer, folder, NULL); +} + +/** + * em_utils_compose_new_message_with_selection: + * @composer: an #EMsgComposer + * @folder: (nullable): a #CamelFolder, or %NULL + * @message_uid: (nullable): a UID of the selected message, or %NULL + * + * Sets up a new @composer window, similar to em_utils_compose_new_message(), + * but also tries to identify From account more precisely, when the @folder + * is a search folder. + * + * Since: 3.28 + **/ +void +em_utils_compose_new_message_with_selection (EMsgComposer *composer, + CamelFolder *folder, + const gchar *message_uid) +{ g_return_if_fail (E_IS_MSG_COMPOSER (composer)); - if (folder != NULL) + if (folder) g_return_if_fail (CAMEL_IS_FOLDER (folder)); - set_up_new_composer (composer, "", folder, NULL, NULL); + set_up_new_composer (composer, "", folder, NULL, message_uid); composer_set_no_change (composer); gtk_widget_show (GTK_WIDGET (composer)); @@ -1570,8 +1687,9 @@ em_utils_get_composer_recipients_as_message (EMsgComposer *composer) } typedef struct _CreateComposerData { - gchar *mailto; CamelFolder *folder; + const gchar *message_uid; /* In the Camel string pool */ + gchar *mailto; } CreateComposerData; static void @@ -1581,6 +1699,7 @@ create_composer_data_free (gpointer ptr) if (ccd) { g_clear_object (&ccd->folder); + camel_pstring_free (ccd->message_uid); g_free (ccd->mailto); g_free (ccd); } @@ -1612,7 +1731,7 @@ msg_composer_created_with_mailto_cb (GObject *source_object, if (ccd->mailto) e_msg_composer_setup_from_url (composer, ccd->mailto); - em_utils_apply_send_account_override_to_composer (composer, ccd->folder); + set_up_new_composer (composer, NULL, ccd->folder, NULL, ccd->message_uid); table = e_msg_composer_get_header_table (composer); @@ -1655,21 +1774,48 @@ msg_composer_created_with_mailto_cb (GObject *source_object, * Opens a new composer window as a child window of @parent's toplevel * window. If @mailto is non-NULL, the composer fields will be filled in * according to the values in the mailto URL. + * + * See: em_utils_compose_new_message_with_mailto_and_selection() **/ void em_utils_compose_new_message_with_mailto (EShell *shell, const gchar *mailto, CamelFolder *folder) { + em_utils_compose_new_message_with_mailto_and_selection (shell, mailto, folder, NULL); +} + +/** + * em_utils_compose_new_message_with_mailto_and_selection: + * @shell: an #EShell + * @mailto: a mailto URL + * @folder: a #CamelFolder, or %NULL + * @message_uid: (nullable): a UID of the selected message, or %NULL + * + * similarly to em_utils_compose_new_message_with_mailto(), opens a new composer + * window as a child window of @parent's toplevel window. If @mailto is non-NULL, + * the composer fields will be filled in according to the values in the mailto URL. + * It also tries to identify From account more precisely, when the @folder + * is a search folder. + * + * Since: 3.28 + **/ +void +em_utils_compose_new_message_with_mailto_and_selection (EShell *shell, + const gchar *mailto, + CamelFolder *folder, + const gchar *message_uid) +{ CreateComposerData *ccd; g_return_if_fail (E_IS_SHELL (shell)); - if (folder != NULL) + if (folder) g_return_if_fail (CAMEL_IS_FOLDER (folder)); ccd = g_new0 (CreateComposerData, 1); ccd->folder = folder ? g_object_ref (folder) : NULL; + ccd->message_uid = camel_pstring_strdup (message_uid); ccd->mailto = g_strdup (mailto); e_msg_composer_new (shell, msg_composer_created_with_mailto_cb, ccd); diff --git a/src/mail/em-composer-utils.h b/src/mail/em-composer-utils.h index d9035ea5a0..91471bcb5f 100644 --- a/src/mail/em-composer-utils.h +++ b/src/mail/em-composer-utils.h @@ -35,10 +35,19 @@ G_BEGIN_DECLS void em_utils_compose_new_message (EMsgComposer *composer, CamelFolder *folder); +void em_utils_compose_new_message_with_selection + (EMsgComposer *composer, + CamelFolder *folder, + const gchar *message_uid); void em_utils_compose_new_message_with_mailto (EShell *shell, const gchar *mailto, CamelFolder *folder); +void em_utils_compose_new_message_with_mailto_and_selection + (EShell *shell, + const gchar *mailto, + CamelFolder *folder, + const gchar *message_uid); void em_utils_edit_message (EMsgComposer *composer, CamelFolder *folder, CamelMimeMessage *message, diff --git a/src/modules/mail/e-mail-shell-backend.c b/src/modules/mail/e-mail-shell-backend.c index 01878688de..99e5aae3eb 100644 --- a/src/modules/mail/e-mail-shell-backend.c +++ b/src/modules/mail/e-mail-shell-backend.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -298,46 +299,54 @@ action_mail_account_new_cb (GtkAction *action, GTK_WINDOW (shell_window)); } +typedef struct _NewComposerData +{ + CamelFolder *folder; + const gchar *message_uid; /* In the Camel string pool */ +} NewComposerData; + static void action_mail_message_new_composer_created_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { - CamelFolder *folder = user_data; + NewComposerData *ncd = user_data; EMsgComposer *composer; GError *error = NULL; - if (folder) - g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (ncd != NULL); + + if (ncd->folder) + g_return_if_fail (CAMEL_IS_FOLDER (ncd->folder)); composer = e_msg_composer_new_finish (result, &error); if (error) { g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message); g_clear_error (&error); } else { - em_utils_compose_new_message (composer, folder); + em_utils_compose_new_message_with_selection (composer, ncd->folder, ncd->message_uid); } - g_clear_object (&folder); + g_clear_object (&ncd->folder); + camel_pstring_free (ncd->message_uid); + g_free (ncd); } static void action_mail_message_new_cb (GtkAction *action, EShellWindow *shell_window) { - EMailShellSidebar *mail_shell_sidebar; - EShellSidebar *shell_sidebar; EShellView *shell_view; EShell *shell; ESourceRegistry *registry; - EMFolderTree *folder_tree; CamelFolder *folder = NULL; - CamelStore *store; GList *list; const gchar *extension_name; const gchar *view_name; gboolean no_transport_defined; - gchar *folder_name; + const gchar *message_uid = NULL; + GtkWidget *message_list; + NewComposerData *ncd; shell = e_shell_window_get_shell (shell_window); registry = e_shell_get_registry (shell); @@ -356,24 +365,31 @@ action_mail_message_new_cb (GtkAction *action, goto exit; shell_view = e_shell_window_get_shell_view (shell_window, view_name); - shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); - mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar); - folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar); + message_list = e_mail_reader_get_message_list (E_MAIL_READER (e_shell_view_get_shell_content (shell_view))); + if (message_list) { + MessageList *ml = MESSAGE_LIST (message_list); + GPtrArray *selected_uids; + + folder = message_list_ref_folder (ml); - if (em_folder_tree_get_selected (folder_tree, &store, &folder_name)) { + selected_uids = message_list_get_selected (ml); + if (selected_uids && selected_uids->len > 0) + message_uid = camel_pstring_strdup (g_ptr_array_index (selected_uids, 0)); - /* FIXME This blocks and is not cancellable. */ - folder = camel_store_get_folder_sync ( - store, folder_name, 0, NULL, NULL); + if (!message_uid) + message_uid = camel_pstring_strdup (ml->cursor_uid); - g_object_unref (store); - g_free (folder_name); + if (selected_uids) + g_ptr_array_unref (selected_uids); } exit: - e_msg_composer_new (shell, action_mail_message_new_composer_created_cb, - folder ? g_object_ref (folder) : NULL); + ncd = g_new0 (NewComposerData, 1); + ncd->folder = folder; + ncd->message_uid = message_uid; + + e_msg_composer_new (shell, action_mail_message_new_composer_created_cb, ncd); } static GtkActionEntry item_entries[] = { diff --git a/src/plugins/mailing-list-actions/mailing-list-actions.c b/src/plugins/mailing-list-actions/mailing-list-actions.c index fcad7506b1..c9be89318e 100644 --- a/src/plugins/mailing-list-actions/mailing-list-actions.c +++ b/src/plugins/mailing-list-actions/mailing-list-actions.c @@ -100,6 +100,7 @@ struct _AsyncContext { EActivity *activity; EMailReader *reader; EmlaAction action; + const gchar *message_uid; /* In the Camel string pool */ }; static void @@ -111,6 +112,8 @@ async_context_free (AsyncContext *context) if (context->reader != NULL) g_object_unref (context->reader); + camel_pstring_free (context->message_uid); + g_slice_free (AsyncContext, context); } @@ -283,7 +286,7 @@ emla_list_action_cb (CamelFolder *folder, e_msg_composer_new (shell, send_message_composer_created_cb, smd); } else if (send_message_response == GTK_RESPONSE_NO) { /* show composer */ - em_utils_compose_new_message_with_mailto (shell, url, folder); + em_utils_compose_new_message_with_mailto_and_selection (shell, url, folder, context->message_uid); } goto exit; @@ -344,6 +347,7 @@ emla_list_action (EMailReader *reader, context->activity = activity; context->reader = g_object_ref (reader); context->action = action; + context->message_uid = camel_pstring_strdup (message_uid); folder = e_mail_reader_ref_folder (reader); -- 2.11.4.GIT