[evolution] Bug 602612 - Add 'Alternative Reply' menu option
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] Bug 602612 - Add 'Alternative Reply' menu option
- Date: Mon, 12 Mar 2018 13:42:02 +0000 (UTC)
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]