[evolution] Bug 602612 - Add 'Alternative Reply' menu option



commit 7b8e53dd1496da1b9c2c5384c2649d7edf5a22e3
Author: Milan Crha <mcrha redhat com>
Date:   Mon Mar 12 14:29:49 2018 +0100

    Bug 602612 - Add 'Alternative Reply' menu option

 data/org.gnome.evolution.mail.gschema.xml.in       |   38 +-
 data/ui/evolution-mail-reader.ui                   |    2 +
 po/POTFILES.in                                     |    2 +-
 src/composer/mail-composer.error.xml               |    5 +
 src/mail/CMakeLists.txt                            |    4 +
 src/mail/e-mail-enums.h                            |   30 +
 src/mail/e-mail-reader-utils.c                     |    5 +-
 src/mail/e-mail-reader.c                           |   91 ++
 .../e-mail-templates-store.c}                      |  340 ++++++--
 src/mail/e-mail-templates-store.h                  |  110 +++
 src/mail/e-mail-templates.c                        |  497 +++++++++++
 src/mail/e-mail-templates.h                        |   49 ++
 src/mail/em-composer-utils.c                       |  864 ++++++++++++++++++-
 src/mail/em-composer-utils.h                       |   11 +-
 src/modules/mail/e-mail-attachment-handler.c       |    2 +-
 src/modules/webkit-editor/e-webkit-editor.c        |    1 +
 src/plugins/templates/CMakeLists.txt               |    2 -
 src/plugins/templates/e-templates-store.h          |   95 ---
 src/plugins/templates/templates.c                  |  517 +-----------
 19 files changed, 1963 insertions(+), 702 deletions(-)
---
diff --git a/data/org.gnome.evolution.mail.gschema.xml.in b/data/org.gnome.evolution.mail.gschema.xml.in
index 7d4d02d..4712824 100644
--- a/data/org.gnome.evolution.mail.gschema.xml.in
+++ b/data/org.gnome.evolution.mail.gschema.xml.in
@@ -16,6 +16,7 @@
 
   <!-- Keep this synchronized with EMailReplyStyle. -->
   <enum id="org.gnome.evolution.mail.ReplyStyle">
+    <value nick='unknown'      value='-1'/>
     <value nick='quoted'       value='0'/>
     <value nick='do-not-quote' value='1'/>
     <value nick='attach'       value='2'/>
@@ -29,6 +30,13 @@
     <value nick='always'    value='2'/>
   </enum>
 
+  <!-- Keep this synchronized with EThreeState from evolution-data-server. -->
+  <enum id="org.gnome.evolution.mail.ThreeState">
+    <value nick='off'          value='0'/>
+    <value nick='on'           value='1'/>
+    <value nick='inconsistent' value='2'/>
+  </enum>
+
   <schema gettext-domain="evolution" id="org.gnome.evolution.mail" path="/org/gnome/evolution/mail/">
     <key name="prompt-check-if-default-mailer" type="b">
       <default>true</default>
@@ -733,7 +741,35 @@
       <_summary>Visually wrap long lines in composer</_summary>
       <_description>Whether to visually wrap long lines of text to avoid horizontal scrolling</_description>
     </key>
-
+    <key name="alt-reply-style" enum="org.gnome.evolution.mail.ReplyStyle">
+      <default>'quoted'</default>
+      <_summary>Alternative reply style</_summary>
+    </key>
+    <key name="alt-reply-html-format" enum="org.gnome.evolution.mail.ThreeState">
+      <default>'inconsistent'</default>
+      <_summary>Format message in HTML</_summary>
+    </key>
+    <key name="alt-reply-start-bottom" enum="org.gnome.evolution.mail.ThreeState">
+      <default>'inconsistent'</default>
+      <_summary>Put the cursor at the bottom of alternative replies</_summary>
+      <_description>This determines whether the cursor is placed at the top of the message or the bottom 
when using Alternative Reply.</_description>
+    </key>
+    <key name="alt-reply-template-apply" type="b">
+      <default>false</default>
+      <_summary>Apply chosen template when using Alternative Reply</_summary>
+    </key>
+    <key name="alt-reply-template-folder-uri" type="s">
+      <default>''</default>
+      <_summary>Last chosen template's folder URI for Alternative Reply</_summary>
+    </key>
+    <key name="alt-reply-template-message-uid" type="s">
+      <default>''</default>
+      <_summary>Last chosen template's message UID for Alternative Reply</_summary>
+    </key>
+    <key name="alt-reply-template-preserve-subject" type="b">
+      <default>false</default>
+      <_summary>Whether preserve original message subject when applying template for Alternative 
Reply</_summary>
+    </key>
     <!-- The following keys are deprecated. -->
 
     <key name="forward-style" type="i">
diff --git a/data/ui/evolution-mail-reader.ui b/data/ui/evolution-mail-reader.ui
index d005a1e..1174fc4 100644
--- a/data/ui/evolution-mail-reader.ui
+++ b/data/ui/evolution-mail-reader.ui
@@ -61,6 +61,7 @@
         <menuitem action='mail-reply-sender'/>
         <menuitem action='mail-reply-list'/>
         <menuitem action='mail-reply-all'/>
+        <menuitem action='mail-reply-alternative'/>
         <menuitem action='mail-forward'/>
         <menu action='mail-forward-as-menu'>
           <menuitem action='mail-forward-attached'/>
@@ -126,6 +127,7 @@
         <menu action='mail-reply-group-menu'>
           <menuitem action='mail-reply-all'/>
           <menuitem action='mail-reply-list'/>
+          <menuitem action='mail-reply-alternative'/>
         </menu>
       </toolitem>
       <toolitem action='mail-forward'>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6ac8212..1f3e304 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -352,6 +352,7 @@ src/mail/e-mail-reader.c
 src/mail/e-mail-reader-utils.c
 src/mail/e-mail-request.c
 src/mail/e-mail-tag-editor.c
+src/mail/e-mail-templates-store.c
 src/mail/e-mail-ui-session.c
 src/mail/em-composer-utils.c
 src/mail/em-filter-editor.c
@@ -521,7 +522,6 @@ src/plugins/save-calendar/ical-format.c
 src/plugins/save-calendar/org-gnome-save-calendar.eplug.xml
 src/plugins/save-calendar/rdf-format.c
 src/plugins/save-calendar/save-calendar.c
-src/plugins/templates/e-templates-store.c
 src/plugins/templates/org-gnome-templates.eplug.xml
 src/plugins/templates/templates.c
 src/shell/e-shell-backend.c
diff --git a/src/composer/mail-composer.error.xml b/src/composer/mail-composer.error.xml
index c6a7dd2..d7982c3 100644
--- a/src/composer/mail-composer.error.xml
+++ b/src/composer/mail-composer.error.xml
@@ -148,4 +148,9 @@ Detailed error: {0}</_secondary>
    <_primary>Something has gone wrong when editing the message</_primary>
    <_secondary>A WebKitWebProcess crashed when editing the message. You can try again by closing the 
composer window and opening a new one. If the issue persists, please file a bug report in the GNOME 
bugzilla.</_secondary>
  </error>
+
+ <error id="failed-create-composer" type="error">
+  <_primary>An error occurred while creating message composer.</_primary>
+  <secondary>{0}</secondary>
+ </error>
 </error-list>
diff --git a/src/mail/CMakeLists.txt b/src/mail/CMakeLists.txt
index 279099f..e9abcc7 100644
--- a/src/mail/CMakeLists.txt
+++ b/src/mail/CMakeLists.txt
@@ -87,6 +87,8 @@ set(SOURCES
        e-mail-send-account-override.c
        e-mail-sidebar.c
        e-mail-tag-editor.c
+       e-mail-templates.c
+       e-mail-templates-store.c
        e-mail-ui-session.c
        e-mail-view.c
        em-composer-utils.c
@@ -173,6 +175,8 @@ set(HEADERS
        e-mail-send-account-override.h
        e-mail-sidebar.h
        e-mail-tag-editor.h
+       e-mail-templates.h
+       e-mail-templates-store.h
        e-mail-ui-session.h
        e-mail-view.h
        em-composer-utils.h
diff --git a/src/mail/e-mail-enums.h b/src/mail/e-mail-enums.h
index 9665967..0f94c6d 100644
--- a/src/mail/e-mail-enums.h
+++ b/src/mail/e-mail-enums.h
@@ -29,6 +29,7 @@ typedef enum {
 } EMailForwardStyle;
 
 typedef enum {
+       E_MAIL_REPLY_STYLE_UNKNOWN = -1,
        E_MAIL_REPLY_STYLE_QUOTED,
        E_MAIL_REPLY_STYLE_DO_NOT_QUOTE,
        E_MAIL_REPLY_STYLE_ATTACH,
@@ -43,6 +44,35 @@ typedef enum {
        E_MAIL_REPLY_TO_LIST
 } EMailReplyType;
 
+/**
+ * EMailReplyFlags:
+ * @E_MAIL_REPLY_FLAG_NONE: no flags used
+ * @E_MAIL_REPLY_FLAG_FORCE_STYLE: Force use of the passed-in reply style; if not set,
+ *    then also checks reply style setting for the used mail account.
+ * @E_MAIL_REPLY_FLAG_FORMAT_PLAIN: Force compose in Plain Text format; cannot be used together
+ *    with @E_MAIL_REPLY_FLAG_FORMAT_HTML. If none of these is set, then uses
+ *    global setting.
+ * @E_MAIL_REPLY_FLAG_FORMAT_HTML: Force compose in HTML format; cannot be used together
+ *    with @E_MAIL_REPLY_FLAG_FORMAT_PLAIN. If none of these is set, then uses
+ *    global setting.
+ * @E_MAIL_REPLY_FLAG_TOP_POSTING: Force top posting; cannot be used together
+ *    with @E_MAIL_REPLY_FLAG_BOTTOM_POSTING. If none it set, then uses global settings.
+ * @E_MAIL_REPLY_FLAG_BOTTOM_POSTING: Force bottom posting; cannot be used together
+ *    with @E_MAIL_REPLY_FLAG_BOTTOM_POSTING. If none it set, then uses global settings.
+ *
+ * Flags influencing behavior of em_utils_reply_to_message().
+ *
+ * Since: 3.30
+ **/
+typedef enum { /*< flags >*/
+       E_MAIL_REPLY_FLAG_NONE                  = 0,
+       E_MAIL_REPLY_FLAG_FORCE_STYLE           = 1 << 0,
+       E_MAIL_REPLY_FLAG_FORMAT_PLAIN          = 1 << 1,
+       E_MAIL_REPLY_FLAG_FORMAT_HTML           = 1 << 2,
+       E_MAIL_REPLY_FLAG_TOP_POSTING           = 1 << 3,
+       E_MAIL_REPLY_FLAG_BOTTOM_POSTING        = 1 << 4
+} EMailReplyFlags;
+
 G_END_DECLS
 
 #endif /* E_MAIL_ENUMS_H */
diff --git a/src/mail/e-mail-reader-utils.c b/src/mail/e-mail-reader-utils.c
index 7e2f4d7..9ac8c9e 100644
--- a/src/mail/e-mail-reader-utils.c
+++ b/src/mail/e-mail-reader-utils.c
@@ -2410,7 +2410,8 @@ mail_reader_reply_composer_created_cb (GObject *object,
                        async_context->reply_type,
                        async_context->reply_style,
                        async_context->part_list,
-                       async_context->address);
+                       async_context->address,
+                       E_MAIL_REPLY_FLAG_NONE);
 
                e_mail_reader_composer_created (async_context->reader, composer, message);
        }
@@ -2518,7 +2519,7 @@ mail_reader_reply_to_message_composer_created_cb (GObject *source_object,
        } else {
                em_utils_reply_to_message (
                        composer, ccd->message, ccd->folder, ccd->message_uid,
-                       ccd->reply_type, ccd->reply_style, ccd->part_list, ccd->address);
+                       ccd->reply_type, ccd->reply_style, ccd->part_list, ccd->address, 
E_MAIL_REPLY_FLAG_NONE);
 
                if (ccd->validity_pgp_sum != 0 || ccd->validity_smime_sum != 0) {
                        GtkToggleAction *action;
diff --git a/src/mail/e-mail-reader.c b/src/mail/e-mail-reader.c
index 2c84230..75d1de3 100644
--- a/src/mail/e-mail-reader.c
+++ b/src/mail/e-mail-reader.c
@@ -1477,6 +1477,85 @@ action_mail_reply_all_cb (GtkAction *action,
 }
 
 static void
+action_mail_reply_alternative_got_message (CamelFolder *folder,
+                                          GAsyncResult *result,
+                                          EMailReaderClosure *closure)
+{
+       EAlertSink *alert_sink;
+       EMailDisplay *mail_display;
+       CamelMimeMessage *message;
+       GError *error = NULL;
+
+       alert_sink = e_activity_get_alert_sink (closure->activity);
+
+       message = camel_folder_get_message_finish (folder, result, &error);
+
+       if (e_activity_handle_cancellation (closure->activity, error)) {
+               g_warn_if_fail (message == NULL);
+               mail_reader_closure_free (closure);
+               g_error_free (error);
+               return;
+
+       } else if (error != NULL) {
+               g_warn_if_fail (message == NULL);
+               e_alert_submit (
+                       alert_sink, "mail:no-retrieve-message",
+                       error->message, NULL);
+               mail_reader_closure_free (closure);
+               g_error_free (error);
+               return;
+       }
+
+       g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+       g_clear_object (&closure->activity);
+
+       mail_display = e_mail_reader_get_mail_display (closure->reader);
+
+       em_utils_reply_alternative (e_mail_reader_get_window (closure->reader),
+               e_shell_backend_get_shell (E_SHELL_BACKEND (e_mail_reader_get_backend (closure->reader))),
+               alert_sink, message, folder, closure->message_uid,
+               e_mail_reader_get_reply_style (closure->reader),
+               mail_display ? e_mail_display_get_part_list (mail_display) : NULL);
+
+       g_object_unref (message);
+       mail_reader_closure_free (closure);
+}
+
+static void
+action_mail_reply_alternative_cb (GtkAction *action,
+                                 EMailReader *reader)
+{
+       EActivity *activity;
+       GCancellable *cancellable;
+       EMailReaderClosure *closure;
+       CamelFolder *folder;
+       GtkWidget *message_list;
+       const gchar *message_uid;
+
+       message_list = e_mail_reader_get_message_list (reader);
+       message_uid = MESSAGE_LIST (message_list)->cursor_uid;
+       g_return_if_fail (message_uid != NULL);
+
+       activity = e_mail_reader_new_activity (reader);
+       cancellable = e_activity_get_cancellable (activity);
+
+       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);
+
+       camel_folder_get_message (
+               folder, message_uid, G_PRIORITY_DEFAULT,
+               cancellable, (GAsyncReadyCallback)
+               action_mail_reply_alternative_got_message, closure);
+
+       g_clear_object (&folder);
+}
+
+static void
 action_mail_reply_group_cb (GtkAction *action,
                             EMailReader *reader)
 {
@@ -2439,6 +2518,13 @@ static GtkActionEntry mail_reader_entries[] = {
          N_("Compose a reply to all the recipients of the selected message"),
          G_CALLBACK (action_mail_reply_all_cb) },
 
+       { "mail-reply-alternative",
+         NULL,
+         N_("Al_ternative Reply…"),
+         "<Alt><Control>r",
+         N_("Choose reply options for the selected message"),
+         G_CALLBACK (action_mail_reply_alternative_cb) },
+
        { "mail-reply-list",
          NULL,
          N_("Reply to _List"),
@@ -4070,6 +4156,11 @@ mail_reader_update_actions (EMailReader *reader,
        action = e_mail_reader_get_action (reader, action_name);
        gtk_action_set_sensitive (action, sensitive);
 
+       action_name = "mail-reply-alternative";
+       sensitive = have_enabled_account && single_message_selected;
+       action = e_mail_reader_get_action (reader, action_name);
+       gtk_action_set_sensitive (action, sensitive);
+
        action_name = "mail-reply-group";
        sensitive = have_enabled_account && single_message_selected;
        action = e_mail_reader_get_action (reader, action_name);
diff --git a/src/plugins/templates/e-templates-store.c b/src/mail/e-mail-templates-store.c
similarity index 85%
rename from src/plugins/templates/e-templates-store.c
rename to src/mail/e-mail-templates-store.c
index 1f4017b..9d41e41 100644
--- a/src/plugins/templates/e-templates-store.c
+++ b/src/mail/e-mail-templates-store.c
@@ -25,9 +25,9 @@
 
 #include "shell/e-shell-view.h"
 
-#include "e-templates-store.h"
+#include "e-mail-templates-store.h"
 
-struct _ETemplatesStorePrivate {
+struct _EMailTemplatesStorePrivate {
        GWeakRef *account_store_weakref; /* EMailAccountStore * */
 
        gulong service_enabled_handler_id;
@@ -41,7 +41,7 @@ struct _ETemplatesStorePrivate {
        guint menu_refresh_idle_id;
 };
 
-G_DEFINE_TYPE (ETemplatesStore, e_templates_store, G_TYPE_OBJECT);
+G_DEFINE_TYPE (EMailTemplatesStore, e_mail_templates_store, G_TYPE_OBJECT);
 
 enum {
        PROP_0,
@@ -56,25 +56,25 @@ enum {
 static guint signals[LAST_SIGNAL];
 
 static void
-templates_store_lock (ETemplatesStore *templates_store)
+templates_store_lock (EMailTemplatesStore *templates_store)
 {
-       g_return_if_fail (E_IS_TEMPLATES_STORE (templates_store));
+       g_return_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store));
 
        g_mutex_lock (&templates_store->priv->busy_lock);
 }
 
 static void
-templates_store_unlock (ETemplatesStore *templates_store)
+templates_store_unlock (EMailTemplatesStore *templates_store)
 {
-       g_return_if_fail (E_IS_TEMPLATES_STORE (templates_store));
+       g_return_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store));
 
        g_mutex_unlock (&templates_store->priv->busy_lock);
 }
 
 static void
-templates_store_emit_changed (ETemplatesStore *templates_store)
+templates_store_emit_changed (EMailTemplatesStore *templates_store)
 {
-       g_return_if_fail (E_IS_TEMPLATES_STORE (templates_store));
+       g_return_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store));
 
        g_signal_emit (templates_store, signals[CHANGED], 0, NULL);
 }
@@ -174,7 +174,7 @@ tmpl_message_data_compare (gconstpointer ptr1,
 
 typedef struct _TmplFolderData {
        volatile gint ref_count;
-       GWeakRef *templates_store_weakref; /* ETemplatesStore * */
+       GWeakRef *templates_store_weakref; /* EMailTemplatesStore * */
        CamelFolder *folder;
        gulong changed_handler_id;
 
@@ -187,12 +187,12 @@ typedef struct _TmplFolderData {
 } TmplFolderData;
 
 static TmplFolderData *
-tmpl_folder_data_new (ETemplatesStore *templates_store,
+tmpl_folder_data_new (EMailTemplatesStore *templates_store,
                      CamelFolder *folder)
 {
        TmplFolderData *tfd;
 
-       g_return_val_if_fail (E_IS_TEMPLATES_STORE (templates_store), NULL);
+       g_return_val_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store), NULL);
        g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
 
        tfd = g_new0 (TmplFolderData, 1);
@@ -397,7 +397,7 @@ tmpl_folder_data_update_done_cb (GObject *source,
 
        if (g_task_propagate_boolean (G_TASK (result), &local_error)) {
                /* Content changed, rebuild menu when needed */
-               ETemplatesStore *templates_store;
+               EMailTemplatesStore *templates_store;
 
                templates_store = g_weak_ref_get (tfd->templates_store_weakref);
                if (templates_store) {
@@ -515,7 +515,7 @@ static void
 tmpl_folder_data_schedule_update (TmplFolderData *tfd,
                                  CamelFolderChangeInfo *change_info)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        TfdUpdateData *tud;
        GTask *task;
        guint ii;
@@ -574,7 +574,7 @@ tmpl_folder_data_folder_changed_cb (CamelFolder *folder,
            (change_info->uid_changed && change_info->uid_changed->len)) {
                tmpl_folder_data_schedule_update (tfd, change_info);
        } else if (change_info->uid_removed && change_info->uid_removed->len) {
-               ETemplatesStore *templates_store;
+               EMailTemplatesStore *templates_store;
 
                templates_store = g_weak_ref_get (tfd->templates_store_weakref);
                if (templates_store) {
@@ -614,7 +614,7 @@ tmpl_store_data_traverse_to_free_cb (GNode *node,
 
 typedef struct _TmplStoreData {
        volatile gint ref_count;
-       GWeakRef *templates_store_weakref; /* ETemplatesStore * */
+       GWeakRef *templates_store_weakref; /* EMailTemplatesStore * */
        GWeakRef *store_weakref; /* CamelStore * */
 
        gulong folder_created_handler_id;
@@ -634,7 +634,7 @@ tmpl_store_data_set_root_folder_path (TmplStoreData *tsd,
                                      const gchar *root_folder_path);
 
 static TmplStoreData *
-tmpl_store_data_new (ETemplatesStore *templates_store,
+tmpl_store_data_new (EMailTemplatesStore *templates_store,
                     CamelStore *store,
                     const gchar *root_folder_path,
                     const gchar *templates_folder_uri,
@@ -642,7 +642,7 @@ tmpl_store_data_new (ETemplatesStore *templates_store,
 {
        TmplStoreData *tsd;
 
-       g_return_val_if_fail (E_IS_TEMPLATES_STORE (templates_store), NULL);
+       g_return_val_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store), NULL);
        g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
        g_return_val_if_fail (root_folder_path && *root_folder_path, NULL);
        g_return_val_if_fail (templates_folder_uri && *templates_folder_uri, NULL);
@@ -960,7 +960,7 @@ tmpl_store_data_update_done_cb (GObject *source,
 
        if (g_task_propagate_boolean (G_TASK (result), &local_error)) {
                /* Content changed, rebuild menu when needed */
-               ETemplatesStore *templates_store;
+               EMailTemplatesStore *templates_store;
 
                templates_store = g_weak_ref_get (tsd->templates_store_weakref);
                if (templates_store) {
@@ -980,7 +980,7 @@ tmpl_store_data_initial_setup_thread (GTask *task,
                                      gpointer task_data,
                                      GCancellable *cancellable)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        TmplStoreData *tsd = task_data;
        CamelStore *store;
        gboolean changed = FALSE;
@@ -1079,7 +1079,7 @@ tmpl_store_data_initial_setup_thread (GTask *task,
 static void
 tmpl_store_data_schedule_initial_setup (TmplStoreData *tsd)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        GTask *task;
 
        g_return_if_fail (tsd != NULL);
@@ -1123,7 +1123,7 @@ tmpl_store_data_folder_thread (GTask *task,
                               gpointer task_data,
                               GCancellable *cancellable)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        TsdFolderData *fd = task_data;
        CamelStore *store;
        gboolean changed = FALSE;
@@ -1230,7 +1230,7 @@ tmpl_store_data_folder_created_cb (CamelStore *store,
                                   gpointer user_data)
 {
        TmplStoreData *tsd = user_data;
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
 
        g_return_if_fail (CAMEL_IS_STORE (store));
        g_return_if_fail (folder_info != NULL);
@@ -1271,7 +1271,7 @@ tmpl_store_data_folder_deleted_cb (CamelStore *store,
                                   gpointer user_data)
 {
        TmplStoreData *tsd = user_data;
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        gboolean changed = FALSE;
 
        g_return_if_fail (CAMEL_IS_STORE (store));
@@ -1309,7 +1309,7 @@ tmpl_store_data_folder_renamed_cb (CamelStore *store,
                                   gpointer user_data)
 {
        TmplStoreData *tsd = user_data;
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        gboolean changed = FALSE;
 
        g_return_if_fail (CAMEL_IS_STORE (store));
@@ -1375,7 +1375,7 @@ tmpl_store_data_notify_display_name_cb (CamelService *service,
                                        gpointer user_data)
 {
        TmplStoreData *tsd = user_data;
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
 
        g_return_if_fail (CAMEL_IS_SERVICE (service));
        g_return_if_fail (tsd != NULL);
@@ -1385,7 +1385,7 @@ tmpl_store_data_notify_display_name_cb (CamelService *service,
                EMailAccountStore *account_store;
                gboolean changed = FALSE;
 
-               account_store = e_templates_store_ref_account_store (templates_store);
+               account_store = e_mail_templates_store_ref_account_store (templates_store);
 
                templates_store_lock (templates_store);
 
@@ -1404,7 +1404,7 @@ tmpl_store_data_notify_display_name_cb (CamelService *service,
 }
 
 static gchar *
-templates_store_find_custom_templates_root_folder_path (ETemplatesStore *templates_store,
+templates_store_find_custom_templates_root_folder_path (EMailTemplatesStore *templates_store,
                                                        CamelStore *store,
                                                        EMailSession *mail_session,
                                                        ESource **out_identity_source,
@@ -1414,7 +1414,7 @@ templates_store_find_custom_templates_root_folder_path (ETemplatesStore *templat
        ESource *identity_source;
        gchar *root_folder_path = NULL;
 
-       g_return_val_if_fail (E_IS_TEMPLATES_STORE (templates_store), NULL);
+       g_return_val_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store), NULL);
        g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
        g_return_val_if_fail (out_identity_source != NULL, NULL);
        g_return_val_if_fail (out_use_store != NULL, NULL);
@@ -1471,7 +1471,7 @@ templates_store_find_custom_templates_root_folder_path (ETemplatesStore *templat
 }
 
 static void
-templates_store_maybe_add_store (ETemplatesStore *templates_store,
+templates_store_maybe_add_store (EMailTemplatesStore *templates_store,
                                 CamelStore *store)
 {
        ESource *identity_source = NULL;
@@ -1481,10 +1481,10 @@ templates_store_maybe_add_store (ETemplatesStore *templates_store,
        gchar *root_folder_path, *templates_folder_uri = NULL;
        gboolean changed = FALSE;
 
-       g_return_if_fail (E_IS_TEMPLATES_STORE (templates_store));
+       g_return_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store));
        g_return_if_fail (CAMEL_IS_STORE (store));
 
-       account_store = e_templates_store_ref_account_store (templates_store);
+       account_store = e_mail_templates_store_ref_account_store (templates_store);
        if (!account_store)
                return;
 
@@ -1544,13 +1544,13 @@ templates_store_maybe_add_store (ETemplatesStore *templates_store,
 }
 
 static void
-templates_store_maybe_remove_store (ETemplatesStore *templates_store,
+templates_store_maybe_remove_store (EMailTemplatesStore *templates_store,
                                    CamelStore *store)
 {
        GSList *link;
        gboolean changed = FALSE;
 
-       g_return_if_fail (E_IS_TEMPLATES_STORE (templates_store));
+       g_return_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store));
        g_return_if_fail (CAMEL_IS_STORE (store));
 
        templates_store_lock (templates_store);
@@ -1582,15 +1582,15 @@ templates_store_maybe_remove_store (ETemplatesStore *templates_store,
 }
 
 static void
-templates_store_maybe_add_enabled_services (ETemplatesStore *templates_store)
+templates_store_maybe_add_enabled_services (EMailTemplatesStore *templates_store)
 {
        EMailAccountStore *account_store;
        GQueue queue = G_QUEUE_INIT;
 
-       g_return_if_fail (E_IS_TEMPLATES_STORE (templates_store));
+       g_return_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store));
        g_return_if_fail (templates_store->priv->stores == NULL);
 
-       account_store = e_templates_store_ref_account_store (templates_store);
+       account_store = e_mail_templates_store_ref_account_store (templates_store);
        g_return_if_fail (account_store != NULL);
 
        e_mail_account_store_queue_enabled_services (account_store, &queue);
@@ -1612,7 +1612,7 @@ templates_store_service_enabled_cb (EMailAccountStore *account_store,
                                    CamelService *service,
                                    GWeakRef *weak_ref)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
 
        if (!CAMEL_IS_STORE (service))
                return;
@@ -1630,7 +1630,7 @@ templates_store_service_disabled_cb (EMailAccountStore *account_store,
                                     CamelService *service,
                                     GWeakRef *weak_ref)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
 
        if (!CAMEL_IS_STORE (service))
                return;
@@ -1648,7 +1648,7 @@ templates_store_service_removed_cb (EMailAccountStore *account_store,
                                    CamelService *service,
                                    GWeakRef *weak_ref)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
 
        if (!CAMEL_IS_STORE (service))
                return;
@@ -1666,7 +1666,7 @@ templates_store_source_changed_cb (ESourceRegistry *registry,
                                   ESource *source,
                                   GWeakRef *weak_ref)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
 
        g_return_if_fail (E_IS_SOURCE (source));
 
@@ -1754,7 +1754,7 @@ templates_store_source_changed_cb (ESourceRegistry *registry,
 }
 
 static void
-templates_store_set_account_store (ETemplatesStore *templates_store,
+templates_store_set_account_store (EMailTemplatesStore *templates_store,
                                   EMailAccountStore *account_store)
 {
        g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (account_store));
@@ -1771,7 +1771,7 @@ templates_store_set_property (GObject *object,
        switch (property_id) {
                case PROP_ACCOUNT_STORE:
                        templates_store_set_account_store (
-                               E_TEMPLATES_STORE (object),
+                               E_MAIL_TEMPLATES_STORE (object),
                                g_value_get_object (value));
                        return;
        }
@@ -1789,8 +1789,8 @@ templates_store_get_property (GObject *object,
                case PROP_ACCOUNT_STORE:
                        g_value_take_object (
                                value,
-                               e_templates_store_ref_account_store (
-                               E_TEMPLATES_STORE (object)));
+                               e_mail_templates_store_ref_account_store (
+                               E_MAIL_TEMPLATES_STORE (object)));
                        return;
        }
 
@@ -1800,12 +1800,12 @@ templates_store_get_property (GObject *object,
 static void
 templates_store_dispose (GObject *object)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        EMailAccountStore *account_store;
 
-       templates_store = E_TEMPLATES_STORE (object);
+       templates_store = E_MAIL_TEMPLATES_STORE (object);
 
-       account_store = e_templates_store_ref_account_store (templates_store);
+       account_store = e_mail_templates_store_ref_account_store (templates_store);
 
        if (account_store) {
                if (templates_store->priv->service_enabled_handler_id) {
@@ -1843,15 +1843,15 @@ templates_store_dispose (GObject *object)
        g_clear_object (&account_store);
 
        /* Chain up to parent's method. */
-       G_OBJECT_CLASS (e_templates_store_parent_class)->dispose (object);
+       G_OBJECT_CLASS (e_mail_templates_store_parent_class)->dispose (object);
 }
 
 static void
 templates_store_finalize (GObject *object)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
 
-       templates_store = E_TEMPLATES_STORE (object);
+       templates_store = E_MAIL_TEMPLATES_STORE (object);
 
        g_slist_free_full (templates_store->priv->stores, tmpl_store_data_unref);
        templates_store->priv->stores = NULL;
@@ -1862,25 +1862,25 @@ templates_store_finalize (GObject *object)
        g_mutex_clear (&templates_store->priv->busy_lock);
 
        /* Chain up to parent's method. */
-       G_OBJECT_CLASS (e_templates_store_parent_class)->finalize (object);
+       G_OBJECT_CLASS (e_mail_templates_store_parent_class)->finalize (object);
 }
 
 static void
 templates_store_constructed (GObject *object)
 {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        ESourceRegistry *registry;
        EMailAccountStore *account_store;
        EMailSession *session;
 
-       templates_store = E_TEMPLATES_STORE (object);
+       templates_store = E_MAIL_TEMPLATES_STORE (object);
 
        /* Chain up to parent's method. */
-       G_OBJECT_CLASS (e_templates_store_parent_class)->constructed (object);
+       G_OBJECT_CLASS (e_mail_templates_store_parent_class)->constructed (object);
 
        templates_store->priv->cancellable = g_cancellable_new ();
 
-       account_store = e_templates_store_ref_account_store (templates_store);
+       account_store = e_mail_templates_store_ref_account_store (templates_store);
        g_return_if_fail (account_store != NULL);
 
        session = e_mail_account_store_get_session (account_store);
@@ -1916,11 +1916,11 @@ templates_store_constructed (GObject *object)
 }
 
 static void
-e_templates_store_class_init (ETemplatesStoreClass *class)
+e_mail_templates_store_class_init (EMailTemplatesStoreClass *class)
 {
        GObjectClass *object_class;
 
-       g_type_class_add_private (class, sizeof (ETemplatesStorePrivate));
+       g_type_class_add_private (class, sizeof (EMailTemplatesStorePrivate));
 
        object_class = G_OBJECT_CLASS (class);
        object_class->set_property = templates_store_set_property;
@@ -1945,22 +1945,22 @@ e_templates_store_class_init (ETemplatesStoreClass *class)
                "changed",
                G_TYPE_FROM_CLASS (class),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ETemplatesStoreClass, changed),
+               G_STRUCT_OFFSET (EMailTemplatesStoreClass, changed),
                NULL, NULL, NULL,
                G_TYPE_NONE, 0, G_TYPE_NONE);
 }
 
 static void
-e_templates_store_init (ETemplatesStore *templates_store)
+e_mail_templates_store_init (EMailTemplatesStore *templates_store)
 {
-       templates_store->priv = G_TYPE_INSTANCE_GET_PRIVATE (templates_store, E_TYPE_TEMPLATES_STORE, 
ETemplatesStorePrivate);
+       templates_store->priv = G_TYPE_INSTANCE_GET_PRIVATE (templates_store, E_TYPE_MAIL_TEMPLATES_STORE, 
EMailTemplatesStorePrivate);
 
        g_mutex_init (&templates_store->priv->busy_lock);
        templates_store->priv->account_store_weakref = e_weak_ref_new (NULL);
 }
 
-ETemplatesStore *
-e_templates_store_ref_default (EMailAccountStore *account_store)
+EMailTemplatesStore *
+e_mail_templates_store_ref_default (EMailAccountStore *account_store)
 {
        static gpointer def_templates_store = NULL;
 
@@ -1969,7 +1969,7 @@ e_templates_store_ref_default (EMailAccountStore *account_store)
        if (def_templates_store) {
                g_object_ref (def_templates_store);
        } else {
-               def_templates_store = g_object_new (E_TYPE_TEMPLATES_STORE,
+               def_templates_store = g_object_new (E_TYPE_MAIL_TEMPLATES_STORE,
                        "account-store", account_store,
                        NULL);
 
@@ -1980,9 +1980,9 @@ e_templates_store_ref_default (EMailAccountStore *account_store)
 }
 
 EMailAccountStore *
-e_templates_store_ref_account_store (ETemplatesStore *templates_store)
+e_mail_templates_store_ref_account_store (EMailTemplatesStore *templates_store)
 {
-       g_return_val_if_fail (E_IS_TEMPLATES_STORE (templates_store), NULL);
+       g_return_val_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store), NULL);
 
        return g_weak_ref_get (templates_store->priv->account_store_weakref);
 }
@@ -2011,18 +2011,18 @@ tmpl_store_data_folder_has_messages_cb (GNode *node,
 }
 
 typedef struct _TmplActionData {
-       ETemplatesStore *templates_store; /* not referenced */
+       EMailTemplatesStore *templates_store; /* not referenced */
        CamelFolder *folder;
        const gchar *uid; /* from camel_pstring */
-       ETemplatesStoreActionFunc action_cb;
+       EMailTemplatesStoreActionFunc action_cb;
        gpointer action_cb_user_data;
 } TmplActionData;
 
 static TmplActionData *
-tmpl_action_data_new (ETemplatesStore *templates_store,
+tmpl_action_data_new (EMailTemplatesStore *templates_store,
                      CamelFolder *folder,
                      const gchar *uid,
-                     ETemplatesStoreActionFunc action_cb,
+                     EMailTemplatesStoreActionFunc action_cb,
                      gpointer action_cb_user_data)
 {
        TmplActionData *tad;
@@ -2063,20 +2063,19 @@ templates_store_action_activated_cb (GtkAction *action,
 }
 
 static void
-templates_store_add_to_menu_recurse (ETemplatesStore *templates_store,
+templates_store_add_to_menu_recurse (EMailTemplatesStore *templates_store,
                                     GNode *node,
                                     GtkUIManager *ui_manager,
                                     GtkActionGroup *action_group,
                                     const gchar *base_menu_path,
                                     guint merge_id,
-                                    ETemplatesStoreActionFunc action_cb,
+                                    EMailTemplatesStoreActionFunc action_cb,
                                     gpointer action_cb_user_data,
                                     gboolean with_folder_menu,
                                     guint *action_count)
 {
        TmplFolderData *tfd;
 
-       g_return_if_fail (E_IS_TEMPLATES_STORE (templates_store));
        g_return_if_fail (node != NULL);
 
        while (node) {
@@ -2152,14 +2151,14 @@ templates_store_add_to_menu_recurse (ETemplatesStore *templates_store,
 }
 
 void
-e_templates_store_build_menu (ETemplatesStore *templates_store,
-                             EShellView *shell_view,
-                             GtkUIManager *ui_manager,
-                             GtkActionGroup *action_group,
-                             const gchar *base_menu_path,
-                             guint merge_id,
-                             ETemplatesStoreActionFunc action_cb,
-                             gpointer action_cb_user_data)
+e_mail_templates_store_build_menu (EMailTemplatesStore *templates_store,
+                                  EShellView *shell_view,
+                                  GtkUIManager *ui_manager,
+                                  GtkActionGroup *action_group,
+                                  const gchar *base_menu_path,
+                                  guint merge_id,
+                                  EMailTemplatesStoreActionFunc action_cb,
+                                  gpointer action_cb_user_data)
 {
        GSList *link;
        GtkAction *action;
@@ -2169,7 +2168,7 @@ e_templates_store_build_menu (ETemplatesStore *templates_store,
        gchar *tmp_menu_path = NULL;
        gchar *action_name;
 
-       g_return_if_fail (E_IS_TEMPLATES_STORE (templates_store));
+       g_return_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store));
        g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
        g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager));
        g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
@@ -2278,3 +2277,180 @@ e_templates_store_build_menu (ETemplatesStore *templates_store,
 
        g_free (tmp_menu_path);
 }
+
+static void
+templates_store_add_to_tree_store_recurse (EMailTemplatesStore *templates_store,
+                                          GNode *node,
+                                          GtkTreeStore *tree_store,
+                                          GtkTreeIter *parent,
+                                          gboolean with_folder_name,
+                                          const gchar *find_folder_uri,
+                                          const gchar *find_message_uid,
+                                          gboolean *out_found_message,
+                                          GtkTreeIter *out_found_iter,
+                                          gboolean *out_found_first_message,
+                                          GtkTreeIter *out_found_first_iter)
+{
+       TmplFolderData *tfd;
+
+       g_return_if_fail (node != NULL);
+       g_return_if_fail (tree_store != NULL);
+
+       while (node) {
+               tfd = node->data;
+               if (tfd) {
+                       tmpl_folder_data_lock (tfd);
+
+                       if (tfd->folder) {
+                               GtkTreeIter *pparent = parent, iparent, iter;
+                               GSList *link;
+                               gboolean is_the_folder = FALSE;
+
+                               if (out_found_message && !*out_found_message && out_found_iter && 
find_folder_uri && *find_folder_uri) {
+                                       gchar *folder_uri;
+
+                                       folder_uri = e_mail_folder_uri_from_folder (tfd->folder);
+                                       is_the_folder = g_strcmp0 (folder_uri, find_folder_uri) == 0;
+                                       g_free (folder_uri);
+                               }
+
+                               if (with_folder_name) {
+                                       gtk_tree_store_append (tree_store, &iparent, pparent);
+                                       gtk_tree_store_set (tree_store, &iparent,
+                                               E_MAIL_TEMPLATES_STORE_COLUMN_DISPLAY_NAME, 
camel_folder_get_display_name (tfd->folder),
+                                               -1);
+
+                                       pparent = &iparent;
+                               }
+
+                               if (node->children) {
+                                       templates_store_add_to_tree_store_recurse (templates_store, 
node->children, tree_store, pparent,
+                                               TRUE, find_folder_uri, find_message_uid, out_found_message, 
out_found_iter,
+                                               out_found_first_message, out_found_first_iter);
+                               }
+
+                               for (link = tfd->messages; link; link = g_slist_next (link)) {
+                                       TmplMessageData *tmd = link->data;
+
+                                       if (tmd && tmd->uid && tmd->subject) {
+                                               gtk_tree_store_append (tree_store, &iter, pparent);
+                                               gtk_tree_store_set (tree_store, &iter,
+                                                       E_MAIL_TEMPLATES_STORE_COLUMN_DISPLAY_NAME, 
tmd->subject,
+                                                       E_MAIL_TEMPLATES_STORE_COLUMN_FOLDER, tfd->folder,
+                                                       E_MAIL_TEMPLATES_STORE_COLUMN_MESSAGE_UID, tmd->uid,
+                                                       -1);
+
+                                               if (!*out_found_first_message) {
+                                                       *out_found_first_message = TRUE;
+                                                       *out_found_first_iter = iter;
+                                               }
+
+                                               if (is_the_folder && out_found_message && 
!*out_found_message) {
+                                                       *out_found_message = g_strcmp0 (tmd->uid, 
find_message_uid) == 0;
+
+                                                       if (*out_found_message && out_found_iter)
+                                                               *out_found_iter = iter;
+                                               }
+                                       }
+                               }
+                       }
+
+                       tmpl_folder_data_unlock (tfd);
+               }
+
+               node = node->next;
+       }
+}
+
+GtkTreeStore *
+e_mail_templates_store_build_model (EMailTemplatesStore *templates_store,
+                                   const gchar *find_folder_uri,
+                                   const gchar *find_message_uid,
+                                   gboolean *out_found_message,
+                                   GtkTreeIter *out_found_iter)
+{
+       GtkTreeStore *tree_store;
+       GSList *link;
+       gint multiple_accounts = 0;
+       gboolean found_first_message = FALSE;
+       GtkTreeIter found_first_iter;
+
+       g_return_val_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store), NULL);
+
+       if (out_found_message)
+               *out_found_message = FALSE;
+
+       tree_store = gtk_tree_store_new (E_MAIL_TEMPLATES_STORE_N_COLUMNS,
+               G_TYPE_STRING,          /* E_MAIL_TEMPLATES_STORE_COLUMN_DISPLAY_NAME */
+               CAMEL_TYPE_FOLDER,      /* E_MAIL_TEMPLATES_STORE_COLUMN_FOLDER */
+               G_TYPE_STRING);         /* E_MAIL_TEMPLATES_STORE_COLUMN_MESSAGE_UID */
+
+       templates_store_lock (templates_store);
+
+       for (link = templates_store->priv->stores; link && multiple_accounts <= 1; link = g_slist_next 
(link)) {
+               TmplStoreData *tsd = link->data;
+
+               if (!tsd)
+                       continue;
+
+               tmpl_store_data_lock (tsd);
+
+               if (tsd->folders && tsd->folders->children) {
+                       CamelStore *store;
+
+                       store = g_weak_ref_get (tsd->store_weakref);
+                       if (store) {
+                               g_node_traverse (tsd->folders, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+                                       tmpl_store_data_folder_has_messages_cb, &multiple_accounts);
+                       }
+
+                       g_clear_object (&store);
+               }
+
+               tmpl_store_data_unlock (tsd);
+       }
+
+       for (link = templates_store->priv->stores; link && multiple_accounts > 0; link = g_slist_next (link)) 
{
+               TmplStoreData *tsd = link->data;
+
+               if (!tsd)
+                       continue;
+
+               tmpl_store_data_lock (tsd);
+
+               if (tsd->folders && tsd->folders->children) {
+                       CamelStore *store;
+
+                       store = g_weak_ref_get (tsd->store_weakref);
+                       if (store) {
+                               GtkTreeIter *pparent = NULL, parent;
+
+                               if (multiple_accounts > 1) {
+                                       gtk_tree_store_append (tree_store, &parent, NULL);
+                                       gtk_tree_store_set (tree_store, &parent,
+                                               E_MAIL_TEMPLATES_STORE_COLUMN_DISPLAY_NAME, 
camel_service_get_display_name (CAMEL_SERVICE (store)),
+                                               -1);
+
+                                       pparent = &parent;
+                               }
+
+                               templates_store_add_to_tree_store_recurse (templates_store, 
tsd->folders->children, tree_store, pparent, FALSE,
+                                       find_folder_uri, find_message_uid, out_found_message, out_found_iter,
+                                       &found_first_message, &found_first_iter);
+                       }
+
+                       g_clear_object (&store);
+               }
+
+               tmpl_store_data_unlock (tsd);
+       }
+
+       templates_store_unlock (templates_store);
+
+       if (out_found_message && !*out_found_message && out_found_iter) {
+               *out_found_message = found_first_message;
+               *out_found_iter = found_first_iter;
+       }
+
+       return tree_store;
+}
diff --git a/src/mail/e-mail-templates-store.h b/src/mail/e-mail-templates-store.h
new file mode 100644
index 0000000..f954257
--- /dev/null
+++ b/src/mail/e-mail-templates-store.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef E_MAIL_TEMPLATES_STORE_H
+#define E_MAIL_TEMPLATES_STORE_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <camel/camel.h>
+#include <libedataserver/libedataserver.h>
+#include <libemail-engine/libemail-engine.h>
+#include <mail/e-mail-account-store.h>
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_TEMPLATES_STORE \
+       (e_mail_templates_store_get_type ())
+#define E_MAIL_TEMPLATES_STORE(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_TEMPLATES_STORE, EMailTemplatesStore))
+#define E_MAIL_TEMPLATES_STORE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_TEMPLATES_STORE, EMailTemplatesStoreClass))
+#define E_IS_MAIL_TEMPLATES_STORE(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_TEMPLATES_STORE))
+#define E_IS_MAIL_TEMPLATES_STORE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_TEMPLATES_STORE))
+#define E_MAIL_TEMPLATES_STORE_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_TEMPLATES_STORE, EMailTemplatesStoreClass))
+
+G_BEGIN_DECLS
+
+enum {
+       E_MAIL_TEMPLATES_STORE_COLUMN_DISPLAY_NAME = 0, /* gchar * */
+       E_MAIL_TEMPLATES_STORE_COLUMN_FOLDER,           /* CamelFolder * */
+       E_MAIL_TEMPLATES_STORE_COLUMN_MESSAGE_UID,              /* gchar * */
+       E_MAIL_TEMPLATES_STORE_N_COLUMNS
+};
+
+typedef struct _EMailTemplatesStore EMailTemplatesStore;
+typedef struct _EMailTemplatesStoreClass EMailTemplatesStoreClass;
+typedef struct _EMailTemplatesStorePrivate EMailTemplatesStorePrivate;
+
+/**
+ * EMailTemplatesStore:
+ *
+ * Contains only private data that should be read and manipulated using
+ * the functions below.
+ **/
+struct _EMailTemplatesStore {
+       GObject parent;
+       EMailTemplatesStorePrivate *priv;
+};
+
+struct _EMailTemplatesStoreClass {
+       GObjectClass parent_class;
+
+       /* Signals */
+       void            (*changed)              (EMailTemplatesStore *templates_store);
+};
+
+typedef void   (* EMailTemplatesStoreActionFunc)       (EMailTemplatesStore *templates_store,
+                                                CamelFolder *folder,
+                                                const gchar *message_uid,
+                                                gpointer user_data);
+
+GType          e_mail_templates_store_get_type (void) G_GNUC_CONST;
+EMailTemplatesStore *
+               e_mail_templates_store_ref_default
+                                               (EMailAccountStore *account_store);
+EMailAccountStore *
+               e_mail_templates_store_ref_account_store
+                                               (EMailTemplatesStore *templates_store);
+void           e_mail_templates_store_build_menu
+                                               (EMailTemplatesStore *templates_store,
+                                                EShellView *shell_view,
+                                                GtkUIManager *ui_manager,
+                                                GtkActionGroup *action_group,
+                                                const gchar *base_menu_path,
+                                                guint merge_id,
+                                                EMailTemplatesStoreActionFunc action_cb,
+                                                gpointer action_cb_user_data);
+GtkTreeStore * e_mail_templates_store_build_model
+                                               (EMailTemplatesStore *templates_store,
+                                                const gchar *find_folder_uri,
+                                                const gchar *find_message_uid,
+                                                gboolean *out_found_message,
+                                                GtkTreeIter *out_found_iter);
+
+G_END_DECLS
+
+#endif /* E_MAIL_TEMPLATES_STORE_H */
diff --git a/src/mail/e-mail-templates.c b/src/mail/e-mail-templates.c
new file mode 100644
index 0000000..8d3bb7a
--- /dev/null
+++ b/src/mail/e-mail-templates.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2008 - Diego Escalante Urrelo
+ * Copyright (C) 2018 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *             Diego Escalante Urrelo <diegoe gnome org>
+ *             Bharath Acharya <abharath novell com>
+ */
+
+#include "evolution-config.h"
+
+#include <string.h>
+
+#include "e-util/e-util.h"
+
+#include "e-mail-templates.h"
+
+/* Replaces $ORIG[variable] in given template by given replacement from the original message */
+static void
+replace_template_variable (GString *text,
+                           const gchar *variable,
+                           const gchar *replacement)
+{
+       const gchar *p, *next;
+       GString *str;
+       gint find_len;
+       gchar *find;
+
+       g_return_if_fail (text != NULL);
+       g_return_if_fail (variable != NULL);
+       g_return_if_fail (*variable);
+
+       find = g_strconcat ("$ORIG[", variable, "]", NULL);
+
+       find_len = strlen (find);
+       str = g_string_new ("");
+       p = text->str;
+       while (next = e_util_strstrcase (p, find), next) {
+               if (p < next)
+                       g_string_append_len (str, p, next - p);
+               if (replacement && *replacement)
+                       g_string_append (str, replacement);
+               p = next + find_len;
+       }
+       g_string_append (str, p);
+
+       g_string_assign (text, str->str);
+
+       g_string_free (str, TRUE);
+       g_free (find);
+}
+
+static void
+replace_email_addresses (GString *template,
+                         CamelInternetAddress *internet_address,
+                         const gchar *variable)
+{
+       gint address_index = 0;
+       GString *emails = g_string_new ("");
+       const gchar *address_name, *address_email;
+
+       g_return_if_fail (template);
+       g_return_if_fail (internet_address);
+       g_return_if_fail (variable);
+
+       while (camel_internet_address_get (internet_address, address_index, &address_name, &address_email)) {
+               gchar *address = camel_internet_address_format_address (address_name, address_email);
+
+               if (address_index > 0)
+                       g_string_append_printf (emails, ", %s", address);
+               else
+                       g_string_append_printf (emails, "%s", address);
+
+               address_index++;
+               g_free (address);
+       }
+       replace_template_variable (template, variable, emails->str);
+       g_string_free (emails, TRUE);
+}
+
+static CamelMimePart *
+fill_template (CamelMimeMessage *message,
+               CamelMimePart *template)
+{
+       const CamelNameValueArray *headers;
+       CamelContentType *ct;
+       CamelStream *stream;
+       CamelMimePart *return_part;
+       CamelMimePart *message_part = NULL;
+       CamelDataWrapper *dw;
+       CamelInternetAddress *internet_address;
+       GString *template_body;
+       GByteArray *byte_array;
+       gint i;
+       guint jj, len;
+       gboolean message_html, template_html;
+
+       ct = camel_mime_part_get_content_type (template);
+       template_html = ct && camel_content_type_is (ct, "text", "html");
+
+       message_html = FALSE;
+       /* When template is html, then prefer HTML part of the original message. Otherwise go for plaintext */
+       dw = camel_medium_get_content (CAMEL_MEDIUM (message));
+       if (CAMEL_IS_MULTIPART (dw)) {
+               CamelMultipart *multipart = CAMEL_MULTIPART (dw);
+
+               for (i = 0; i < camel_multipart_get_number (multipart); i++) {
+                       CamelMimePart *part = camel_multipart_get_part (multipart, i);
+                       CamelContentType *ct = camel_mime_part_get_content_type (part);
+
+                       if (!ct)
+                               continue;
+
+                       if (camel_content_type_is (ct, "text", "html") && template_html) {
+                               message_part = camel_multipart_get_part (multipart, i);
+                               message_html = TRUE;
+                               break;
+                       } else if (camel_content_type_is (ct, "text", "plain") && message_html == FALSE) {
+                               message_part = camel_multipart_get_part (multipart, i);
+                       }
+               }
+       } else
+               message_part = CAMEL_MIME_PART (message);
+
+       /* Get content of the template */
+       stream = camel_stream_mem_new ();
+       camel_data_wrapper_decode_to_stream_sync (camel_medium_get_content (CAMEL_MEDIUM (template)), stream, 
NULL, NULL);
+       camel_stream_flush (stream, NULL, NULL);
+       byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
+       template_body = g_string_new_len ((gchar *) byte_array->data, byte_array->len);
+       g_object_unref (stream);
+
+       /* Replace all $ORIG[header_name] by respective values */
+       headers = camel_medium_get_headers (CAMEL_MEDIUM (message));
+       len = camel_name_value_array_get_length (headers);
+       for (jj = 0; jj < len; jj++) {
+               const gchar *header_name = NULL, *header_value = NULL;
+
+               if (!camel_name_value_array_get (headers, jj, &header_name, &header_value) ||
+                   !header_name)
+                       continue;
+
+               if (g_ascii_strncasecmp (header_name, "content-", 8) != 0 &&
+                   g_ascii_strcasecmp (header_name, "to") != 0 &&
+                   g_ascii_strcasecmp (header_name, "cc") != 0 &&
+                   g_ascii_strcasecmp (header_name, "bcc") != 0 &&
+                   g_ascii_strcasecmp (header_name, "from") != 0 &&
+                   g_ascii_strcasecmp (header_name, "subject") != 0)
+                       replace_template_variable (template_body, header_name, header_value);
+       }
+
+       /* Now manually replace the *subject* header. The header->value for subject header could be
+        * base64 encoded, so let camel_mime_message to decode it for us if needed */
+       replace_template_variable (template_body, "subject", camel_mime_message_get_subject (message));
+
+       /* Replace TO and FROM modifiers. */
+       internet_address = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO);
+       replace_email_addresses (template_body, internet_address, "to");
+
+       internet_address = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC);
+       replace_email_addresses (template_body, internet_address, "cc");
+
+       internet_address = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_BCC);
+       replace_email_addresses (template_body, internet_address, "bcc");
+
+       internet_address = camel_mime_message_get_from (message);
+       replace_email_addresses (template_body, internet_address, "from");
+
+       /* Now extract body of the original message and replace the $ORIG[body] modifier in template */
+       if (message_part && e_util_strstrcase (template_body->str, "$ORIG[body]")) {
+               GString *message_body;
+               CamelStream *mem_stream;
+
+               stream = camel_stream_mem_new ();
+               mem_stream = stream;
+
+               ct = camel_mime_part_get_content_type (message_part);
+               if (ct) {
+                       const gchar *charset = camel_content_type_param (ct, "charset");
+                       if (charset && *charset) {
+                               CamelMimeFilter *filter = camel_mime_filter_charset_new (charset, "UTF-8");
+                               if (filter) {
+                                       CamelStream *filtered = camel_stream_filter_new (stream);
+
+                                       if (filtered) {
+                                               camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered), 
filter);
+                                               g_object_unref (stream);
+                                               stream = filtered;
+                                       }
+
+                                       g_object_unref (filter);
+                               }
+                       }
+               }
+
+               camel_data_wrapper_decode_to_stream_sync (camel_medium_get_content (CAMEL_MEDIUM 
(message_part)), stream, NULL, NULL);
+               camel_stream_flush (stream, NULL, NULL);
+               byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem_stream));
+               message_body = g_string_new_len ((gchar *) byte_array->data, byte_array->len);
+               g_object_unref (stream);
+
+               if (template_html && !message_html) {
+                       gchar *html = camel_text_to_html (
+                               message_body->str,
+                               CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+                               CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+                               CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+                               CAMEL_MIME_FILTER_TOHTML_MARK_CITATION |
+                               CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES, 0);
+                       g_string_assign (message_body, html);
+                       g_free (html);
+               } else if (!template_html && message_html) {
+                       g_string_prepend (message_body, "<pre>");
+                       g_string_append (message_body, "</pre>");
+               } /* Other cases should not occur. And even if they happen to do, there's nothing we can 
really do about it */
+
+               replace_template_variable (template_body, "body", message_body->str);
+               g_string_free (message_body, TRUE);
+       } else {
+               replace_template_variable (template_body, "body", "");
+       }
+
+       return_part = camel_mime_part_new ();
+
+       if (template_html)
+               camel_mime_part_set_content (return_part, template_body->str, template_body->len, 
"text/html");
+       else
+               camel_mime_part_set_content (return_part, template_body->str, template_body->len, 
"text/plain");
+
+       g_string_free (template_body, TRUE);
+
+       return return_part;
+}
+
+static CamelMimePart *
+find_template_part_in_multipart (CamelMultipart *multipart,
+                                CamelMultipart *new_multipart)
+{
+       CamelMimePart *template_part = NULL;
+       gint ii;
+
+       for (ii = 0; ii < camel_multipart_get_number (multipart); ii++) {
+               CamelMimePart *part = camel_multipart_get_part (multipart, ii);
+               CamelContentType *ct = camel_mime_part_get_content_type (part);
+
+               if (!template_part && ct && camel_content_type_is (ct, "multipart", "*")) {
+                       CamelDataWrapper *dw;
+
+                       dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+                       template_part = (dw && CAMEL_IS_MULTIPART (dw)) ?
+                               find_template_part_in_multipart (CAMEL_MULTIPART (dw), new_multipart) : NULL;
+
+                       if (!template_part) {
+                               /* Copy any other parts (attachments...) to the output message */
+                               camel_mime_part_set_disposition (part, "attachment");
+                               camel_multipart_add_part (new_multipart, part);
+                       }
+               } else if (ct && camel_content_type_is (ct, "text", "html")) {
+                       template_part = part;
+               } else if (ct && camel_content_type_is (ct, "text", "plain") && !template_part) {
+                       template_part = part;
+               } else {
+                       /* Copy any other parts (attachments...) to the output message */
+                       camel_mime_part_set_disposition (part, "attachment");
+                       camel_multipart_add_part (new_multipart, part);
+               }
+       }
+
+       return template_part;
+}
+
+CamelMimeMessage *
+e_mail_templates_apply_sync (CamelMimeMessage *source_message,
+                            CamelFolder *templates_folder,
+                            const gchar *templates_message_uid,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       CamelMimeMessage *template_message, *result_message = NULL;
+       CamelMultipart *new_multipart;
+       CamelDataWrapper *dw;
+       const CamelNameValueArray *headers;
+       CamelMimePart *template_part = NULL;
+       guint ii, len;
+
+       g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (source_message), NULL);
+       g_return_val_if_fail (CAMEL_IS_FOLDER (templates_folder), NULL);
+       g_return_val_if_fail (templates_message_uid != NULL, NULL);
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return NULL;
+
+       template_message = camel_folder_get_message_sync (templates_folder, templates_message_uid, 
cancellable, error);
+       if (!template_message)
+               return NULL;
+
+       result_message = camel_mime_message_new ();
+       new_multipart = camel_multipart_new ();
+       camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (new_multipart), "multipart/alternative");
+       camel_multipart_set_boundary (new_multipart, NULL);
+
+       dw = camel_medium_get_content (CAMEL_MEDIUM (template_message));
+       /* If template is a multipart, then try to use HTML. When no HTML part is available, use plaintext. 
Every other
+        * add as an attachment */
+       if (CAMEL_IS_MULTIPART (dw)) {
+               template_part = find_template_part_in_multipart (CAMEL_MULTIPART (dw), new_multipart);
+       } else {
+               CamelContentType *ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (template_message));
+
+               if (ct && (camel_content_type_is (ct, "text", "html") ||
+                   camel_content_type_is (ct, "text", "plain"))) {
+                       template_part = CAMEL_MIME_PART (template_message);
+               }
+       }
+
+       g_warn_if_fail (template_part != NULL);
+
+       if (template_part) {
+               CamelMimePart *out_part = NULL;
+
+               /* Here replace all the modifiers in template body by values
+                  from message and return the newly created part */
+               out_part = fill_template (source_message, template_part);
+
+               /* Assigning part directly to mime_message causes problem with
+                  "Content-type" header displaying in the HTML message (camel parsing bug?) */
+               camel_multipart_add_part (new_multipart, out_part);
+               g_object_unref (out_part);
+       }
+
+       camel_medium_set_content (CAMEL_MEDIUM (result_message), CAMEL_DATA_WRAPPER (new_multipart));
+
+       /* Add the headers from the message we are replying to, so CC and that
+        * stuff is preserved. Also replace any $ORIG[header-name] modifiers ignoring
+        * 'content-*' headers */
+       headers = camel_medium_dup_headers (CAMEL_MEDIUM (source_message));
+       len = camel_name_value_array_get_length (headers);
+       for (ii = 0; ii < len; ii++) {
+               const gchar *header_name = NULL, *header_value = NULL;
+
+               if (!camel_name_value_array_get (headers, ii, &header_name, &header_value) ||
+                   !header_name)
+                       continue;
+
+               if (g_ascii_strncasecmp (header_name, "content-", 8) != 0 &&
+                   g_ascii_strcasecmp (header_name, "from") != 0) {
+                       gchar *new_header_value = NULL;
+
+                       /* Some special handling of the 'subject' header */
+                       if (g_ascii_strncasecmp (header_name, "subject", 7) == 0) {
+                               GString *subject = g_string_new (camel_mime_message_get_subject 
(template_message));
+                               guint jj;
+
+                               /* Now replace all possible $ORIG[]s in the subject line by values from 
original message */
+                               for (jj = 0; jj < len; jj++) {
+                                       const gchar *m_header_name = NULL, *m_header_value = NULL;
+
+                                       if (camel_name_value_array_get (headers, jj, &m_header_name, 
&m_header_value) &&
+                                           m_header_name &&
+                                           g_ascii_strncasecmp (m_header_name, "content-", 8) != 0 &&
+                                           g_ascii_strcasecmp (m_header_name, "subject") != 0)
+                                               replace_template_variable (subject, m_header_name, 
m_header_value);
+                               }
+                               /* Now replace $ORIG[subject] variable, handling possible base64 encryption */
+                               replace_template_variable (
+                                       subject, "subject",
+                                       camel_mime_message_get_subject (source_message));
+                               new_header_value = g_string_free (subject, FALSE);
+                       }
+
+                       camel_medium_add_header (CAMEL_MEDIUM (result_message), header_name, new_header_value 
? new_header_value : header_value);
+
+                       g_free (new_header_value);
+               }
+       }
+
+       /* Set the To: field to the same To: field of the message we are replying to. */
+       camel_mime_message_set_recipients (
+               result_message, CAMEL_RECIPIENT_TYPE_TO,
+               camel_mime_message_get_reply_to (source_message) ? camel_mime_message_get_reply_to 
(source_message) :
+               camel_mime_message_get_from (source_message));
+
+       /* Copy the CC and BCC from the template.*/
+       camel_mime_message_set_recipients (result_message, CAMEL_RECIPIENT_TYPE_CC,
+               camel_mime_message_get_recipients (template_message, CAMEL_RECIPIENT_TYPE_CC));
+
+       camel_mime_message_set_recipients (result_message, CAMEL_RECIPIENT_TYPE_BCC,
+               camel_mime_message_get_recipients (template_message, CAMEL_RECIPIENT_TYPE_BCC));
+
+       g_clear_object (&template_message);
+       g_clear_object (&new_multipart);
+
+       return result_message;
+}
+
+typedef struct _AsyncContext {
+       CamelMimeMessage *source_message;
+       CamelFolder *templates_folder;
+       gchar *templates_message_uid;
+       CamelMimeMessage *result_message;
+} AsyncContext;
+
+static void
+async_context_free (gpointer ptr)
+{
+       AsyncContext *context = ptr;
+
+       if (context) {
+               g_clear_object (&context->source_message);
+               g_clear_object (&context->templates_folder);
+               g_clear_object (&context->result_message);
+               g_free (context->templates_message_uid);
+               g_free (context);
+       }
+}
+
+static void
+e_mail_templates_apply_thread (ESimpleAsyncResult *simple,
+                              gpointer source_object,
+                              GCancellable *cancellable)
+{
+       AsyncContext *context;
+       GError *local_error = NULL;
+
+       context = e_simple_async_result_get_op_pointer (simple);
+       g_return_if_fail (context != NULL);
+
+       context->result_message = e_mail_templates_apply_sync (context->source_message,
+               context->templates_folder, context->templates_message_uid, cancellable, &local_error);
+
+       if (local_error)
+               e_simple_async_result_take_error (simple, local_error);
+}
+
+void
+e_mail_templates_apply (CamelMimeMessage *source_message,
+                       CamelFolder *templates_folder,
+                       const gchar *templates_message_uid,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+       ESimpleAsyncResult *simple;
+       AsyncContext *context;
+
+       g_return_if_fail (CAMEL_IS_MIME_MESSAGE (source_message));
+       g_return_if_fail (CAMEL_IS_FOLDER (templates_folder));
+       g_return_if_fail (templates_message_uid != NULL);
+       g_return_if_fail (callback != NULL);
+
+       context = g_new0 (AsyncContext, 1);
+       context->source_message = g_object_ref (source_message);
+       context->templates_folder = g_object_ref (templates_folder);
+       context->templates_message_uid = g_strdup (templates_message_uid);
+       context->result_message = NULL;
+
+       simple = e_simple_async_result_new (G_OBJECT (source_message), callback,
+               user_data, e_mail_templates_apply);
+
+       e_simple_async_result_set_op_pointer (simple, context, (GDestroyNotify) async_context_free);
+
+       e_simple_async_result_run_in_thread (simple, G_PRIORITY_DEFAULT, e_mail_templates_apply_thread, 
cancellable);
+
+       g_object_unref (simple);
+}
+
+CamelMimeMessage *
+e_mail_templates_apply_finish (GObject *source_object,
+                              GAsyncResult *result,
+                              GError **error)
+{
+       ESimpleAsyncResult *simple;
+       AsyncContext *context;
+
+       g_return_val_if_fail (e_simple_async_result_is_valid (result, source_object, e_mail_templates_apply), 
NULL);
+
+       simple = E_SIMPLE_ASYNC_RESULT (result);
+       context = e_simple_async_result_get_op_pointer (simple);
+
+       if (e_simple_async_result_propagate_error (simple, error))
+               return NULL;
+
+       return context->result_message ? g_object_ref (context->result_message) : NULL;
+}
diff --git a/src/mail/e-mail-templates.h b/src/mail/e-mail-templates.h
new file mode 100644
index 0000000..348fb11
--- /dev/null
+++ b/src/mail/e-mail-templates.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2008 - Diego Escalante Urrelo
+ * Copyright (C) 2018 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *             Diego Escalante Urrelo <diegoe gnome org>
+ *             Bharath Acharya <abharath novell com>
+ */
+
+#ifndef E_MAIL_TEMPLATES_H
+#define E_MAIL_TEMPLATES_H
+
+#include <camel/camel.h>
+
+G_BEGIN_DECLS
+
+CamelMimeMessage *
+               e_mail_templates_apply_sync     (CamelMimeMessage *source_message,
+                                                CamelFolder *templates_folder,
+                                                const gchar *templates_message_uid,
+                                                GCancellable *cancellable,
+                                                GError **error);
+void           e_mail_templates_apply          (CamelMimeMessage *source_message,
+                                                CamelFolder *templates_folder,
+                                                const gchar *templates_message_uid,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+CamelMimeMessage *
+               e_mail_templates_apply_finish   (GObject *source_object,
+                                                GAsyncResult *result,
+                                                GError **error);
+
+G_END_DECLS
+
+#endif /* E_MAIL_TEMPLATES_H */
diff --git a/src/mail/em-composer-utils.c b/src/mail/em-composer-utils.c
index c710512..2aaa369 100644
--- a/src/mail/em-composer-utils.c
+++ b/src/mail/em-composer-utils.c
@@ -43,6 +43,8 @@
 
 #include "e-mail-printer.h"
 #include "e-mail-ui-session.h"
+#include "e-mail-templates.h"
+#include "e-mail-templates-store.h"
 #include "em-utils.h"
 #include "em-composer-utils.h"
 #include "em-folder-selector.h"
@@ -2668,64 +2670,58 @@ em_utils_camel_address_to_destination (CamelInternetAddress *iaddr)
        return destv;
 }
 
-static void
-reply_setup_composer (EMsgComposer *composer,
-                     CamelMimeMessage *message,
-                     const gchar *identity_uid,
-                     const gchar *identity_name,
-                     const gchar *identity_address,
-                     CamelInternetAddress *to,
-                     CamelInternetAddress *cc,
-                     CamelFolder *folder,
-                     const gchar *message_uid,
-                     CamelNNTPAddress *postto)
+static gchar *
+emcu_construct_reply_subject (const gchar *source_subject)
 {
-       gchar *message_id, *references;
-       EDestination **tov, **ccv;
-       EComposerHeaderTable *table;
-       CamelMedium *medium;
-       gchar *subject;
-
-       g_return_if_fail (E_IS_MSG_COMPOSER (composer));
-       g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
-
-       e_msg_composer_set_is_reply_or_forward (composer, TRUE);
-
-       if (to != NULL)
-               g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (to));
+       gchar *res;
 
-       if (cc != NULL)
-               g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (cc));
-
-       /* construct the tov/ccv */
-       tov = em_utils_camel_address_to_destination (to);
-       ccv = em_utils_camel_address_to_destination (cc);
-
-       /* Set the subject of the new message. */
-       if ((subject = (gchar *) camel_mime_message_get_subject (message))) {
+       if (source_subject) {
                GSettings *settings;
                gboolean skip_len = -1;
 
-               if (em_utils_is_re_in_subject (subject, &skip_len, NULL, NULL) && skip_len > 0)
-                       subject = subject + skip_len;
+               if (em_utils_is_re_in_subject (source_subject, &skip_len, NULL, NULL) && skip_len > 0)
+                       source_subject = source_subject + skip_len;
 
                settings = e_util_ref_settings ("org.gnome.evolution.mail");
                if (g_settings_get_boolean (settings, "composer-use-localized-fwd-re")) {
                        /* Translators: This is a reply attribution in the message reply subject. The %s is 
replaced with the subject of the original message. Both 'Re'-s in the 'reply-attribution' translation context 
should translate into the same string, the same as the ':' separator. */
-                       subject = g_strdup_printf (C_("reply-attribution", "Re: %s"), subject);
+                       res = g_strdup_printf (C_("reply-attribution", "Re: %s"), source_subject);
                } else {
                        /* Do not localize this string */
-                       subject = g_strdup_printf ("Re: %s", subject);
+                       res = g_strdup_printf ("Re: %s", source_subject);
                }
                g_clear_object (&settings);
        } else {
-               subject = g_strdup ("");
+               res = g_strdup ("");
        }
 
+       return res;
+}
+
+static void
+reply_setup_composer_recipients (EMsgComposer *composer,
+                                CamelInternetAddress *to,
+                                CamelInternetAddress *cc,
+                                CamelFolder *folder,
+                                const gchar *message_uid,
+                                CamelNNTPAddress *postto)
+{
+       EComposerHeaderTable *table;
+       EDestination **tov, **ccv;
+
+       g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+       if (to != NULL)
+               g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (to));
+
+       if (cc != NULL)
+               g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (cc));
+
+       /* Construct the tov/ccv */
+       tov = em_utils_camel_address_to_destination (to);
+       ccv = em_utils_camel_address_to_destination (cc);
+
        table = e_msg_composer_get_header_table (composer);
-       e_composer_header_table_set_subject (table, subject);
        e_composer_header_table_set_destinations_to (table, tov);
-       e_composer_header_table_set_identity_uid (table, identity_uid, identity_name, identity_address);
 
        /* Add destinations instead of setting, so we don't remove
         * automatic CC addresses that have already been added. */
@@ -2733,9 +2729,8 @@ reply_setup_composer (EMsgComposer *composer,
 
        e_destination_freev (tov);
        e_destination_freev (ccv);
-       g_free (subject);
 
-       /* add post-to, if nessecary */
+       /* Add post-to, if necessary */
        if (postto && camel_address_length ((CamelAddress *) postto)) {
                CamelFolder *use_folder = folder, *temp_folder = NULL;
                gchar *store_url = NULL;
@@ -2773,6 +2768,46 @@ reply_setup_composer (EMsgComposer *composer,
                g_free (store_url);
                g_clear_object (&temp_folder);
        }
+}
+
+static void
+reply_setup_composer (EMsgComposer *composer,
+                     CamelMimeMessage *message,
+                     const gchar *identity_uid,
+                     const gchar *identity_name,
+                     const gchar *identity_address,
+                     CamelInternetAddress *to,
+                     CamelInternetAddress *cc,
+                     CamelFolder *folder,
+                     const gchar *message_uid,
+                     CamelNNTPAddress *postto)
+{
+       gchar *message_id, *references;
+       EComposerHeaderTable *table;
+       CamelMedium *medium;
+       gchar *subject;
+
+       g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+       g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+       e_msg_composer_set_is_reply_or_forward (composer, TRUE);
+
+       if (to != NULL)
+               g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (to));
+
+       if (cc != NULL)
+               g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (cc));
+
+       reply_setup_composer_recipients (composer, to, cc, folder, message_uid, postto);
+
+       /* Set the subject of the new message. */
+       subject = emcu_construct_reply_subject (camel_mime_message_get_subject (message));
+
+       table = e_msg_composer_get_header_table (composer);
+       e_composer_header_table_set_subject (table, subject);
+       e_composer_header_table_set_identity_uid (table, identity_uid, identity_name, identity_address);
+
+       g_free (subject);
 
        /* Add In-Reply-To and References. */
 
@@ -3566,9 +3601,722 @@ emcu_folder_is_inbox (CamelFolder *folder)
        return is_inbox;
 }
 
+typedef struct _AltReplyContext {
+       EShell *shell;
+       EAlertSink *alert_sink;
+       CamelMimeMessage *source_message;
+       CamelFolder *folder;
+       gchar *message_uid;
+       CamelMimeMessage *new_message; /* When processed with a template */
+       EMailPartList *source;
+       EMailReplyType type;
+       EMailReplyStyle style;
+       guint32 flags;
+       gboolean template_preserve_subject;
+} AltReplyContext;
+
+static void
+alt_reply_context_free (gpointer ptr)
+{
+       AltReplyContext *context = ptr;
+
+       if (context) {
+               g_clear_object (&context->shell);
+               g_clear_object (&context->alert_sink);
+               g_clear_object (&context->source_message);
+               g_clear_object (&context->folder);
+               g_clear_object (&context->source);
+               g_clear_object (&context->new_message);
+               g_free (context->message_uid);
+               g_free (context);
+       }
+}
+
+static void
+alt_reply_composer_created_cb (GObject *source_object,
+                              GAsyncResult *result,
+                              gpointer user_data)
+{
+       AltReplyContext *context = user_data;
+       EMsgComposer *composer;
+       GError *error = NULL;
+
+       g_return_if_fail (context != NULL);
+
+       composer = e_msg_composer_new_finish (result, &error);
+
+       if (composer) {
+               EContentEditor *cnt_editor;
+
+               cnt_editor = e_html_editor_get_content_editor (e_msg_composer_get_editor (composer));
+
+               if (context->new_message) {
+                       CamelInternetAddress *to = NULL, *cc = NULL;
+                       CamelNNTPAddress *postto = NULL;
+                       gboolean need_reply_all = FALSE;
+
+                       if ((context->flags & (E_MAIL_REPLY_FLAG_FORMAT_PLAIN | 
E_MAIL_REPLY_FLAG_FORMAT_HTML)) != 0) {
+                               e_content_editor_set_html_mode (cnt_editor, (context->flags & 
E_MAIL_REPLY_FLAG_FORMAT_HTML) != 0);
+                       }
+
+                       em_utils_edit_message (composer, context->folder, context->new_message, 
context->message_uid, TRUE);
+
+                       if (context->type == E_MAIL_REPLY_TO_SENDER) {
+                               /* Reply to sender */
+                               to = camel_internet_address_new ();
+                               if (context->folder)
+                                       postto = camel_nntp_address_new ();
+                               get_reply_sender (context->source_message, to, postto);
+                       } else if (context->type == E_MAIL_REPLY_TO_LIST) {
+                               /* Reply to list */
+                               to = camel_internet_address_new ();
+
+                               if (!get_reply_list (context->source_message, to)) {
+                                       need_reply_all = TRUE;
+                                       g_clear_object (&to);
+                               }
+                       } else if (context->type != E_MAIL_REPLY_TO_ALL) {
+                               g_warn_if_reached ();
+                       }
+
+                       if (context->type == E_MAIL_REPLY_TO_ALL || need_reply_all) {
+                               /* Reply to all */
+                               to = camel_internet_address_new ();
+                               cc = camel_internet_address_new ();
+
+                               if (context->folder)
+                                       postto = camel_nntp_address_new ();
+
+                               em_utils_get_reply_all (e_shell_get_registry (context->shell), 
context->source_message, to, cc, postto);
+                       }
+
+                       reply_setup_composer_recipients (composer, to, cc, context->folder, 
context->message_uid, postto);
+
+                       composer_set_no_change (composer);
+
+                       g_clear_object (&to);
+                       g_clear_object (&cc);
+                       g_clear_object (&postto);
+
+                       if (context->folder && context->message_uid) {
+                               gchar *source_folder_uri = NULL;
+                               gchar *source_message_uid = NULL;
+
+                               em_utils_get_real_folder_uri_and_message_uid (context->folder, 
context->message_uid,
+                                       &source_folder_uri, &source_message_uid);
+
+                               if (!source_message_uid)
+                                       source_message_uid = g_strdup (context->message_uid);
+
+                               if (source_folder_uri) {
+                                       e_msg_composer_set_source_headers (composer, source_folder_uri,
+                                               source_message_uid, CAMEL_MESSAGE_ANSWERED | 
CAMEL_MESSAGE_SEEN);
+                               }
+
+                               g_free (source_folder_uri);
+                               g_free (source_message_uid);
+                       }
+               } else {
+                       em_utils_reply_to_message (composer, context->source_message,
+                               context->folder, context->message_uid, context->type, context->style,
+                               context->source, NULL, context->flags);
+               }
+       } else {
+               e_alert_submit (context->alert_sink, "mail-composer:failed-create-composer",
+                       error ? error->message : _("Unknown error"), NULL);
+       }
+
+       alt_reply_context_free (context);
+       g_clear_error (&error);
+}
+
+static void
+alt_reply_template_applied_cb (GObject *source_object,
+                              GAsyncResult *result,
+                              gpointer user_data)
+{
+       AltReplyContext *context = user_data;
+       GError *error = NULL;
+
+       g_return_if_fail (context != NULL);
+
+       context->new_message = e_mail_templates_apply_finish (source_object, result, &error);
+
+       if (context->new_message) {
+               if (context->template_preserve_subject) {
+                       gchar *subject;
+
+                       subject = emcu_construct_reply_subject (camel_mime_message_get_subject 
(context->source_message));
+                       camel_mime_message_set_subject (context->new_message, subject);
+                       g_free (subject);
+               }
+
+               e_msg_composer_new (context->shell, alt_reply_composer_created_cb, context);
+       } else {
+               e_alert_submit (context->alert_sink, "mail:no-retrieve-message",
+                       error ? error->message : _("Unknown error"), NULL);
+               alt_reply_context_free (context);
+       }
+
+       g_clear_error (&error);
+}
+
+static void
+emcu_three_state_toggled_cb (GtkToggleButton *widget,
+                            gpointer user_data)
+{
+       glong *phandlerid = user_data;
+
+       g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
+       g_return_if_fail (phandlerid != NULL);
+
+       g_signal_handler_block (widget, *phandlerid);
+
+       if (gtk_toggle_button_get_inconsistent (widget) &&
+           gtk_toggle_button_get_active (widget)) {
+               gtk_toggle_button_set_active (widget, FALSE);
+               gtk_toggle_button_set_inconsistent (widget, FALSE);
+       } else if (!gtk_toggle_button_get_active (widget)) {
+               gtk_toggle_button_set_inconsistent (widget, TRUE);
+               gtk_toggle_button_set_active (widget, FALSE);
+       } else {
+       }
+
+       g_signal_handler_unblock (widget, *phandlerid);
+}
+
+static void
+emcu_connect_three_state_changer (GtkToggleButton *toggle_button)
+{
+       glong *phandlerid;
+
+       g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
+
+       phandlerid = g_new0 (glong, 1);
+
+       *phandlerid = g_signal_connect_data (toggle_button, "toggled",
+               G_CALLBACK (emcu_three_state_toggled_cb),
+               phandlerid, (GClosureNotify) g_free, 0);
+}
+
+static void
+emcu_three_state_set_value (GtkToggleButton *toggle_button,
+                           EThreeState value)
+{
+       g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
+
+       if (value == E_THREE_STATE_OFF) {
+               gtk_toggle_button_set_active (toggle_button, FALSE);
+               gtk_toggle_button_set_inconsistent (toggle_button, FALSE);
+       } else if (value == E_THREE_STATE_ON) {
+               gtk_toggle_button_set_active (toggle_button, TRUE);
+               gtk_toggle_button_set_inconsistent (toggle_button, FALSE);
+       } else {
+               gtk_toggle_button_set_active (toggle_button, FALSE);
+               gtk_toggle_button_set_inconsistent (toggle_button, TRUE);
+       }
+}
+
+static EThreeState
+emcu_three_state_get_value (GtkToggleButton *toggle_button)
+{
+       g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), E_THREE_STATE_INCONSISTENT);
+
+       if (gtk_toggle_button_get_inconsistent (toggle_button))
+               return E_THREE_STATE_INCONSISTENT;
+       else if (gtk_toggle_button_get_active (toggle_button))
+               return E_THREE_STATE_ON;
+
+       return E_THREE_STATE_OFF;
+}
+
+static GtkComboBox *
+emcu_create_templates_combo (EShell *shell,
+                            const gchar *folder_uri,
+                            const gchar *message_uid)
+{
+       GtkComboBox *combo;
+       GtkCellRenderer *renderer;
+       EShellBackend *shell_backend;
+       EMailSession *mail_session;
+       EMailTemplatesStore *templates_store;
+       GtkTreeStore *tree_store;
+       GtkTreeIter found_iter;
+       gboolean found_message = FALSE;
+
+       shell_backend = e_shell_get_backend_by_name (shell, "mail");
+       g_return_val_if_fail (E_IS_MAIL_BACKEND (shell_backend), NULL);
+
+       mail_session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend));
+       templates_store = e_mail_templates_store_ref_default (e_mail_ui_session_get_account_store 
(E_MAIL_UI_SESSION (mail_session)));
+
+       tree_store = e_mail_templates_store_build_model (templates_store, folder_uri, message_uid, 
&found_message, &found_iter);
+
+       combo = GTK_COMBO_BOX (gtk_combo_box_new_with_model (GTK_TREE_MODEL (tree_store)));
+
+       renderer = gtk_cell_renderer_text_new ();
+       g_object_set (G_OBJECT (renderer),
+               "ellipsize", PANGO_ELLIPSIZE_END,
+               "max-width-chars", 60,
+               NULL);
+
+       gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
+               "text", E_MAIL_TEMPLATES_STORE_COLUMN_DISPLAY_NAME,
+               NULL);
+
+       g_clear_object (&templates_store);
+       g_clear_object (&tree_store);
+
+       if (found_message) {
+               gtk_combo_box_set_active_iter (combo, &found_iter);
+       } else {
+               gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE);
+       }
+
+       return combo;
+}
+
+/**
+ * em_utils_reply_alternative:
+ * @parent: (nullable): a parent #GtkWindow for the question dialog
+ * @shell: an #EShell instance used to create #EMsgComposer
+ * @alert_sink: an #EAlertSink to put any errors to
+ * @message: a #CamelMimeMessage
+ * @folder: (nullable): a #CamelFolder, or %NULL
+ * @message_uid: (nullable): the UID of @message, or %NULL
+ * @style: the reply style to use
+ * @source: (nullable): source to inherit view settings from
+ *
+ * This is similar to em_utils_reply_to_message(), except it asks user to
+ * change some settings before sending. It calls em_utils_reply_to_message()
+ * at the end for non-templated replies.
+ *
+ * Since: 3.30
+ **/
+void
+em_utils_reply_alternative (GtkWindow *parent,
+                           EShell *shell,
+                           EAlertSink *alert_sink,
+                           CamelMimeMessage *message,
+                           CamelFolder *folder,
+                           const gchar *message_uid,
+                           EMailReplyStyle default_style,
+                           EMailPartList *source)
+{
+       GtkWidget *dialog, *widget, *style_label;
+       GtkBox *hbox, *vbox;
+       GtkRadioButton *recip_sender, *recip_list, *recip_all;
+       GtkLabel *sender_label, *list_label, *all_label;
+       GtkRadioButton *style_default, *style_attach, *style_inline, *style_quote, *style_no_quote;
+       GtkToggleButton *html_format;
+       GtkToggleButton *bottom_posting;
+       GtkCheckButton *apply_template;
+       GtkComboBox *templates;
+       GtkCheckButton *preserve_message_subject;
+       PangoAttrList *attr_list;
+       GSettings *settings;
+       gchar *last_tmpl_folder_uri, *last_tmpl_message_uid, *address, *text;
+       gboolean can_reply_list = FALSE;
+       CamelInternetAddress *to, *cc;
+       CamelNNTPAddress *postto = NULL;
+       gint n_addresses;
+
+       g_return_if_fail (E_IS_SHELL (shell));
+       g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+       settings = e_util_ref_settings ("org.gnome.evolution.mail");
+
+       dialog = gtk_dialog_new_with_buttons (_("Alternative Reply"), parent,
+               GTK_DIALOG_DESTROY_WITH_PARENT,
+               _("_Cancel"), GTK_RESPONSE_CANCEL,
+               _("_Reply"), GTK_RESPONSE_OK,
+               NULL);
+
+       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+       vbox = GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog)));
+       gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+       gtk_box_set_spacing (vbox, 2);
+
+       #define add_with_indent(x) \
+               gtk_widget_set_margin_left (GTK_WIDGET (x), 12); \
+               gtk_box_pack_start (vbox, GTK_WIDGET (x), FALSE, FALSE, 0);
+
+       widget = gtk_label_new (_("Recipients:"));
+       g_object_set (G_OBJECT (widget),
+               "hexpand", FALSE,
+               "halign", GTK_ALIGN_START,
+               NULL);
+       gtk_box_pack_start (vbox, widget, FALSE, FALSE, 0);
+
+       attr_list = pango_attr_list_new ();
+       pango_attr_list_insert (attr_list, pango_attr_style_new (PANGO_STYLE_ITALIC));
+
+       #define add_with_label(wgt, lbl) G_STMT_START { \
+               GtkWidget *divider_label = gtk_label_new (":"); \
+               gtk_label_set_attributes (GTK_LABEL (lbl), attr_list); \
+               hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6)); \
+               gtk_box_pack_start (hbox, GTK_WIDGET (wgt), FALSE, FALSE, 0); \
+               gtk_box_pack_start (hbox, GTK_WIDGET (divider_label), FALSE, FALSE, 0); \
+               gtk_box_pack_start (hbox, GTK_WIDGET (lbl), FALSE, FALSE, 0); \
+               e_binding_bind_property ( \
+                       wgt, "sensitive", \
+                       divider_label, "visible", \
+                       G_BINDING_SYNC_CREATE); \
+               e_binding_bind_property ( \
+                       wgt, "sensitive", \
+                       lbl, "visible", \
+                       G_BINDING_SYNC_CREATE); \
+               add_with_indent (hbox); } G_STMT_END
+
+       recip_sender = GTK_RADIO_BUTTON (gtk_radio_button_new_with_mnemonic (
+               NULL, _("Reply to _Sender")));
+       sender_label = GTK_LABEL (gtk_label_new (""));
+       add_with_label (recip_sender, sender_label);
+
+       recip_list = GTK_RADIO_BUTTON (gtk_radio_button_new_with_mnemonic (
+               gtk_radio_button_get_group (recip_sender), _("Reply to _List")));
+       list_label = GTK_LABEL (gtk_label_new (""));
+       add_with_label (recip_list, list_label);
+
+       recip_all = GTK_RADIO_BUTTON (gtk_radio_button_new_with_mnemonic (
+               gtk_radio_button_get_group (recip_sender), _("Reply to _All")));
+       all_label = GTK_LABEL (gtk_label_new (""));
+       add_with_label (recip_all, all_label);
+
+       #undef add_with_label
+
+       pango_attr_list_unref (attr_list);
+
+       /* One line gap between sections */
+       widget = gtk_label_new (" ");
+       gtk_box_pack_start (vbox, widget, FALSE, FALSE, 0);
+
+       style_label = gtk_label_new (_("Reply style:"));
+       g_object_set (G_OBJECT (style_label),
+               "hexpand", FALSE,
+               "halign", GTK_ALIGN_START,
+               NULL);
+       gtk_box_pack_start (vbox, style_label, FALSE, FALSE, 0);
+
+       style_default = GTK_RADIO_BUTTON (gtk_radio_button_new_with_mnemonic (
+               NULL, _("_Default")));
+       add_with_indent (style_default);
+
+       style_attach = GTK_RADIO_BUTTON (gtk_radio_button_new_with_mnemonic (
+               gtk_radio_button_get_group (style_default), _("Attach_ment")));
+       add_with_indent (style_attach);
+
+       style_inline = GTK_RADIO_BUTTON (gtk_radio_button_new_with_mnemonic (
+               gtk_radio_button_get_group (style_default), _("Inline (_Outlook style)")));
+       add_with_indent (style_inline);
+
+       style_quote = GTK_RADIO_BUTTON (gtk_radio_button_new_with_mnemonic (
+               gtk_radio_button_get_group (style_default), _("_Quote")));
+       add_with_indent (style_quote);
+
+       style_no_quote = GTK_RADIO_BUTTON (gtk_radio_button_new_with_mnemonic (
+               gtk_radio_button_get_group (style_default), _("Do _Not Quote")));
+       add_with_indent (style_no_quote);
+
+       /* One line gap between sections */
+       widget = gtk_label_new (" ");
+       gtk_box_pack_start (vbox, widget, FALSE, FALSE, 0);
+
+       html_format = GTK_TOGGLE_BUTTON (gtk_check_button_new_with_mnemonic (_("_Format message in HTML")));
+       gtk_box_pack_start (vbox, GTK_WIDGET (html_format), FALSE, FALSE, 0);
+
+       bottom_posting = GTK_TOGGLE_BUTTON (gtk_check_button_new_with_mnemonic (_("Start _typing at the 
bottom")));
+       gtk_box_pack_start (vbox, GTK_WIDGET (bottom_posting), FALSE, FALSE, 0);
+
+       /* One line gap between sections */
+       widget = gtk_label_new (" ");
+       gtk_box_pack_start (vbox, widget, FALSE, FALSE, 0);
+
+       apply_template = GTK_CHECK_BUTTON (gtk_check_button_new_with_mnemonic (_("Apply t_emplate")));
+       gtk_box_pack_start (vbox, GTK_WIDGET (apply_template), FALSE, FALSE, 0);
+
+       last_tmpl_folder_uri = g_settings_get_string (settings, "alt-reply-template-folder-uri");
+       last_tmpl_message_uid = g_settings_get_string (settings, "alt-reply-template-message-uid");
+
+       templates = emcu_create_templates_combo (shell, last_tmpl_folder_uri, last_tmpl_message_uid);
+       add_with_indent (templates);
+
+       g_free (last_tmpl_folder_uri);
+       g_free (last_tmpl_message_uid);
+
+       preserve_message_subject = GTK_CHECK_BUTTON (gtk_check_button_new_with_mnemonic (_("Preserve original 
message S_ubject")));
+       add_with_indent (preserve_message_subject);
+
+       #undef add_with_indent
+
+       gtk_widget_show_all (GTK_WIDGET (vbox));
+
+       #define populate_label_with_text(lbl, txt) \
+               g_object_set (G_OBJECT (lbl), \
+                       "ellipsize", PANGO_ELLIPSIZE_END, \
+                       "max-width-chars", 50, \
+                       "label", txt ? txt : "", \
+                       "tooltip-text", txt ? txt : "", \
+                       NULL);
+
+       /* Reply to sender */
+       to = camel_internet_address_new ();
+       if (folder)
+               postto = camel_nntp_address_new ();
+       get_reply_sender (message, to, postto);
+
+       if (postto && camel_address_length (CAMEL_ADDRESS (postto)) > 0) {
+               address = camel_address_format (CAMEL_ADDRESS (postto));
+       } else {
+               address = camel_address_format (CAMEL_ADDRESS (to));
+       }
+
+       populate_label_with_text (sender_label, address);
+
+       g_clear_object (&postto);
+       g_clear_object (&to);
+       g_free (address);
+
+       /* Reply to list */
+       to = camel_internet_address_new ();
+
+       if (!get_reply_list (message, to)) {
+               gtk_widget_set_sensitive (GTK_WIDGET (recip_list), FALSE);
+       } else {
+               can_reply_list = TRUE;
+
+               address = camel_address_format (CAMEL_ADDRESS (to));
+               populate_label_with_text (list_label, address);
+               g_free (address);
+       }
+
+       g_clear_object (&to);
+
+       /* Reply to all */
+       to = camel_internet_address_new ();
+       cc = camel_internet_address_new ();
+
+       if (folder)
+               postto = camel_nntp_address_new ();
+
+       em_utils_get_reply_all (e_shell_get_registry (shell), message, to, cc, postto);
+
+       if (postto && camel_address_length (CAMEL_ADDRESS (postto)) > 0) {
+               n_addresses = camel_address_length (CAMEL_ADDRESS (postto));
+               address = camel_address_format (CAMEL_ADDRESS (postto));
+       } else {
+               camel_address_cat (CAMEL_ADDRESS (to), CAMEL_ADDRESS (cc));
+               n_addresses = camel_address_length (CAMEL_ADDRESS (to));
+               address = camel_address_format (CAMEL_ADDRESS (to));
+       }
+
+       text = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "one recipient", "%d recipients", n_addresses), 
n_addresses);
+       populate_label_with_text (all_label, text);
+       gtk_widget_set_tooltip_text (GTK_WIDGET (all_label), address);
+
+       g_clear_object (&to);
+       g_clear_object (&cc);
+       g_clear_object (&postto);
+       g_free (address);
+       g_free (text);
+
+       #undef populate_label_with_text
+
+       /* Prefer reply-to-list */
+       if (g_settings_get_boolean (settings, "composer-group-reply-to-list")) {
+               if (can_reply_list)
+                       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (recip_list), TRUE);
+               else if (n_addresses > 1)
+                       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (recip_all), TRUE);
+               else
+                       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (recip_sender), TRUE);
+
+       /* Prefer reply-to-all */
+       } else {
+               if (n_addresses > 1)
+                       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (recip_all), TRUE);
+               else if (can_reply_list)
+                       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (recip_list), TRUE);
+               else
+                       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (recip_sender), TRUE);
+       }
+
+       switch (g_settings_get_enum (settings, "alt-reply-style")) {
+       case E_MAIL_REPLY_STYLE_UNKNOWN:
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (style_default), TRUE);
+               break;
+       case E_MAIL_REPLY_STYLE_QUOTED:
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (style_quote), TRUE);
+               break;
+       case E_MAIL_REPLY_STYLE_DO_NOT_QUOTE:
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (style_no_quote), TRUE);
+               break;
+       case E_MAIL_REPLY_STYLE_ATTACH:
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (style_attach), TRUE);
+               break;
+       case E_MAIL_REPLY_STYLE_OUTLOOK:
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (style_inline), TRUE);
+               break;
+       }
+
+       emcu_three_state_set_value (html_format, g_settings_get_enum (settings, "alt-reply-html-format"));
+       emcu_three_state_set_value (bottom_posting, g_settings_get_enum (settings, "alt-reply-start-bottom"));
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (apply_template), g_settings_get_boolean (settings, 
"alt-reply-template-apply"));
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (preserve_message_subject), g_settings_get_boolean 
(settings, "alt-reply-template-preserve-subject"));
+
+       if (!gtk_widget_get_sensitive (GTK_WIDGET (templates)))
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (apply_template), FALSE);
+
+       emcu_connect_three_state_changer (html_format);
+       emcu_connect_three_state_changer (bottom_posting);
+
+       e_binding_bind_property (
+               apply_template, "active",
+               templates, "sensitive",
+               G_BINDING_SYNC_CREATE);
+
+       e_binding_bind_property (
+               apply_template, "active",
+               preserve_message_subject, "sensitive",
+               G_BINDING_SYNC_CREATE);
+
+       /* Enable the 'Reply Style' section only if not using Template */
+       e_binding_bind_property (
+               apply_template, "active",
+               style_label, "sensitive",
+               G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+       e_binding_bind_property (
+               apply_template, "active",
+               style_default, "sensitive",
+               G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+       e_binding_bind_property (
+               apply_template, "active",
+               style_attach, "sensitive",
+               G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+       e_binding_bind_property (
+               apply_template, "active",
+               style_inline, "sensitive",
+               G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+       e_binding_bind_property (
+               apply_template, "active",
+               style_quote, "sensitive",
+               G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+       e_binding_bind_property (
+               apply_template, "active",
+               style_no_quote, "sensitive",
+               G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+       /* Similarly with bottom posting, which doesn't work when using Templates */
+       e_binding_bind_property (
+               apply_template, "active",
+               bottom_posting, "sensitive",
+               G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+       if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+               GtkTreeIter iter;
+               AltReplyContext *context;
+               EThreeState three_state;
+               CamelFolder *template_folder = NULL;
+               gchar *template_message_uid = NULL;
+
+               context = g_new0 (AltReplyContext, 1);
+               context->shell = g_object_ref (shell);
+               context->alert_sink = g_object_ref (alert_sink);
+               context->source_message = g_object_ref (message);
+               context->folder = folder ? g_object_ref (folder) : NULL;
+               context->source = source ? g_object_ref (source) : NULL;
+               context->message_uid = g_strdup (message_uid);
+               context->style = E_MAIL_REPLY_STYLE_UNKNOWN;
+               context->flags = E_MAIL_REPLY_FLAG_FORCE_STYLE;
+
+               if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (style_quote)))
+                       context->style = E_MAIL_REPLY_STYLE_QUOTED;
+               else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (style_no_quote)))
+                       context->style = E_MAIL_REPLY_STYLE_DO_NOT_QUOTE;
+               else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (style_attach)))
+                       context->style = E_MAIL_REPLY_STYLE_ATTACH;
+               else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (style_inline)))
+                       context->style = E_MAIL_REPLY_STYLE_OUTLOOK;
+               else
+                       context->flags = context->flags & (~E_MAIL_REPLY_FLAG_FORCE_STYLE);
+
+               three_state = emcu_three_state_get_value (html_format);
+               g_settings_set_enum (settings, "alt-reply-html-format", three_state);
+
+               if (three_state == E_THREE_STATE_ON)
+                       context->flags |= E_MAIL_REPLY_FLAG_FORMAT_HTML;
+               else if (three_state == E_THREE_STATE_OFF)
+                       context->flags |= E_MAIL_REPLY_FLAG_FORMAT_PLAIN;
+
+               three_state = emcu_three_state_get_value (bottom_posting);
+               g_settings_set_enum (settings, "alt-reply-start-bottom", three_state);
+
+               if (three_state == E_THREE_STATE_ON)
+                       context->flags |= E_MAIL_REPLY_FLAG_BOTTOM_POSTING;
+               else if (three_state == E_THREE_STATE_OFF)
+                       context->flags |= E_MAIL_REPLY_FLAG_TOP_POSTING;
+
+               g_settings_set_enum (settings, "alt-reply-style", context->style);
+               g_settings_set_boolean (settings, "alt-reply-template-apply", gtk_toggle_button_get_active 
(GTK_TOGGLE_BUTTON (apply_template)));
+               g_settings_set_boolean (settings, "alt-reply-template-preserve-subject", 
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (preserve_message_subject)));
+
+               if (gtk_combo_box_get_active_iter (templates, &iter)) {
+                       gtk_tree_model_get (gtk_combo_box_get_model (templates), &iter,
+                               E_MAIL_TEMPLATES_STORE_COLUMN_FOLDER, &template_folder,
+                               E_MAIL_TEMPLATES_STORE_COLUMN_MESSAGE_UID, &template_message_uid,
+                               -1);
+               }
+
+               if (template_folder) {
+                       gchar *folder_uri;
+
+                       folder_uri = e_mail_folder_uri_from_folder (template_folder);
+                       g_settings_set_string (settings, "alt-reply-template-folder-uri", folder_uri ? 
folder_uri : "");
+                       g_free (folder_uri);
+               }
+
+               g_settings_set_string (settings, "alt-reply-template-message-uid", template_message_uid ? 
template_message_uid : "");
+
+               if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (recip_sender)))
+                       context->type = E_MAIL_REPLY_TO_SENDER;
+               else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (recip_list)))
+                       context->type = E_MAIL_REPLY_TO_LIST;
+               else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (recip_all)))
+                       context->type = E_MAIL_REPLY_TO_ALL;
+               else
+                       g_warn_if_reached ();
+
+               if (context->style == E_MAIL_REPLY_STYLE_UNKNOWN)
+                       context->style = default_style;
+
+               context->template_preserve_subject = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON 
(preserve_message_subject));
+
+               if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (apply_template))) {
+                       e_mail_templates_apply (context->source_message, template_folder, 
template_message_uid,
+                               NULL, alt_reply_template_applied_cb, context);
+
+               } else {
+                       e_msg_composer_new (context->shell, alt_reply_composer_created_cb, context);
+               }
+
+               g_clear_object (&template_folder);
+               g_free (template_message_uid);
+       }
+
+       gtk_widget_destroy (dialog);
+       g_clear_object (&settings);
+}
+
 /**
  * em_utils_reply_to_message:
- * @shell: an #EShell
+ * @composer: an #EMsgComposer
  * @message: a #CamelMimeMessage
  * @folder: a #CamelFolder, or %NULL
  * @message_uid: the UID of @message, or %NULL
@@ -3576,6 +4324,7 @@ emcu_folder_is_inbox (CamelFolder *folder)
  * @style: the reply style to use
  * @source: source to inherit view settings from
  * @address: used for E_MAIL_REPLY_TO_RECIPIENT @type
+ * @reply_flags: bit-or of #EMailReplyFlags
  *
  * Creates a new composer ready to reply to @message.
  *
@@ -3590,7 +4339,8 @@ em_utils_reply_to_message (EMsgComposer *composer,
                            EMailReplyType type,
                            EMailReplyStyle style,
                            EMailPartList *parts_list,
-                           CamelInternetAddress *address)
+                          CamelInternetAddress *address,
+                          EMailReplyFlags reply_flags)
 {
        ESourceRegistry *registry;
        CamelInternetAddress *to, *cc;
@@ -3598,12 +4348,25 @@ em_utils_reply_to_message (EMsgComposer *composer,
        EShell *shell;
        ESourceMailCompositionReplyStyle prefer_reply_style = E_SOURCE_MAIL_COMPOSITION_REPLY_STYLE_DEFAULT;
        ESource *source;
+       EContentEditor *cnt_editor;
        gchar *identity_uid = NULL, *identity_name = NULL, *identity_address = NULL;
        guint32 flags;
 
        g_return_if_fail (E_IS_MSG_COMPOSER (composer));
        g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
 
+       cnt_editor = e_html_editor_get_content_editor (e_msg_composer_get_editor (composer));
+
+       if ((reply_flags & (E_MAIL_REPLY_FLAG_FORMAT_PLAIN | E_MAIL_REPLY_FLAG_FORMAT_HTML)) != 0) {
+               e_content_editor_set_html_mode (cnt_editor, (reply_flags & E_MAIL_REPLY_FLAG_FORMAT_HTML) != 
0);
+       }
+
+       if ((reply_flags & (E_MAIL_REPLY_FLAG_TOP_POSTING | E_MAIL_REPLY_FLAG_BOTTOM_POSTING)) != 0) {
+               e_content_editor_set_start_bottom (cnt_editor,
+                       (reply_flags & E_MAIL_REPLY_FLAG_TOP_POSTING) != 0 ?
+                       E_THREE_STATE_OFF : E_THREE_STATE_ON);
+       }
+
        to = camel_internet_address_new ();
        cc = camel_internet_address_new ();
 
@@ -3617,7 +4380,8 @@ em_utils_reply_to_message (EMsgComposer *composer,
                        registry, message, folder, message_uid, &identity_name, &identity_address, 
sort_sources_by_ui, shell);
        if (source != NULL) {
                identity_uid = e_source_dup_uid (source);
-               if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION)) {
+               if (!(reply_flags & E_MAIL_REPLY_FLAG_FORCE_STYLE) &&
+                   e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION)) {
                        ESourceMailComposition *extension;
 
                        extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION);
@@ -3685,7 +4449,8 @@ em_utils_reply_to_message (EMsgComposer *composer,
                if (used_identity_uid) {
                        source = e_source_registry_ref_source (e_shell_get_registry (shell), 
used_identity_uid);
                        if (source) {
-                               if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION)) {
+                               if (!(reply_flags & E_MAIL_REPLY_FLAG_FORCE_STYLE) &&
+                                   e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION)) {
                                        ESourceMailComposition *extension;
 
                                        extension = e_source_get_extension (source, 
E_SOURCE_EXTENSION_MAIL_COMPOSITION);
@@ -3734,6 +4499,13 @@ em_utils_reply_to_message (EMsgComposer *composer,
        /* because some reply types can change recipients after the composer is populated */
        em_utils_apply_send_account_override_to_composer (composer, folder);
 
+       /* This is required to be done (also) at the end */
+       if ((reply_flags & (E_MAIL_REPLY_FLAG_TOP_POSTING | E_MAIL_REPLY_FLAG_BOTTOM_POSTING)) != 0) {
+               e_content_editor_set_start_bottom (cnt_editor,
+                       (reply_flags & E_MAIL_REPLY_FLAG_TOP_POSTING) != 0 ?
+                       E_THREE_STATE_OFF : E_THREE_STATE_ON);
+       }
+
        composer_set_no_change (composer);
 
        gtk_widget_show (GTK_WIDGET (composer));
diff --git a/src/mail/em-composer-utils.h b/src/mail/em-composer-utils.h
index 91471bc..73e0760 100644
--- a/src/mail/em-composer-utils.h
+++ b/src/mail/em-composer-utils.h
@@ -85,7 +85,16 @@ void         em_utils_reply_to_message       (EMsgComposer *composer,
                                                 EMailReplyType type,
                                                 EMailReplyStyle style,
                                                 EMailPartList *source,
-                                                CamelInternetAddress *address);
+                                                CamelInternetAddress *address,
+                                                guint32 reply_flags); /* bit-or of EMailReplyFlags */
+void           em_utils_reply_alternative      (GtkWindow *parent,
+                                                EShell *shell,
+                                                EAlertSink *alert_sink,
+                                                CamelMimeMessage *message,
+                                                CamelFolder *folder,
+                                                const gchar *message_uid,
+                                                EMailReplyStyle default_style,
+                                                EMailPartList *source);
 EDestination **        em_utils_camel_address_to_destination
                                                (CamelInternetAddress *iaddr);
 void           em_configure_new_composer       (EMsgComposer *composer,
diff --git a/src/modules/mail/e-mail-attachment-handler.c b/src/modules/mail/e-mail-attachment-handler.c
index a035434..2ddec78 100644
--- a/src/modules/mail/e-mail-attachment-handler.c
+++ b/src/modules/mail/e-mail-attachment-handler.c
@@ -214,7 +214,7 @@ mail_attachment_handler_composer_created_cb (GObject *source_object,
                        style = g_settings_get_enum (settings, "reply-style-name");
                        g_object_unref (settings);
 
-                       em_utils_reply_to_message (composer, ccd->message, NULL, NULL, ccd->reply_type, 
style, NULL, NULL);
+                       em_utils_reply_to_message (composer, ccd->message, NULL, NULL, ccd->reply_type, 
style, NULL, NULL, E_MAIL_REPLY_FLAG_NONE);
                } else if (ccd->is_forward) {
                        em_utils_forward_message (composer, ccd->message, ccd->forward_style, ccd->folder, 
NULL);
                } else {
diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index 720e7eb..cd0d5f2 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -1838,6 +1838,7 @@ webkit_editor_insert_content (EContentEditor *editor,
                if (!(wk_editor->priv->html_mode)) {
                        if (strstr (content, "<!-- text/html -->")) {
                                if (!show_lose_formatting_dialog (wk_editor)) {
+                                       set_convert_in_situ (wk_editor, FALSE);
                                        wk_editor->priv->reload_in_progress = TRUE;
                                        webkit_editor_set_html_mode (wk_editor, TRUE);
                                        webkit_web_view_load_html (
diff --git a/src/plugins/templates/CMakeLists.txt b/src/plugins/templates/CMakeLists.txt
index c5f90a6..29c67c8 100644
--- a/src/plugins/templates/CMakeLists.txt
+++ b/src/plugins/templates/CMakeLists.txt
@@ -10,8 +10,6 @@ set(DEPENDENCIES
 
 set(SOURCES
        templates.c
-       e-templates-store.h
-       e-templates-store.c
 )
 
 add_library(org-gnome-templates MODULE
diff --git a/src/plugins/templates/templates.c b/src/plugins/templates/templates.c
index 1757b9c..79789dc 100644
--- a/src/plugins/templates/templates.c
+++ b/src/plugins/templates/templates.c
@@ -1,24 +1,23 @@
 /*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2008 - Diego Escalante Urrelo
+ * Copyright (C) 2018 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
  * the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  * for more details.
  *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
  *
  * Authors:
  *             Diego Escalante Urrelo <diegoe gnome org>
  *             Bharath Acharya <abharath novell com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- * Copyright (C) 2008 - Diego Escalante Urrelo
- *
  */
 
 #include "evolution-config.h"
@@ -27,19 +26,19 @@
 #include <glib/gi18n.h>
 #include <string.h>
 
-#include <e-util/e-util.h>
-
-#include <shell/e-shell-view.h>
+#include "e-util/e-util.h"
 
-#include <mail/e-mail-reader.h>
-#include <mail/e-mail-ui-session.h>
-#include <mail/em-composer-utils.h>
-#include <mail/em-utils.h>
-#include <mail/message-list.h>
+#include "shell/e-shell-view.h"
 
-#include <composer/e-msg-composer.h>
+#include "mail/e-mail-reader.h"
+#include "mail/e-mail-ui-session.h"
+#include "mail/e-mail-templates.h"
+#include "mail/e-mail-templates-store.h"
+#include "mail/em-composer-utils.h"
+#include "mail/em-utils.h"
+#include "mail/message-list.h"
 
-#include "e-templates-store.h"
+#include "composer/e-msg-composer.h"
 
 #define CONF_KEY_TEMPLATE_PLACEHOLDERS "template-placeholders"
 
@@ -48,11 +47,11 @@ typedef struct _AsyncContext AsyncContext;
 struct _AsyncContext {
        EActivity *activity;
        EMailReader *reader;
-       CamelMimeMessage *message;
-       CamelMimeMessage *template;
+       CamelMimeMessage *source_message;
+       CamelMimeMessage *new_message;
        CamelFolder *template_folder;
        gchar *source_folder_uri;
-       gchar *message_uid;
+       gchar *source_message_uid;
        gchar *template_message_uid;
 };
 
@@ -83,7 +82,7 @@ gint          e_plugin_lib_enable             (EPlugin *plugin,
 #define TEMPLATES_DATA_KEY "templates::data"
 
 typedef struct _TemplatesData {
-       ETemplatesStore *templates_store;
+       EMailTemplatesStore *templates_store;
        gulong changed_handler_id;
        gboolean changed;
        guint merge_id;
@@ -124,12 +123,12 @@ async_context_free (AsyncContext *context)
 {
        g_clear_object (&context->activity);
        g_clear_object (&context->reader);
-       g_clear_object (&context->message);
-       g_clear_object (&context->template);
+       g_clear_object (&context->source_message);
+       g_clear_object (&context->new_message);
        g_clear_object (&context->template_folder);
 
        g_free (context->source_folder_uri);
-       g_free (context->message_uid);
+       g_free (context->source_message_uid);
        g_free (context->template_message_uid);
 
        g_slice_free (AsyncContext, context);
@@ -554,296 +553,6 @@ e_plugin_lib_get_configure_widget (EPlugin *epl)
        return hbox;
 }
 
-/* Case insensitive version of strstr */
-static gchar *
-strstr_nocase (const gchar *haystack,
-               const gchar *needle)
-{
-/* When _GNU_SOURCE is available, use the nonstandard extension of libc */
-#ifdef _GNU_SOURCE
-       g_return_val_if_fail (haystack, NULL);
-       g_return_Val_if_fail (needle, NULL);
-
-       return strcasestr (haystack, needle)
-#else
-/* Otherwise convert both, haystack and needle to lowercase and use good old strstr */
-       gchar *l_haystack;
-       gchar *l_needle;
-       gchar *pos;
-
-       g_return_val_if_fail (haystack, NULL);
-       g_return_val_if_fail (needle, NULL);
-
-       l_haystack = g_ascii_strdown (haystack, -1);
-       l_needle = g_ascii_strdown (needle, -1);
-       pos = strstr (l_haystack, l_needle);
-
-       /* Get actual position of the needle in the haystack instead of l_haystack or
-        * leave it NULL */
-       if (pos)
-               pos = (gchar *)(haystack + (pos - l_haystack));
-
-       g_free (l_haystack);
-       g_free (l_needle);
-
-       return pos;
-#endif
-}
-
-/* Replaces $ORIG[variable] in given template by given replacement from the original message */
-static void
-replace_template_variable (GString *text,
-                           const gchar *variable,
-                           const gchar *replacement)
-{
-       const gchar *p, *next;
-       GString *str;
-       gint find_len;
-       gchar *find;
-
-       g_return_if_fail (text != NULL);
-       g_return_if_fail (variable != NULL);
-       g_return_if_fail (*variable);
-
-       find = g_strconcat ("$ORIG[", variable, "]", NULL);
-
-       find_len = strlen (find);
-       str = g_string_new ("");
-       p = text->str;
-       while (next = strstr_nocase (p, find), next) {
-               if (p < next)
-                       g_string_append_len (str, p, next - p);
-               if (replacement && *replacement)
-                       g_string_append (str, replacement);
-               p = next + find_len;
-       }
-       g_string_append (str, p);
-
-       g_string_assign (text, str->str);
-
-       g_string_free (str, TRUE);
-       g_free (find);
-}
-
-static void
-replace_email_addresses (GString *template,
-                         CamelInternetAddress *internet_address,
-                         const gchar *variable)
-{
-       gint address_index = 0;
-       GString *emails = g_string_new ("");
-       const gchar *address_name, *address_email;
-
-       g_return_if_fail (template);
-       g_return_if_fail (internet_address);
-       g_return_if_fail (variable);
-
-       while (camel_internet_address_get (internet_address, address_index, &address_name, &address_email)) {
-               gchar *address = camel_internet_address_format_address (address_name, address_email);
-
-               if (address_index > 0)
-                       g_string_append_printf (emails, ", %s", address);
-               else
-                       g_string_append_printf (emails, "%s", address);
-
-               address_index++;
-               g_free (address);
-       }
-       replace_template_variable (template, variable, emails->str);
-       g_string_free (emails, TRUE);
-}
-
-static CamelMimePart *
-fill_template (CamelMimeMessage *message,
-               CamelMimePart *template)
-{
-       const CamelNameValueArray *headers;
-       CamelContentType *ct;
-       CamelStream *stream;
-       CamelMimePart *return_part;
-       CamelMimePart *message_part = NULL;
-       CamelDataWrapper *dw;
-       CamelInternetAddress *internet_address;
-       GString *template_body;
-       GByteArray *byte_array;
-       gint i;
-       guint jj, len;
-       gboolean message_html, template_html;
-
-       ct = camel_mime_part_get_content_type (template);
-       template_html = ct && camel_content_type_is (ct, "text", "html");
-
-       message_html = FALSE;
-       /* When template is html, then prefer HTML part of the original message. Otherwise go for plaintext */
-       dw = camel_medium_get_content (CAMEL_MEDIUM (message));
-       if (CAMEL_IS_MULTIPART (dw)) {
-               CamelMultipart *multipart = CAMEL_MULTIPART (dw);
-
-               for (i = 0; i < camel_multipart_get_number (multipart); i++) {
-                       CamelMimePart *part = camel_multipart_get_part (multipart, i);
-                       CamelContentType *ct = camel_mime_part_get_content_type (part);
-
-                       if (!ct)
-                               continue;
-
-                       if (camel_content_type_is (ct, "text", "html") && template_html) {
-                               message_part = camel_multipart_get_part (multipart, i);
-                               message_html = TRUE;
-                               break;
-                       } else if (camel_content_type_is (ct, "text", "plain") && message_html == FALSE) {
-                               message_part = camel_multipart_get_part (multipart, i);
-                       }
-               }
-       } else
-               message_part = CAMEL_MIME_PART (message);
-
-       /* Get content of the template */
-       stream = camel_stream_mem_new ();
-       camel_data_wrapper_decode_to_stream_sync (camel_medium_get_content (CAMEL_MEDIUM (template)), stream, 
NULL, NULL);
-       camel_stream_flush (stream, NULL, NULL);
-       byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
-       template_body = g_string_new_len ((gchar *) byte_array->data, byte_array->len);
-       g_object_unref (stream);
-
-       /* Replace all $ORIG[header_name] by respective values */
-       headers = camel_medium_get_headers (CAMEL_MEDIUM (message));
-       len = camel_name_value_array_get_length (headers);
-       for (jj = 0; jj < len; jj++) {
-               const gchar *header_name = NULL, *header_value = NULL;
-
-               if (!camel_name_value_array_get (headers, jj, &header_name, &header_value) ||
-                   !header_name)
-                       continue;
-
-               if (g_ascii_strncasecmp (header_name, "content-", 8) != 0 &&
-                   g_ascii_strcasecmp (header_name, "to") != 0 &&
-                   g_ascii_strcasecmp (header_name, "cc") != 0 &&
-                   g_ascii_strcasecmp (header_name, "bcc") != 0 &&
-                   g_ascii_strcasecmp (header_name, "from") != 0 &&
-                   g_ascii_strcasecmp (header_name, "subject") != 0)
-                       replace_template_variable (template_body, header_name, header_value);
-       }
-
-       /* Now manually replace the *subject* header. The header->value for subject header could be
-        * base64 encoded, so let camel_mime_message to decode it for us if needed */
-       replace_template_variable (template_body, "subject", camel_mime_message_get_subject (message));
-
-       /* Replace TO and FROM modifiers. */
-       internet_address = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO);
-       replace_email_addresses (template_body, internet_address, "to");
-
-       internet_address = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC);
-       replace_email_addresses (template_body, internet_address, "cc");
-
-       internet_address = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_BCC);
-       replace_email_addresses (template_body, internet_address, "bcc");
-
-       internet_address = camel_mime_message_get_from (message);
-       replace_email_addresses (template_body, internet_address, "from");
-
-       /* Now extract body of the original message and replace the $ORIG[body] modifier in template */
-       if (message_part && strstr_nocase (template_body->str, "$ORIG[body]")) {
-               GString *message_body;
-               CamelStream *mem_stream;
-
-               stream = camel_stream_mem_new ();
-               mem_stream = stream;
-
-               ct = camel_mime_part_get_content_type (message_part);
-               if (ct) {
-                       const gchar *charset = camel_content_type_param (ct, "charset");
-                       if (charset && *charset) {
-                               CamelMimeFilter *filter = camel_mime_filter_charset_new (charset, "UTF-8");
-                               if (filter) {
-                                       CamelStream *filtered = camel_stream_filter_new (stream);
-
-                                       if (filtered) {
-                                               camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered), 
filter);
-                                               g_object_unref (stream);
-                                               stream = filtered;
-                                       }
-
-                                       g_object_unref (filter);
-                               }
-                       }
-               }
-
-               camel_data_wrapper_decode_to_stream_sync (camel_medium_get_content (CAMEL_MEDIUM 
(message_part)), stream, NULL, NULL);
-               camel_stream_flush (stream, NULL, NULL);
-               byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem_stream));
-               message_body = g_string_new_len ((gchar *) byte_array->data, byte_array->len);
-               g_object_unref (stream);
-
-               if (template_html && !message_html) {
-                       gchar *html = camel_text_to_html (
-                               message_body->str,
-                               CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
-                               CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
-                               CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
-                               CAMEL_MIME_FILTER_TOHTML_MARK_CITATION |
-                               CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES, 0);
-                       g_string_assign (message_body, html);
-                       g_free (html);
-               } else if (!template_html && message_html) {
-                       g_string_prepend (message_body, "<pre>");
-                       g_string_append (message_body, "</pre>");
-               } /* Other cases should not occur. And even if they happen to do, there's nothing we can 
really do about it */
-
-               replace_template_variable (template_body, "body", message_body->str);
-               g_string_free (message_body, TRUE);
-       } else {
-               replace_template_variable (template_body, "body", "");
-       }
-
-       return_part = camel_mime_part_new ();
-
-       if (template_html)
-               camel_mime_part_set_content (return_part, template_body->str, template_body->len, 
"text/html");
-       else
-               camel_mime_part_set_content (return_part, template_body->str, template_body->len, 
"text/plain");
-
-       g_string_free (template_body, TRUE);
-
-       return return_part;
-}
-
-static CamelMimePart *
-find_template_part_in_multipart (CamelMultipart *multipart,
-                                CamelMultipart *new_multipart)
-{
-       CamelMimePart *template_part = NULL;
-       gint ii;
-
-       for (ii = 0; ii < camel_multipart_get_number (multipart); ii++) {
-               CamelMimePart *part = camel_multipart_get_part (multipart, ii);
-               CamelContentType *ct = camel_mime_part_get_content_type (part);
-
-               if (!template_part && ct && camel_content_type_is (ct, "multipart", "*")) {
-                       CamelDataWrapper *dw;
-
-                       dw = camel_medium_get_content (CAMEL_MEDIUM (part));
-                       template_part = (dw && CAMEL_IS_MULTIPART (dw)) ?
-                               find_template_part_in_multipart (CAMEL_MULTIPART (dw), new_multipart) : NULL;
-
-                       if (!template_part) {
-                               /* Copy any other parts (attachments...) to the output message */
-                               camel_mime_part_set_disposition (part, "attachment");
-                               camel_multipart_add_part (new_multipart, part);
-                       }
-               } else if (ct && camel_content_type_is (ct, "text", "html")) {
-                       template_part = part;
-               } else if (ct && camel_content_type_is (ct, "text", "plain") && !template_part) {
-                       template_part = part;
-               } else {
-                       /* Copy any other parts (attachments...) to the output message */
-                       camel_mime_part_set_disposition (part, "attachment");
-                       camel_multipart_add_part (new_multipart, part);
-               }
-       }
-
-       return template_part;
-}
-
 static void
 create_new_message_composer_created_cb (GObject *source_object,
                                        GAsyncResult *result,
@@ -851,19 +560,7 @@ create_new_message_composer_created_cb (GObject *source_object,
 {
        AsyncContext *context = user_data;
        EAlertSink *alert_sink;
-       CamelMimeMessage *new;
-       CamelMimeMessage *message;
-       CamelMimeMessage *template;
-       CamelMultipart *new_multipart;
-       CamelDataWrapper *dw;
-       const CamelNameValueArray *headers;
-       CamelMimePart *template_part = NULL;
-       CamelFolder *folder;
-       EMailBackend *backend;
-       EMailSession *session;
-       const gchar *message_uid;
        EMsgComposer *composer;
-       guint ii, len;
        GError *error = NULL;
 
        g_return_if_fail (context != NULL);
@@ -873,13 +570,11 @@ create_new_message_composer_created_cb (GObject *source_object,
        composer = e_msg_composer_new_finish (result, &error);
 
        if (e_activity_handle_cancellation (context->activity, error)) {
-               g_warn_if_fail (context->template == NULL);
                async_context_free (context);
                g_error_free (error);
                return;
 
        } else if (error != NULL) {
-               g_warn_if_fail (context->template == NULL);
                e_alert_submit (
                        alert_sink, "mail:no-retrieve-message",
                        error->message, NULL);
@@ -890,154 +585,41 @@ create_new_message_composer_created_cb (GObject *source_object,
 
        g_return_if_fail (E_IS_MSG_COMPOSER (composer));
 
-       message = context->message;
-       message_uid = context->message_uid;
-       template = context->template;
-
-       backend = e_mail_reader_get_backend (context->reader);
-       session = e_mail_backend_get_session (backend);
-
-       folder = e_mail_session_get_local_folder (session, E_MAIL_LOCAL_FOLDER_TEMPLATES);
-
-       new = camel_mime_message_new ();
-       new_multipart = camel_multipart_new ();
-       camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (new_multipart), "multipart/alternative");
-       camel_multipart_set_boundary (new_multipart, NULL);
-
-       dw = camel_medium_get_content (CAMEL_MEDIUM (template));
-       /* If template is a multipart, then try to use HTML. When no HTML part is available, use plaintext. 
Every other
-        * add as an attachment */
-       if (CAMEL_IS_MULTIPART (dw)) {
-               template_part = find_template_part_in_multipart (CAMEL_MULTIPART (dw), new_multipart);
-       } else {
-               CamelContentType *ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (template));
-
-               if (ct && (camel_content_type_is (ct, "text", "html") ||
-                   camel_content_type_is (ct, "text", "plain"))) {
-                       template_part = CAMEL_MIME_PART (template);
-               }
-       }
-
-       g_warn_if_fail (template_part != NULL);
-
-       if (template_part) {
-               CamelMimePart *out_part = NULL;
-
-               /* Here replace all the modifiers in template body by values
-                  from message and return the newly created part */
-               out_part = fill_template (message, template_part);
-
-               /* Assigning part directly to mime_message causes problem with
-                  "Content-type" header displaying in the HTML message (camel parsing bug?) */
-               camel_multipart_add_part (new_multipart, out_part);
-               g_object_unref (out_part);
-       }
-
-       camel_medium_set_content (CAMEL_MEDIUM (new), CAMEL_DATA_WRAPPER (new_multipart));
-
-       /* Add the headers from the message we are replying to, so CC and that
-        * stuff is preserved. Also replace any $ORIG[header-name] modifiers ignoring
-        * 'content-*' headers */
-       headers = camel_medium_dup_headers (CAMEL_MEDIUM (message));
-       len = camel_name_value_array_get_length (headers);
-       for (ii = 0; ii < len; ii++) {
-               const gchar *header_name = NULL, *header_value = NULL;
-
-               if (!camel_name_value_array_get (headers, ii, &header_name, &header_value) ||
-                   !header_name)
-                       continue;
-
-               if (g_ascii_strncasecmp (header_name, "content-", 8) != 0 &&
-                   g_ascii_strcasecmp (header_name, "from") != 0) {
-                       gchar *new_header_value = NULL;
-
-                       /* Some special handling of the 'subject' header */
-                       if (g_ascii_strncasecmp (header_name, "subject", 7) == 0) {
-                               GString *subject = g_string_new (camel_mime_message_get_subject (template));
-                               guint jj;
-
-                               /* Now replace all possible $ORIG[]s in the subject line by values from 
original message */
-                               for (jj = 0; jj < len; jj++) {
-                                       const gchar *m_header_name = NULL, *m_header_value = NULL;
-
-                                       if (camel_name_value_array_get (headers, jj, &m_header_name, 
&m_header_value) &&
-                                           m_header_name &&
-                                           g_ascii_strncasecmp (m_header_name, "content-", 8) != 0 &&
-                                           g_ascii_strcasecmp (m_header_name, "subject") != 0)
-                                               replace_template_variable (subject, m_header_name, 
m_header_value);
-                               }
-                               /* Now replace $ORIG[subject] variable, handling possible base64 encryption */
-                               replace_template_variable (
-                                       subject, "subject",
-                                       camel_mime_message_get_subject (message));
-                               new_header_value = g_string_free (subject, FALSE);
-                       }
-
-                       camel_medium_add_header (CAMEL_MEDIUM (new), header_name, new_header_value ? 
new_header_value : header_value);
-
-                       g_free (new_header_value);
-               }
-       }
-
-       /* Set the To: field to the same To: field of the message we are replying to. */
-       camel_mime_message_set_recipients (
-               new, CAMEL_RECIPIENT_TYPE_TO,
-               camel_mime_message_get_reply_to (message) ? camel_mime_message_get_reply_to (message) :
-               camel_mime_message_get_from (message));
-
-       /* Copy the CC and BCC from the template.*/
-       camel_mime_message_set_recipients (
-               new, CAMEL_RECIPIENT_TYPE_CC,
-               camel_mime_message_get_recipients (
-                       template, CAMEL_RECIPIENT_TYPE_CC));
-
-       camel_mime_message_set_recipients (
-               new, CAMEL_RECIPIENT_TYPE_BCC,
-               camel_mime_message_get_recipients (
-                       template, CAMEL_RECIPIENT_TYPE_BCC));
-
        /* Create the composer */
-       em_utils_edit_message (composer, folder, new, message_uid, TRUE);
-       if (composer && context->source_folder_uri && context->message_uid)
+       em_utils_edit_message (composer, context->template_folder, context->new_message, 
context->source_message_uid, TRUE);
+       if (composer && context->source_folder_uri && context->source_message_uid)
                e_msg_composer_set_source_headers (
                        composer, context->source_folder_uri,
-                       context->message_uid, CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN);
-
-       g_object_unref (new_multipart);
-       g_object_unref (new);
+                       context->source_message_uid, CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN);
 
        async_context_free (context);
 }
 
 static void
-create_new_message (GObject *source_object,
-                    GAsyncResult *result,
-                    gpointer user_data)
+templates_template_applied_cb (GObject *source_object,
+                              GAsyncResult *result,
+                              gpointer user_data)
 {
        AsyncContext *context = user_data;
        EAlertSink *alert_sink;
        EMailBackend *backend;
        EShell *shell;
-       CamelFolder *folder;
        GError *error = NULL;
 
-       g_return_if_fail (CAMEL_IS_FOLDER (source_object));
        g_return_if_fail (context != NULL);
 
-       folder = CAMEL_FOLDER (source_object);
-
        alert_sink = e_activity_get_alert_sink (context->activity);
 
-       context->template = camel_folder_get_message_finish (folder, result, &error);
+       context->new_message = e_mail_templates_apply_finish (source_object, result, &error);
 
        if (e_activity_handle_cancellation (context->activity, error)) {
-               g_warn_if_fail (context->template == NULL);
+               g_warn_if_fail (context->new_message == NULL);
                async_context_free (context);
                g_error_free (error);
                return;
 
        } else if (error != NULL) {
-               g_warn_if_fail (context->template == NULL);
+               g_warn_if_fail (context->new_message == NULL);
                e_alert_submit (
                        alert_sink, "mail:no-retrieve-message",
                        error->message, NULL);
@@ -1046,7 +628,7 @@ create_new_message (GObject *source_object,
                return;
        }
 
-       g_return_if_fail (CAMEL_IS_MIME_MESSAGE (context->template));
+       g_warn_if_fail (context->new_message != NULL);
 
        backend = e_mail_reader_get_backend (context->reader);
        shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
@@ -1060,12 +642,10 @@ template_got_source_message (CamelFolder *folder,
                              AsyncContext *context)
 {
        EAlertSink *alert_sink;
-       GCancellable *cancellable;
        CamelMimeMessage *message;
        GError *error = NULL;
 
        alert_sink = e_activity_get_alert_sink (context->activity);
-       cancellable = e_activity_get_cancellable (context->activity);
 
        message = camel_folder_get_message_finish (folder, result, &error);
 
@@ -1087,19 +667,14 @@ template_got_source_message (CamelFolder *folder,
 
        g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
 
-       context->message = message;
-
-       /* Now fetch the template message. */
+       context->source_message = message;
 
-       camel_folder_get_message (
-               context->template_folder,
-               context->template_message_uid,
-               G_PRIORITY_DEFAULT, cancellable,
-               create_new_message, context);
+       e_mail_templates_apply (context->source_message, context->template_folder, 
context->template_message_uid,
+               e_activity_get_cancellable (context->activity), templates_template_applied_cb, context);
 }
 
 static void
-action_reply_with_template_cb (ETemplatesStore *templates_store,
+action_reply_with_template_cb (EMailTemplatesStore *templates_store,
                               CamelFolder *template_folder,
                               const gchar *template_message_uid,
                               gpointer user_data)
@@ -1135,10 +710,10 @@ action_reply_with_template_cb (ETemplatesStore *templates_store,
        em_utils_get_real_folder_uri_and_message_uid (
                folder, message_uid,
                &context->source_folder_uri,
-               &context->message_uid);
+               &context->source_message_uid);
 
-       if (context->message_uid == NULL)
-               context->message_uid = g_strdup (message_uid);
+       if (context->source_message_uid == NULL)
+               context->source_message_uid = g_strdup (message_uid);
 
        camel_folder_get_message (
                folder, message_uid, G_PRIORITY_DEFAULT,
@@ -1343,7 +918,7 @@ templates_update_actions_cb (EShellView *shell_view,
                        shell_window = e_shell_view_get_shell_window (shell_view);
                        ui_manager = e_shell_window_get_ui_manager (shell_window);
 
-                       e_templates_store_build_menu (td->templates_store, shell_view, ui_manager, 
action_group,
+                       e_mail_templates_store_build_menu (td->templates_store, shell_view, ui_manager, 
action_group,
                                "/mail-message-popup/mail-message-templates", td->merge_id,
                                action_reply_with_template_cb, shell_view);
                }
@@ -1370,7 +945,7 @@ init_composer_actions (GtkUIManager *ui_manager,
 }
 
 static void
-templates_store_changed_cb (ETemplatesStore *templates_store,
+templates_store_changed_cb (EMailTemplatesStore *templates_store,
                            gpointer user_data)
 {
        TemplatesData *td = user_data;
@@ -1401,7 +976,7 @@ mail_shell_view_created_cb (EShellWindow *shell_window,
        session = e_mail_backend_get_session (backend);
 
        td = g_new0 (TemplatesData, 1);
-       td->templates_store = e_templates_store_ref_default (e_mail_ui_session_get_account_store 
(E_MAIL_UI_SESSION (session)));
+       td->templates_store = e_mail_templates_store_ref_default (e_mail_ui_session_get_account_store 
(E_MAIL_UI_SESSION (session)));
        td->changed_handler_id = g_signal_connect (td->templates_store, "changed", G_CALLBACK 
(templates_store_changed_cb), td);
        td->merge_id = gtk_ui_manager_new_merge_id (ui_manager);
        td->changed = TRUE;


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