[evolution/wip/mcrha/webkit-jsc-api] Make EContentEditor::get_content() ansynchronous function (untested)
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/mcrha/webkit-jsc-api] Make EContentEditor::get_content() ansynchronous function (untested)
- Date: Fri, 15 Nov 2019 11:27:10 +0000 (UTC)
commit b790fb8e421eb9976a0a95ab8b6ebfc04a52ee9e
Author: Milan Crha <mcrha redhat com>
Date: Fri Nov 15 12:27:31 2019 +0100
Make EContentEditor::get_content() ansynchronous function (untested)
data/webkit/e-editor.js | 142 +++++
src/composer/e-composer-actions.c | 36 +-
src/composer/e-composer-private.c | 2 +
src/composer/e-composer-private.h | 3 +
src/composer/e-msg-composer.c | 637 +++++++++++++++------
src/composer/e-msg-composer.h | 2 +
src/e-util/e-content-editor.c | 367 +++++++++++-
src/e-util/e-content-editor.h | 84 ++-
src/e-util/e-html-editor.c | 173 ++++--
src/e-util/e-html-editor.h | 7 +-
src/e-util/e-mail-signature-editor.c | 96 ++--
src/e-util/e-util-enums.h | 33 +-
src/e-util/test-html-editor-units-utils.c | 95 ++-
src/e-util/test-html-editor.c | 140 ++++-
src/mail/e-mail-notes.c | 162 ++++--
.../composer-to-meeting/e-composer-to-meeting.c | 120 ++--
src/modules/webkit-editor/e-webkit-editor.c | 290 +++++-----
src/plugins/external-editor/external-editor.c | 71 ++-
18 files changed, 1832 insertions(+), 628 deletions(-)
---
diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js
index 6e3ee6edff..8cf407a603 100644
--- a/data/webkit/e-editor.js
+++ b/data/webkit/e-editor.js
@@ -42,6 +42,14 @@ var EvoEditor = {
E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN : 12,
E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA : 13,
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES : 1 << 0,
+ E_CONTENT_EDITOR_GET_RAW_BODY_HTML : 1 << 1,
+ E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN : 1 << 2,
+ E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED : 1 << 3,
+ E_CONTENT_EDITOR_GET_RAW_DRAFT : 1 << 4,
+ E_CONTENT_EDITOR_GET_TO_SEND_HTML : 1 << 5,
+ E_CONTENT_EDITOR_GET_TO_SEND_PLAIN : 1 << 6,
+
/* Flags for ClaimAffectedContent() */
CLAIM_CONTENT_FLAG_NONE : 0,
CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE : 1 << 0,
@@ -1233,6 +1241,140 @@ EvoEditor.SetMode = function(mode)
}
}
+EvoEditor.GetContent = function(flags, cid_uid_prefix)
+{
+ var content_data = {}, img_elems = [], elems, ii, jj;
+
+ if (!document.body)
+ return content_data;
+
+ EvoUndoRedo.Disable();
+
+ try {
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED) != 0) {
+ var hidden_elems = [];
+
+ try {
+ elems = document.getElementsByClassName("-x-evo-signature-wrapper");
+ if (elems && elems.length) {
+ for (ii = 0; ii < elems.length; ii++) {
+ var elem = elems.item(ii);
+
+ if (elem && !elem.hidden) {
+ hidden_elems[hidden_elems.length] = elem;
+ elem.hidden = true;
+ }
+ }
+ }
+
+ elems = document.getElementsByTagName("BLOCKQUOTE");
+ if (elems && elems.length) {
+ for (ii = 0; ii < elems.length; ii++) {
+ var elem = elems.item(ii);
+
+ if (elem && !elem.hidden) {
+ hidden_elems[hidden_elems.length] = elem;
+ elem.hidden = true;
+ }
+ }
+ }
+
+ content_data["raw-body-stripped"] = document.body.innerText;
+ } finally {
+ for (ii = 0; ii < hidden_elems.length; ii++) {
+ hidden_elems[ii].hidden = false;
+ }
+ }
+ }
+
+ // Do these before changing image sources
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_RAW_BODY_HTML) != 0)
+ content_data["raw-body-html"] = document.body.innerHTML;
+
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN) != 0)
+ content_data["raw-body-plain"] = document.body.innerText;
+
+ if (EvoEditor.mode == EvoEditor.MODE_HTML &&
+ (flags & EvoEditor.E_CONTENT_EDITOR_GET_INLINE_IMAGES) != 0) {
+ var images = [];
+
+ for (ii = 0; ii < document.images.length; ii++) {
+ var elem = document.images.item(ii);
+
+ if (elem && elem.src && (
+ elem.src.toLowerCase().startsWith("data:") ||
+ elem.src.toLowerCase().startsWith("file://"))) {
+ for (jj = 0; jj < img_elems.length; jj++) {
+ if (elem.src == img_elems[jj].orig_src) {
+ elem.subelems[elem.subelems.length] = elem;
+ elem.src = img_elems[jj].cid;
+ break;
+ }
+ }
+
+ if (jj >= img_elems.length) {
+ var img_obj = {
+ subelems : [ elem ],
+ cid : "cid:" + cid_uid_prefix + "-" +
img_elems.length,
+ orig_src : elem.src
+ };
+
+ if (elem.src.toLowerCase().startsWith("cid:"))
+ img_obj.cid = elem.src;
+
+ img_elems[img_elems.length] = img_obj;
+ images[images.length] = {
+ cid : img_obj.cid,
+ src : elem.src
+ };
+ elem.src = img_obj.cid;
+ }
+ } else if (elem && elem.src && elem.src.toLowerCase().startsWith("cid:")) {
+ images[images.length] = {
+ cid : elem.src,
+ src : elem.src
+ };
+ }
+ }
+
+ if (images.length)
+ content_data["images"] = images;
+ }
+
+ // Draft should have replaced images as well
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_RAW_DRAFT) != 0) {
+ document.head.setAttribute("x-evo-selection",
EvoSelection.ToString(EvoSelection.Store(document)));
+ try {
+ content_data["raw-draft"] = document.documentElement.innerHTML;
+ } finally {
+ document.head.removeAttribute("x-evo-selection");
+ }
+ }
+
+ if (EvoEditor.mode == EvoEditor.MODE_HTML &&
+ (flags & EvoEditor.E_CONTENT_EDITOR_GET_TO_SEND_HTML) != 0)
+ content_data["to-send-html"] = EvoEditor.convertHtmlToSend();
+
+ if ((flags & EvoEditor. E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) != 0) {
+ content_data["to-send-plain"] = EvoConvertToPlainText(document.body);
+ }
+ } finally {
+ try {
+ for (ii = 0; ii < img_elems.length; ii++) {
+ var img_obj = img_elems[ii];
+
+ for (jj = 0; jj < img_obj.subelems.length; jj++) {
+ img_obj.subelems[jj].src = img_obj.orig_src;
+ }
+ }
+ } finally {
+ EvoUndoRedo.Enable();
+ }
+ }
+
+ return content_data;
+}
+
document.onload = EvoEditor.initializeContent;
document.onselectionchange = function() {
diff --git a/src/composer/e-composer-actions.c b/src/composer/e-composer-actions.c
index 6990e19023..5cb03cab94 100644
--- a/src/composer/e-composer-actions.c
+++ b/src/composer/e-composer-actions.c
@@ -162,6 +162,30 @@ action_print_preview_cb (GtkAction *action,
e_msg_composer_print (composer, print_action);
}
+static void
+action_save_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EMsgComposer *composer = user_data;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (E_IS_HTML_EDITOR (source_object));
+
+ if (!e_html_editor_save_finish (E_HTML_EDITOR (source_object), result, &error)) {
+ e_alert_submit (
+ E_ALERT_SINK (composer),
+ E_ALERT_NO_SAVE_FILE,
+ e_html_editor_get_filename (E_HTML_EDITOR (source_object)), error ? error->message :
_("Unknown error"), NULL);
+ } else {
+ composer_set_content_editor_changed (composer);
+ }
+
+ g_object_unref (composer);
+ g_clear_error (&error);
+}
+
static void
action_save_cb (GtkAction *action,
EMsgComposer *composer)
@@ -169,7 +193,6 @@ action_save_cb (GtkAction *action,
EHTMLEditor *editor;
const gchar *filename;
gint fd;
- GError *error = NULL;
editor = e_msg_composer_get_editor (composer);
filename = e_html_editor_get_filename (editor);
@@ -202,16 +225,7 @@ action_save_cb (GtkAction *action,
} else
close (fd);
- if (!e_html_editor_save (editor, filename, TRUE, &error)) {
- e_alert_submit (
- E_ALERT_SINK (composer),
- E_ALERT_NO_SAVE_FILE,
- filename, error->message, NULL);
- g_error_free (error);
- return;
- }
-
- composer_set_content_editor_changed (composer);
+ e_html_editor_save (editor, filename, TRUE, NULL, action_save_ready_cb, g_object_ref (composer));
}
static void
diff --git a/src/composer/e-composer-private.c b/src/composer/e-composer-private.c
index 8b6b8b4625..e4a1c17924 100644
--- a/src/composer/e-composer-private.c
+++ b/src/composer/e-composer-private.c
@@ -552,6 +552,8 @@ e_composer_private_finalize (EMsgComposer *composer)
g_free (composer->priv->mime_type);
g_free (composer->priv->mime_body);
g_free (composer->priv->previous_identity_uid);
+
+ g_clear_pointer (&composer->priv->content_hash, e_content_editor_util_free_content_hash);
}
gchar *
diff --git a/src/composer/e-composer-private.h b/src/composer/e-composer-private.h
index 4a2e2e3e06..c415974cbc 100644
--- a/src/composer/e-composer-private.h
+++ b/src/composer/e-composer-private.h
@@ -121,6 +121,9 @@ struct _EMsgComposerPrivate {
gulong drag_data_received_handler_id;
gchar *previous_identity_uid;
+
+ guint content_hash_ref_count; /* when reaches 0, the content_hash is freed; to be able to reuse it */
+ EContentEditorContentHash *content_hash;
};
void e_composer_private_constructed (EMsgComposer *composer);
diff --git a/src/composer/e-msg-composer.c b/src/composer/e-msg-composer.c
index e4c9ac095e..5f20646fec 100644
--- a/src/composer/e-msg-composer.c
+++ b/src/composer/e-msg-composer.c
@@ -179,6 +179,19 @@ async_context_free (AsyncContext *context)
g_slice_free (AsyncContext, context);
}
+static void
+e_msg_composer_unref_content_hash (EMsgComposer *composer)
+{
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (composer->priv->content_hash_ref_count > 0);
+
+ composer->priv->content_hash_ref_count--;
+
+ if (!composer->priv->content_hash_ref_count) {
+ g_clear_pointer (&composer->priv->content_hash, e_content_editor_util_free_content_hash);
+ }
+}
+
static void
e_msg_composer_inc_soft_busy (EMsgComposer *composer)
{
@@ -1404,7 +1417,7 @@ composer_build_message (EMsgComposer *composer,
type = camel_content_type_decode (priv->mime_type);
} else {
- gchar *text;
+ const gchar *text;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
@@ -1412,15 +1425,12 @@ composer_build_message (EMsgComposer *composer,
cnt_editor = e_html_editor_get_content_editor (editor);
data = g_byte_array_new ();
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
+ text = e_content_editor_util_get_content_data (e_msg_composer_get_content_hash (composer),
+ E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
if (!text) {
g_warning ("%s: Failed to retrieve text/plain processed content", G_STRFUNC);
- text = g_strdup ("");
+ text = "";
last_error = e_content_editor_dup_last_error (cnt_editor);
}
@@ -1428,7 +1438,6 @@ composer_build_message (EMsgComposer *composer,
g_byte_array_append (data, (guint8 *) text, strlen (text));
if (!g_str_has_suffix (text, "\r\n"))
g_byte_array_append (data, (const guint8 *) "\r\n", 2);
- g_free (text);
type = camel_content_type_new ("text", "plain");
charset = best_charset (
@@ -1488,16 +1497,11 @@ composer_build_message (EMsgComposer *composer,
if ((flags & COMPOSER_FLAG_HTML_CONTENT) != 0 ||
(flags & COMPOSER_FLAG_SAVE_DRAFT) != 0) {
- gchar *text;
+ const gchar *text;
gsize length;
gboolean pre_encode;
- EHTMLEditor *editor;
- EContentEditor *cnt_editor;
GSList *inline_images_parts = NULL, *link;
- editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (editor);
-
data = g_byte_array_new ();
if ((flags & COMPOSER_FLAG_SAVE_DRAFT) != 0) {
/* X-Evolution-Format */
@@ -1508,39 +1512,31 @@ composer_build_message (EMsgComposer *composer,
composer_add_evolution_composer_mode_header (
CAMEL_MEDIUM (context->message), composer);
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_INLINE_IMAGES,
- from_domain, &inline_images_parts);
+ text = e_content_editor_util_get_content_data (e_msg_composer_get_content_hash
(composer),
+ E_CONTENT_EDITOR_GET_RAW_DRAFT);
if (!text) {
g_warning ("%s: Failed to retrieve draft content", G_STRFUNC);
- text = g_strdup ("");
+ text = "";
}
} else {
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_PROCESSED |
- E_CONTENT_EDITOR_GET_INLINE_IMAGES,
- from_domain, &inline_images_parts);
+ text = e_content_editor_util_get_content_data (e_msg_composer_get_content_hash
(composer),
+ E_CONTENT_EDITOR_GET_TO_SEND_HTML);
if (!text) {
g_warning ("%s: Failed to retrieve HTML processed content", G_STRFUNC);
- text = g_strdup ("");
+ text = "";
}
}
- if (!last_error)
- last_error = e_content_editor_dup_last_error (cnt_editor);
+ inline_images_parts = e_content_editor_util_get_content_data (e_msg_composer_get_content_hash
(composer),
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES);
length = strlen (text);
g_byte_array_append (data, (guint8 *) text, (guint) length);
if (!g_str_has_suffix (text, "\r\n"))
g_byte_array_append (data, (const guint8 *) "\r\n", 2);
pre_encode = text_requires_quoted_printable (text, length);
- g_free (text);
mem_stream = camel_stream_mem_new_with_byte_array (data);
stream = camel_stream_filter_new (mem_stream);
@@ -4228,40 +4224,198 @@ e_msg_composer_get_shell (EMsgComposer *composer)
return E_SHELL (composer->priv->shell);
}
+/**
+ * e_msg_composer_get_content_hash:
+ * @composer: an #EMsgComposer
+ *
+ * Returns current #EContentEditorContentHash with content
+ * of the composer. It's valid, and available, only during
+ * operations/signals, which construct message from the @composer
+ * content. The @composer precaches the content, thus it can
+ * be accessed in a synchronous way (in constrast to EContentEditor,
+ * which allows getting the content only asynchronously).
+ * The content hash is owned by the @composer and it is freed
+ * as soon as the respective operation is finished.
+ *
+ * Returns: (transfer none) (nullable): an #EContentEditorContentHash
+ * with current content data, or %NULL, when it is not loaded.
+ *
+ * Since: 3.36
+ **/
+EContentEditorContentHash *
+e_msg_composer_get_content_hash (EMsgComposer *composer)
+{
+ g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
+
+ /* Calling the function out of expected place should warn that something goes wrong */
+ g_warn_if_fail (composer->priv->content_hash != NULL);
+
+ return composer->priv->content_hash;
+}
+
+typedef void (* PrepareContentHashCallback) (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error);
+
+typedef struct _PrepareContentHashData {
+ EMsgComposer *composer;
+ PrepareContentHashCallback callback;
+ gpointer user_data;
+} PrepareContentHashData;
+
+static PrepareContentHashData *
+prepare_content_hash_data_new (EMsgComposer *composer,
+ PrepareContentHashCallback callback,
+ gpointer user_data)
+{
+ PrepareContentHashData *pchd;
+
+ pchd = g_slice_new (PrepareContentHashData);
+ pchd->composer = g_object_ref (composer);
+ pchd->callback = callback;
+ pchd->user_data = user_data;
+
+ return pchd;
+}
+
+static void
+prepare_content_hash_data_free (gpointer ptr)
+{
+ PrepareContentHashData *pchd = ptr;
+
+ if (pchd) {
+ g_clear_object (&pchd->composer);
+ g_slice_free (PrepareContentHashData, pchd);
+ }
+}
+
+static void
+e_msg_composer_prepare_content_hash_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ PrepareContentHashData *pchd = user_data;
+ EContentEditorContentHash *content_hash;
+ GError *error = NULL;
+
+ g_return_if_fail (pchd != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ if (content_hash) {
+ g_warn_if_fail (pchd->composer->priv->content_hash == NULL);
+ g_warn_if_fail (pchd->composer->priv->content_hash_ref_count == 0);
+
+ pchd->composer->priv->content_hash = content_hash;
+ pchd->composer->priv->content_hash_ref_count = 1;
+ }
+
+ pchd->callback (pchd->composer, pchd->user_data, error);
+
+ prepare_content_hash_data_free (pchd);
+ g_clear_error (&error);
+}
+
+static void
+e_msg_composer_prepare_content_hash (EMsgComposer *composer,
+ GCancellable *cancellable,
+ EActivity *activity,
+ PrepareContentHashCallback callback,
+ gpointer user_data)
+{
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ CamelInternetAddress *from;
+ PrepareContentHashData *pchd;
+ const gchar *from_domain = NULL;
+
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (callback != NULL);
+
+ if (e_msg_composer_get_content_hash (composer)) {
+ composer->priv->content_hash_ref_count++;
+
+ callback (composer, user_data, NULL);
+ return;
+ }
+
+ if (activity)
+ e_activity_set_text (activity, _("Reading text content…"));
+
+ pchd = prepare_content_hash_data_new (composer, callback, user_data);
+ editor = e_msg_composer_get_editor (composer);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ from = e_msg_composer_get_from (composer);
+
+ if (from && camel_internet_address_get (from, 0, NULL, &from_domain)) {
+ const gchar *at = strchr (from_domain, '@');
+
+ if (at)
+ from_domain = at + 1;
+ else
+ from_domain = NULL;
+ }
+
+ if (!from_domain || !*from_domain)
+ from_domain = "localhost";
+
+ e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_ALL, from_domain, cancellable,
+ e_msg_composer_prepare_content_hash_ready_cb, pchd);
+
+ g_clear_object (&from);
+}
+
+static gboolean
+e_msg_composer_claim_no_build_message_error (EMsgComposer *composer,
+ EActivity *activity,
+ const GError *error,
+ gboolean unref_content_hash_on_error)
+{
+ g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), FALSE);
+
+ if (error) {
+ if (!e_activity_handle_cancellation (activity, error)) {
+ EAlertSink *alert_sink;
+
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ e_alert_submit (
+ alert_sink,
+ "mail-composer:no-build-message",
+ error->message, NULL);
+ }
+
+ if (e_msg_composer_is_exiting (composer)) {
+ gtk_window_present (GTK_WINDOW (composer));
+ composer->priv->application_exiting = FALSE;
+ }
+
+ gtk_window_present (GTK_WINDOW (composer));
+
+ if (unref_content_hash_on_error)
+ e_msg_composer_unref_content_hash (composer);
+ }
+
+ return error != NULL;
+}
+
static void
msg_composer_send_cb (EMsgComposer *composer,
GAsyncResult *result,
AsyncContext *context)
{
CamelMimeMessage *message;
- EAlertSink *alert_sink;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
GError *error = NULL;
- alert_sink = e_activity_get_alert_sink (context->activity);
-
message = e_msg_composer_get_message_finish (composer, result, &error);
- if (e_activity_handle_cancellation (context->activity, error)) {
- g_warn_if_fail (message == NULL);
- async_context_free (context);
- g_error_free (error);
-
- gtk_window_present (GTK_WINDOW (composer));
- return;
- }
-
- if (error != NULL) {
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, TRUE)) {
g_warn_if_fail (message == NULL);
- e_alert_submit (
- alert_sink,
- "mail-composer:no-build-message",
- error->message, NULL);
async_context_free (context);
- g_error_free (error);
-
- gtk_window_present (GTK_WINDOW (composer));
+ g_clear_error (&error);
return;
}
@@ -4282,9 +4436,47 @@ msg_composer_send_cb (EMsgComposer *composer,
g_object_unref (message);
+ e_msg_composer_unref_content_hash (composer);
async_context_free (context);
}
+static void
+e_msg_composer_send_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ AsyncContext *context = user_data;
+ gboolean proceed_with_send = TRUE;
+
+ g_return_if_fail (context != NULL);
+
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, FALSE)) {
+ async_context_free (context);
+ return;
+ }
+
+ /* This gives the user a chance to abort the send. */
+ g_signal_emit (composer, signals[PRESEND], 0, &proceed_with_send);
+
+ if (!proceed_with_send) {
+ gtk_window_present (GTK_WINDOW (composer));
+ e_msg_composer_unref_content_hash (composer);
+
+ if (e_msg_composer_is_exiting (composer)) {
+ gtk_window_present (GTK_WINDOW (composer));
+ composer->priv->application_exiting = FALSE;
+ }
+
+ async_context_free (context);
+ return;
+ }
+
+ e_msg_composer_get_message (
+ composer, G_PRIORITY_DEFAULT, e_activity_get_cancellable (context->activity),
+ (GAsyncReadyCallback) msg_composer_send_cb,
+ context);
+}
+
/**
* e_msg_composer_send:
* @composer: an #EMsgComposer
@@ -4297,18 +4489,9 @@ e_msg_composer_send (EMsgComposer *composer)
EHTMLEditor *editor;
AsyncContext *context;
GCancellable *cancellable;
- gboolean proceed_with_send = TRUE;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
- /* This gives the user a chance to abort the send. */
- g_signal_emit (composer, signals[PRESEND], 0, &proceed_with_send);
-
- if (!proceed_with_send) {
- gtk_window_present (GTK_WINDOW (composer));
- return;
- }
-
editor = e_msg_composer_get_editor (composer);
context = g_slice_new0 (AsyncContext);
@@ -4316,10 +4499,8 @@ e_msg_composer_send (EMsgComposer *composer)
cancellable = e_activity_get_cancellable (context->activity);
- e_msg_composer_get_message (
- composer, G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) msg_composer_send_cb,
- context);
+ e_msg_composer_prepare_content_hash (composer, cancellable, context->activity,
+ e_msg_composer_send_content_hash_ready_cb, context);
}
static void
@@ -4352,43 +4533,16 @@ msg_composer_save_to_drafts_cb (EMsgComposer *composer,
AsyncContext *context)
{
CamelMimeMessage *message;
- EAlertSink *alert_sink;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
GError *error = NULL;
- alert_sink = e_activity_get_alert_sink (context->activity);
-
- message = e_msg_composer_get_message_draft_finish (
- composer, result, &error);
-
- if (e_activity_handle_cancellation (context->activity, error)) {
- g_warn_if_fail (message == NULL);
- async_context_free (context);
- g_error_free (error);
-
- if (e_msg_composer_is_exiting (composer)) {
- gtk_window_present (GTK_WINDOW (composer));
- composer->priv->application_exiting = FALSE;
- }
-
- return;
- }
+ message = e_msg_composer_get_message_draft_finish (composer, result, &error);
- if (error != NULL) {
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, TRUE)) {
g_warn_if_fail (message == NULL);
- e_alert_submit (
- alert_sink,
- "mail-composer:no-build-message",
- error->message, NULL);
async_context_free (context);
- g_error_free (error);
-
- if (e_msg_composer_is_exiting (composer)) {
- gtk_window_present (GTK_WINDOW (composer));
- composer->priv->application_exiting = FALSE;
- }
-
+ g_clear_error (&error);
return;
}
@@ -4410,9 +4564,34 @@ msg_composer_save_to_drafts_cb (EMsgComposer *composer,
G_OBJECT (context->activity),
msg_composer_save_to_drafts_done_cb, composer);
+ e_msg_composer_unref_content_hash (composer);
async_context_free (context);
}
+static void
+e_msg_composer_save_to_drafts_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ AsyncContext *context = user_data;
+
+ g_return_if_fail (context != NULL);
+
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, FALSE)) {
+ if (e_msg_composer_is_exiting (composer)) {
+ gtk_window_present (GTK_WINDOW (composer));
+ composer->priv->application_exiting = FALSE;
+ }
+ async_context_free (context);
+ return;
+ }
+
+ e_msg_composer_get_message_draft (
+ composer, G_PRIORITY_DEFAULT, e_activity_get_cancellable (context->activity),
+ (GAsyncReadyCallback) msg_composer_save_to_drafts_cb,
+ context);
+}
+
/**
* e_msg_composer_save_to_drafts:
* @composer: an #EMsgComposer
@@ -4436,10 +4615,8 @@ e_msg_composer_save_to_drafts (EMsgComposer *composer)
cancellable = e_activity_get_cancellable (context->activity);
- e_msg_composer_get_message_draft (
- composer, G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) msg_composer_save_to_drafts_cb,
- context);
+ e_msg_composer_prepare_content_hash (composer, cancellable, context->activity,
+ e_msg_composer_save_to_drafts_content_hash_ready_cb, context);
}
static void
@@ -4448,30 +4625,16 @@ msg_composer_save_to_outbox_cb (EMsgComposer *composer,
AsyncContext *context)
{
CamelMimeMessage *message;
- EAlertSink *alert_sink;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
GError *error = NULL;
- alert_sink = e_activity_get_alert_sink (context->activity);
-
message = e_msg_composer_get_message_finish (composer, result, &error);
- if (e_activity_handle_cancellation (context->activity, error)) {
- g_warn_if_fail (message == NULL);
- async_context_free (context);
- g_error_free (error);
- return;
- }
-
- if (error != NULL) {
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, TRUE)) {
g_warn_if_fail (message == NULL);
- e_alert_submit (
- alert_sink,
- "mail-composer:no-build-message",
- error->message, NULL);
async_context_free (context);
- g_error_free (error);
+ g_clear_error (&error);
return;
}
@@ -4483,11 +4646,49 @@ msg_composer_save_to_outbox_cb (EMsgComposer *composer,
g_object_unref (message);
- async_context_free (context);
-
editor = e_msg_composer_get_editor (composer);
cnt_editor = e_html_editor_get_content_editor (editor);
e_content_editor_set_changed (cnt_editor, TRUE);
+
+ async_context_free (context);
+}
+
+static void
+e_msg_composer_save_to_outbox_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ AsyncContext *context = user_data;
+
+ g_return_if_fail (context != NULL);
+
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, FALSE)) {
+ async_context_free (context);
+ return;
+ }
+
+ if (!composer->priv->is_sending_message) {
+ gboolean proceed_with_save = TRUE;
+
+ /* This gives the user a chance to abort the save. */
+ g_signal_emit (composer, signals[PRESEND], 0, &proceed_with_save);
+
+ if (!proceed_with_save) {
+ if (e_msg_composer_is_exiting (composer)) {
+ gtk_window_present (GTK_WINDOW (composer));
+ composer->priv->application_exiting = FALSE;
+ }
+
+ e_msg_composer_unref_content_hash (composer);
+ async_context_free (context);
+ return;
+ }
+ }
+
+ e_msg_composer_get_message (
+ composer, G_PRIORITY_DEFAULT, e_activity_get_cancellable (context->activity),
+ (GAsyncReadyCallback) msg_composer_save_to_outbox_cb,
+ context);
}
/**
@@ -4505,16 +4706,6 @@ e_msg_composer_save_to_outbox (EMsgComposer *composer)
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
- if (!composer->priv->is_sending_message) {
- gboolean proceed_with_save = TRUE;
-
- /* This gives the user a chance to abort the save. */
- g_signal_emit (composer, signals[PRESEND], 0, &proceed_with_save);
-
- if (!proceed_with_save)
- return;
- }
-
editor = e_msg_composer_get_editor (composer);
context = g_slice_new0 (AsyncContext);
@@ -4522,10 +4713,8 @@ e_msg_composer_save_to_outbox (EMsgComposer *composer)
cancellable = e_activity_get_cancellable (context->activity);
- e_msg_composer_get_message (
- composer, G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) msg_composer_save_to_outbox_cb,
- context);
+ e_msg_composer_prepare_content_hash (composer, cancellable, context->activity,
+ e_msg_composer_save_to_outbox_content_hash_ready_cb, context);
}
static void
@@ -4534,29 +4723,14 @@ msg_composer_print_cb (EMsgComposer *composer,
AsyncContext *context)
{
CamelMimeMessage *message;
- EAlertSink *alert_sink;
GError *error = NULL;
- alert_sink = e_activity_get_alert_sink (context->activity);
-
- message = e_msg_composer_get_message_print_finish (
- composer, result, &error);
-
- if (e_activity_handle_cancellation (context->activity, error)) {
- g_warn_if_fail (message == NULL);
- async_context_free (context);
- g_error_free (error);
- return;
- }
+ message = e_msg_composer_get_message_print_finish (composer, result, &error);
- if (error != NULL) {
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, TRUE)) {
g_warn_if_fail (message == NULL);
async_context_free (context);
- e_alert_submit (
- alert_sink,
- "mail-composer:no-build-message",
- error->message, NULL);
- g_error_free (error);
+ g_clear_error (&error);
return;
}
@@ -4571,6 +4745,26 @@ msg_composer_print_cb (EMsgComposer *composer,
async_context_free (context);
}
+static void
+e_msg_composer_print_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ AsyncContext *context = user_data;
+
+ g_return_if_fail (context != NULL);
+
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, FALSE)) {
+ async_context_free (context);
+ return;
+ }
+
+ e_msg_composer_get_message_print (
+ composer, G_PRIORITY_DEFAULT, e_activity_get_cancellable (context->activity),
+ (GAsyncReadyCallback) msg_composer_print_cb,
+ context);
+}
+
/**
* e_msg_composer_print:
* @composer: an #EMsgComposer
@@ -4596,10 +4790,8 @@ e_msg_composer_print (EMsgComposer *composer,
cancellable = e_activity_get_cancellable (context->activity);
- e_msg_composer_get_message_print (
- composer, G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) msg_composer_print_cb,
- context);
+ e_msg_composer_prepare_content_hash (composer, cancellable, context->activity,
+ e_msg_composer_print_content_hash_ready_cb, context);
}
static GList *
@@ -5286,9 +5478,86 @@ composer_get_message_ready (EMsgComposer *composer,
g_simple_async_result_complete (simple);
+ e_msg_composer_unref_content_hash (composer);
+
g_object_unref (simple);
}
+typedef struct _BuildMessageWrapperData {
+ EMsgComposer *composer;
+ ComposerFlags flags;
+ gint io_priority;
+ GCancellable *cancellable;
+ GSimpleAsyncResult *simple;
+} BuildMessageWrapperData;
+
+static BuildMessageWrapperData *
+build_message_wrapper_data_new (EMsgComposer *composer,
+ ComposerFlags flags,
+ gint io_priority,
+ GCancellable *cancellable,
+ GSimpleAsyncResult *simple)
+{
+ BuildMessageWrapperData *bmwd;
+
+ bmwd = g_slice_new (BuildMessageWrapperData);
+ bmwd->composer = g_object_ref (composer);
+ bmwd->flags = flags;
+ bmwd->io_priority = io_priority;
+ bmwd->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ bmwd->simple = g_object_ref (simple);
+
+ return bmwd;
+}
+
+static void
+build_message_wrapper_data_free (gpointer ptr)
+{
+ BuildMessageWrapperData *bmwd = ptr;
+
+ if (bmwd) {
+ g_clear_object (&bmwd->composer);
+ g_clear_object (&bmwd->cancellable);
+ g_clear_object (&bmwd->simple);
+ g_slice_free (BuildMessageWrapperData, bmwd);
+ }
+}
+
+static void
+composer_build_message_wrapper_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ BuildMessageWrapperData *bmwd = user_data;
+
+ g_return_if_fail (bmwd != NULL);
+
+ if (error) {
+ g_simple_async_result_set_from_error (bmwd->simple, error);
+ g_simple_async_result_complete (bmwd->simple);
+ } else {
+ composer_build_message (composer, bmwd->flags, bmwd->io_priority,
+ bmwd->cancellable, (GAsyncReadyCallback)
+ composer_get_message_ready, bmwd->simple);
+ }
+
+ build_message_wrapper_data_free (bmwd);
+}
+
+static void
+composer_build_message_wrapper (EMsgComposer *composer,
+ ComposerFlags flags,
+ gint io_priority,
+ GCancellable *cancellable,
+ GSimpleAsyncResult *simple)
+{
+ BuildMessageWrapperData *bmwd;
+
+ bmwd = build_message_wrapper_data_new (composer, flags, io_priority, cancellable, simple);
+
+ e_msg_composer_prepare_content_hash (composer, cancellable, NULL,
composer_build_message_wrapper_content_hash_ready_cb, bmwd);
+}
+
/**
* e_msg_composer_get_message:
* @composer: an #EMsgComposer
@@ -5350,10 +5619,7 @@ e_msg_composer_get_message (EMsgComposer *composer,
flags |= COMPOSER_FLAG_SMIME_ENCRYPT;
#endif
- composer_build_message (
- composer, flags, io_priority,
- cancellable, (GAsyncReadyCallback)
- composer_get_message_ready, simple);
+ composer_build_message_wrapper (composer, flags, io_priority, cancellable, simple);
}
CamelMimeMessage *
@@ -5401,10 +5667,7 @@ e_msg_composer_get_message_print (EMsgComposer *composer,
flags |= COMPOSER_FLAG_HTML_CONTENT;
flags |= COMPOSER_FLAG_SAVE_OBJECT_DATA;
- composer_build_message (
- composer, flags, io_priority,
- cancellable, (GAsyncReadyCallback)
- composer_get_message_ready, simple);
+ composer_build_message_wrapper (composer, flags, io_priority, cancellable, simple);
}
CamelMimeMessage *
@@ -5486,10 +5749,7 @@ e_msg_composer_get_message_draft (EMsgComposer *composer,
flags |= COMPOSER_FLAG_SMIME_ENCRYPT;
#endif
- composer_build_message (
- composer, flags, io_priority,
- cancellable, (GAsyncReadyCallback)
- composer_get_message_ready, simple);
+ composer_build_message_wrapper (composer, flags, io_priority, cancellable, simple);
}
CamelMimeMessage *
@@ -5607,32 +5867,32 @@ e_msg_composer_get_reply_to (EMsgComposer *composer)
GByteArray *
e_msg_composer_get_raw_message_text_without_signature (EMsgComposer *composer)
{
- EHTMLEditor *editor;
- EContentEditor *cnt_editor;
- gchar *content;
+ EContentEditorContentHash *content_hash;
+ const gchar *content;
+ gsize content_length;
GByteArray *bytes;
gboolean needs_crlf;
g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
- editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (editor);
+ content_hash = e_msg_composer_get_content_hash (composer);
+ g_return_val_if_fail (content_hash != NULL, NULL);
- content = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_BODY |
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE,
- NULL, NULL);
+ content = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED);
if (!content) {
g_warning ("%s: Failed to retrieve content", G_STRFUNC);
- content = g_strdup ("");
+
+ content = "";
}
needs_crlf = !g_str_has_suffix (content, "\r\n");
- bytes = g_byte_array_new_take ((guint8 *) content, strlen (content));
+ content_length = strlen (content);
+
+ bytes = g_byte_array_sized_new (content_length + 3);
+
+ g_byte_array_append (bytes, (const guint8 *) content, content_length);
if (needs_crlf)
g_byte_array_append (bytes, (const guint8 *) "\r\n", 2);
@@ -5648,31 +5908,32 @@ e_msg_composer_get_raw_message_text_without_signature (EMsgComposer *composer)
GByteArray *
e_msg_composer_get_raw_message_text (EMsgComposer *composer)
{
- EHTMLEditor *editor;
- EContentEditor *cnt_editor;
- gchar *content;
+ EContentEditorContentHash *content_hash;
+ const gchar *content;
+ gsize content_length;
GByteArray *bytes;
gboolean needs_crlf;
g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
- editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (editor);
+ content_hash = e_msg_composer_get_content_hash (composer);
+ g_return_val_if_fail (content_hash != NULL, NULL);
- content = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_BODY |
- E_CONTENT_EDITOR_GET_TEXT_PLAIN,
- NULL, NULL);
+ content = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN);
if (!content) {
g_warning ("%s: Failed to retrieve content", G_STRFUNC);
- content = g_strdup ("");
+
+ content = "";
}
needs_crlf = !g_str_has_suffix (content, "\r\n");
- bytes = g_byte_array_new_take ((guint8 *) content, strlen (content));
+ content_length = strlen (content);
+
+ bytes = g_byte_array_sized_new (content_length + 3);
+
+ g_byte_array_append (bytes, (const guint8 *) content, content_length);
if (needs_crlf)
g_byte_array_append (bytes, (const guint8 *) "\r\n", 2);
diff --git a/src/composer/e-msg-composer.h b/src/composer/e-msg-composer.h
index e62ca84297..f385889ba4 100644
--- a/src/composer/e-msg-composer.h
+++ b/src/composer/e-msg-composer.h
@@ -108,6 +108,8 @@ EFocusTracker * e_msg_composer_get_focus_tracker
CamelSession * e_msg_composer_ref_session (EMsgComposer *composer);
EShell * e_msg_composer_get_shell (EMsgComposer *composer);
+EContentEditorContentHash *
+ e_msg_composer_get_content_hash (EMsgComposer *composer);
void e_msg_composer_send (EMsgComposer *composer);
void e_msg_composer_save_to_drafts (EMsgComposer *composer);
void e_msg_composer_save_to_outbox (EMsgComposer *composer);
diff --git a/src/e-util/e-content-editor.c b/src/e-util/e-content-editor.c
index 64a066cb6d..cb01a9aa9b 100644
--- a/src/e-util/e-content-editor.c
+++ b/src/e-util/e-content-editor.c
@@ -23,6 +23,7 @@
#include "e-html-editor.h"
#include "e-util-enumtypes.h"
+#include "e-misc-utils.h"
#include "e-content-editor.h"
G_DEFINE_INTERFACE (EContentEditor, e_content_editor, GTK_TYPE_WIDGET);
@@ -1574,25 +1575,344 @@ e_content_editor_insert_content (EContentEditor *editor,
iface->insert_content (editor, content, flags);
}
-gchar *
+/*
+ Finish the operation with e_content_editor_get_content_finish().
+ */
+void
e_content_editor_get_content (EContentEditor *editor,
- EContentEditorGetContentFlags flags,
+ guint32 flags,
const gchar *inline_images_from_domain,
- GSList **inline_images_parts /* newly created CamelMimePart * */)
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES))
+ g_return_if_fail (inline_images_from_domain != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->get_content != NULL);
+
+ iface->get_content (editor, flags, inline_images_from_domain, cancellable, callback, user_data);
+}
+
+/*
+ Finishes previous call of e_content_editor_get_content(). The implementation
+ creates the GHashTable with e_content_editor_util_new_content_hash() and fills
+ it with e_content_editor_util_put_content_data(), e_content_editor_util_take_content_data()
+ or e_content_editor_util_take_content_data_images(). The caller can access
+ the members with e_content_editor_util_get_content_data().
+
+ The returned pointer should be freed with e_content_editor_util_free_content_hash(),
+ when done with it.
+ */
+EContentEditorContentHash *
+e_content_editor_get_content_finish (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error)
{
EContentEditorInterface *iface;
g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
- if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES)) {
- g_return_val_if_fail (inline_images_from_domain != NULL, NULL);
- g_return_val_if_fail (inline_images_parts != NULL, NULL);
- }
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
g_return_val_if_fail (iface != NULL, NULL);
g_return_val_if_fail (iface->get_content != NULL, NULL);
- return iface->get_content (editor, flags, inline_images_from_domain, inline_images_parts);
+ return iface->get_content_finish (editor, result, error);
+}
+
+typedef struct _ContentHashData {
+ gpointer data;
+ GDestroyNotify destroy_data;
+} ContentHashData;
+
+static ContentHashData *
+content_hash_data_new (gpointer data,
+ GDestroyNotify destroy_data)
+{
+ ContentHashData *chd;
+
+ chd = g_slice_new (ContentHashData);
+ chd->data = data;
+ chd->destroy_data = destroy_data;
+
+ return chd;
+}
+
+static void
+content_hash_data_free (gpointer ptr)
+{
+ ContentHashData *chd = ptr;
+
+ if (ptr) {
+ if (chd->destroy_data && chd->data)
+ chd->destroy_data (chd->data);
+
+ g_slice_free (ContentHashData, chd);
+ }
+}
+
+static void
+content_data_free_obj_slist (gpointer ptr)
+{
+ GSList *lst = ptr;
+
+ g_slist_free_full (lst, g_object_unref);
+}
+
+EContentEditorContentHash *
+e_content_editor_util_new_content_hash (void)
+{
+ return (EContentEditorContentHash *) g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
content_hash_data_free);
+}
+
+void
+e_content_editor_util_free_content_hash (EContentEditorContentHash *content_hash)
+{
+ if (content_hash)
+ g_hash_table_unref ((GHashTable *) content_hash);
+}
+
+void
+e_content_editor_util_put_content_data (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ const gchar *data)
+{
+ g_return_if_fail (content_hash != NULL);
+ g_return_if_fail (flag != E_CONTENT_EDITOR_GET_ALL);
+ g_return_if_fail (data != NULL);
+
+ e_content_editor_util_take_content_data (content_hash, flag, g_strdup (data), g_free);
+}
+
+void
+e_content_editor_util_take_content_data (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ gpointer data,
+ GDestroyNotify destroy_data)
+{
+ g_return_if_fail (content_hash != NULL);
+ g_return_if_fail (flag != E_CONTENT_EDITOR_GET_ALL);
+ g_return_if_fail (data != NULL);
+
+ g_hash_table_insert ((GHashTable *) content_hash, GUINT_TO_POINTER (flag), content_hash_data_new
(data, destroy_data));
+}
+
+void
+e_content_editor_util_take_content_data_images (EContentEditorContentHash *content_hash,
+ GSList *image_parts) /* CamelMimePart * */
+{
+ g_return_if_fail (content_hash != NULL);
+ g_return_if_fail (image_parts != NULL);
+
+ g_hash_table_insert ((GHashTable *) content_hash, GUINT_TO_POINTER
(E_CONTENT_EDITOR_GET_INLINE_IMAGES),
+ content_hash_data_new (image_parts, content_data_free_obj_slist));
+}
+
+/* The actual data type depends on the @flag. The E_CONTENT_EDITOR_GET_INLINE_IMAGES returns
+ a GSList of CamelMimePart-s of inline images. All the other flags return plain strings.
+
+ The returned pointer is owned by content_hash and cannot be freed
+ neither modified. It's freed together with the content_hash, or
+ when its key is overwritten.
+ */
+gpointer
+e_content_editor_util_get_content_data (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag)
+{
+ ContentHashData *chd;
+
+ g_return_val_if_fail (content_hash != NULL, NULL);
+ g_return_val_if_fail (flag != E_CONTENT_EDITOR_GET_ALL, NULL);
+
+ chd = g_hash_table_lookup ((GHashTable *) content_hash, GUINT_TO_POINTER (flag));
+
+ return chd ? chd->data : NULL;
+}
+
+/* The same rules apply as with e_content_editor_util_get_content_data(). The difference is
+ that after calling this function the data is stoled from the content_hash and the caller
+ is responsible to free it. Any following calls with the same flag will return %NULL.
+ */
+gpointer
+e_content_editor_util_steal_content_data (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ GDestroyNotify *out_destroy_data)
+{
+ ContentHashData *chd;
+ gpointer data;
+
+ if (out_destroy_data)
+ *out_destroy_data = NULL;
+
+ g_return_val_if_fail (content_hash != NULL, NULL);
+ g_return_val_if_fail (flag != E_CONTENT_EDITOR_GET_ALL, NULL);
+
+ chd = g_hash_table_lookup ((GHashTable *) content_hash, GUINT_TO_POINTER (flag));
+
+ if (!chd)
+ return NULL;
+
+ data = chd->data;
+
+ if (out_destroy_data)
+ *out_destroy_data = chd->destroy_data;
+
+ chd->data = NULL;
+ chd->destroy_data = NULL;
+
+ return data;
+}
+
+/**
+ * e_content_editor_util_create_data_mimepart:
+ * @uri: a file:// or data: URI of the data to convert to MIME part
+ * @cid: content ID to use for the MIME part, should start with "cid:"; can be %NULL
+ * @as_inline: whether to use "inline" content disposition; will use "attachment", if set to %FALSE
+ * @prefer_filename: preferred file name to use, can be %NULL
+ * @prefer_mime_type: preferred MIME type for the part, can be %NULL
+ * @cancellable: optional #GCancellable object, or %NULL
+ *
+ * Converts URI into a #CamelMimePart. Supports file:// and data: URIs.
+ * The @prefer_filename can override the file name from the @uri.
+ *
+ * Free the returned pointer, if not %NULL, with g_object_unref(), when
+ * no longer needed.
+ *
+ * Returns: (transfer full) (nullable): a new #CamelMimePart containing
+ * the referenced data, or %NULL, when cannot be converted (due to
+ * unsupported URI, file not found or such).
+ *
+ * Since: 3.36
+ **/
+CamelMimePart *
+e_content_editor_util_create_data_mimepart (const gchar *uri,
+ const gchar *cid,
+ gboolean as_inline,
+ const gchar *prefer_filename,
+ const gchar *prefer_mime_type,
+ GCancellable *cancellable)
+{
+ CamelMimePart *mime_part = NULL;
+ GInputStream *input_stream = NULL;
+ GFileInfo *file_info = NULL;
+ gchar *mime_type = NULL;
+ guchar *data = NULL;
+ gsize data_length = 0;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ /* base64-encoded "data:" URIs */
+ if (g_ascii_strncasecmp (uri, "data:", 5) == 0) {
+ /* data:[<mime type>][;charset=<charset>][;base64],<encoded data> */
+ const gchar *ptr, *from;
+ gboolean is_base64 = FALSE;
+
+ ptr = uri + 5;
+ from = ptr;
+ while (*ptr && *ptr != ',') {
+ ptr++;
+
+ if (*ptr == ',' || *ptr == ';') {
+ if (g_ascii_strncasecmp (from, "base64", ptr - from) == 0)
+ is_base64 = TRUE;
+
+ if (from == uri + 5 && *ptr == ';' && !prefer_mime_type)
+ mime_type = g_strndup (from, ptr - from);
+
+ from = ptr + 1;
+ }
+ }
+
+ if (is_base64 && *ptr == ',') {
+ data = g_base64_decode (ptr + 1, &data_length);
+
+ if (data && data_length && !mime_type && !prefer_mime_type) {
+ gchar *content_type;
+
+ content_type = g_content_type_guess (NULL, data, data_length, NULL);
+
+ if (content_type) {
+ mime_type = g_content_type_get_mime_type (content_type);
+ g_free (content_type);
+ }
+ }
+ }
+
+ /* files on the disk */
+ } else if (g_ascii_strncasecmp (uri, "file://", 7) == 0) {
+ GFileInputStream *file_stream;
+ GFile *file;
+
+ file = g_file_new_for_uri (uri);
+ file_stream = g_file_read (file, NULL, NULL);
+ g_clear_object (&file);
+
+ if (file_stream) {
+ if (!prefer_filename) {
+ file_info = g_file_input_stream_query_info (file_stream,
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, cancellable, NULL);
+
+ if (file_info) {
+ prefer_filename = g_file_info_get_display_name (file_info);
+ }
+ }
+
+ if (!prefer_mime_type)
+ mime_type = e_util_guess_mime_type (uri, TRUE);
+
+ input_stream = (GInputStream *) file_stream;
+ }
+ }
+
+ if (data || input_stream) {
+ if (!prefer_mime_type)
+ prefer_mime_type = mime_type;
+
+ if (!prefer_mime_type)
+ prefer_mime_type = "application/octet-stream";
+
+ if (input_stream) {
+ CamelDataWrapper *wrapper;
+
+ wrapper = camel_data_wrapper_new ();
+
+ if (camel_data_wrapper_construct_from_input_stream_sync (wrapper, input_stream,
cancellable, NULL)) {
+ camel_data_wrapper_set_mime_type (wrapper, prefer_mime_type);
+
+ mime_part = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (mime_part), wrapper);
+ }
+
+ g_object_unref (wrapper);
+ } else {
+ mime_part = camel_mime_part_new ();
+ camel_mime_part_set_content (mime_part, (const gchar *) data, data_length,
prefer_mime_type);
+ }
+
+ if (mime_part) {
+ camel_mime_part_set_disposition (mime_part, as_inline ? "inline" : "attachment");
+
+ if (cid)
+ camel_mime_part_set_content_id (mime_part, cid);
+
+ if (prefer_filename && *prefer_filename)
+ camel_mime_part_set_filename (mime_part, prefer_filename);
+
+ camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
+ }
+ }
+
+ g_clear_object (&input_stream);
+ g_clear_object (&file_info);
+ g_free (mime_type);
+ g_free (data);
+
+ return mime_part;
}
void
@@ -2119,32 +2439,39 @@ e_content_editor_selection_wrap (EContentEditor *editor)
iface->selection_wrap (editor);
}
-guint
-e_content_editor_get_caret_position (EContentEditor *editor)
+void
+e_content_editor_get_caret_position (EContentEditor *editor,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
EContentEditorInterface *iface;
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_val_if_fail (iface != NULL, 0);
- g_return_val_if_fail (iface->get_caret_position != NULL, 0);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->get_caret_position != NULL);
- return iface->get_caret_position (editor);
+ iface->get_caret_position (editor, cancellable, callback, user_data);
}
-guint
-e_content_editor_get_caret_offset (EContentEditor *editor)
+gboolean
+e_content_editor_get_caret_position_finish (EContentEditor *editor,
+ GAsyncResult *result,
+ guint *out_position,
+ guint *out_offset,
+ GError **error)
{
EContentEditorInterface *iface;
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_val_if_fail (iface != NULL, 0);
- g_return_val_if_fail (iface->get_caret_offset != NULL, 0);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->get_caret_position_finish != NULL, FALSE);
- return iface->get_caret_offset (editor);
+ return iface->get_caret_position_finish (editor, result, out_position, out_offset, error);
}
gchar *
diff --git a/src/e-util/e-content-editor.h b/src/e-util/e-content-editor.h
index f1630522a2..9b2c971a9a 100644
--- a/src/e-util/e-content-editor.h
+++ b/src/e-util/e-content-editor.h
@@ -40,6 +40,8 @@ struct _EHTMLEditor;
#define E_TYPE_CONTENT_EDITOR e_content_editor_get_type ()
G_DECLARE_INTERFACE (EContentEditor, e_content_editor, E, CONTENT_EDITOR, GtkWidget)
+typedef GHashTable EContentEditorContentHash;
+
typedef void (*EContentEditorInitializedCallback) (EContentEditor *content_editor,
gpointer user_data);
@@ -56,10 +58,16 @@ struct _EContentEditorInterface {
const gchar *content,
EContentEditorInsertContentFlags flags);
- gchar * (*get_content) (EContentEditor *editor,
- EContentEditorGetContentFlags flags,
+ void (*get_content) (EContentEditor *editor,
+ guint32 flags, /* bit-or of
EContentEditorGetContentFlags */
const gchar *inline_images_from_domain,
- GSList **inline_images_parts /* newly created
CamelMimePart * */);
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ EContentEditorContentHash *
+ (*get_content_finish) (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error);
void (*insert_image) (EContentEditor *editor,
const gchar *uri);
@@ -129,9 +137,16 @@ struct _EContentEditorInterface {
void (*selection_wrap) (EContentEditor *editor);
- guint (*get_caret_position) (EContentEditor *editor);
+ void (*get_caret_position) (EContentEditor *editor,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
- guint (*get_caret_offset) (EContentEditor *editor);
+ gboolean (*get_caret_position_finish) (EContentEditor *editor,
+ GAsyncResult *result,
+ guint *out_position,
+ guint *out_offset,
+ GError **error);
gchar * (*get_current_signature_uid) (EContentEditor *editor);
@@ -543,10 +558,48 @@ void e_content_editor_insert_content (EContentEditor *editor,
const gchar *content,
EContentEditorInsertContentFlags flags);
-gchar * e_content_editor_get_content (EContentEditor *editor,
- EContentEditorGetContentFlags flags,
+void e_content_editor_get_content (EContentEditor *editor,
+ guint32 flags, /* bit-or of EContentEditorGetContentFlags */
const gchar *inline_images_from_domain,
- GSList **inline_images_parts /* newly created CamelMimePart
* */);
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+EContentEditorContentHash *
+ e_content_editor_get_content_finish
+ (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error);
+EContentEditorContentHash *
+ e_content_editor_util_new_content_hash
+ (void);
+void e_content_editor_util_free_content_hash
+ (EContentEditorContentHash *content_hash);
+void e_content_editor_util_put_content_data
+ (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ const gchar *data);
+void e_content_editor_util_take_content_data
+ (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ gpointer data,
+ GDestroyNotify destroy_data);
+void e_content_editor_util_take_content_data_images
+ (EContentEditorContentHash *content_hash,
+ GSList *image_parts); /* CamelMimePart * */
+gpointer e_content_editor_util_get_content_data
+ (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag);
+gpointer e_content_editor_util_steal_content_data
+ (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ GDestroyNotify *out_destroy_data);
+CamelMimePart * e_content_editor_util_create_data_mimepart
+ (const gchar *uri,
+ const gchar *cid,
+ gboolean as_inline,
+ const gchar *prefer_filename,
+ const gchar *prefer_mime_type,
+ GCancellable *cancellable);
void e_content_editor_insert_image_from_mime_part
(EContentEditor *editor,
@@ -627,11 +680,18 @@ void e_content_editor_selection_restore
void e_content_editor_selection_wrap (EContentEditor *editor);
-guint e_content_editor_get_caret_position
- (EContentEditor *editor);
+void e_content_editor_get_caret_position
+ (EContentEditor *editor,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
-guint e_content_editor_get_caret_offset
- (EContentEditor *editor);
+gboolean e_content_editor_get_caret_position_finish
+ (EContentEditor *editor,
+ GAsyncResult *result,
+ guint *out_position,
+ guint *out_offset,
+ GError **error);
gchar * e_content_editor_get_current_signature_uid
(EContentEditor *editor);
diff --git a/src/e-util/e-html-editor.c b/src/e-util/e-html-editor.c
index f9c35d9a3b..00ebe50b2d 100644
--- a/src/e-util/e-html-editor.c
+++ b/src/e-util/e-html-editor.c
@@ -1334,66 +1334,157 @@ e_html_editor_pack_above (EHTMLEditor *editor,
editor->priv->editor_layout_row++;
}
+typedef struct _SaveContentData {
+ GOutputStream *stream;
+ GCancellable *cancellable;
+} SaveContentData;
+
+static SaveContentData *
+save_content_data_new (GOutputStream *stream,
+ GCancellable *cancellable)
+{
+ SaveContentData *scd;
+
+ scd = g_slice_new (SaveContentData);
+ scd->stream = stream;
+ scd->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+
+ return scd;
+}
+
+static void
+save_content_data_free (gpointer ptr)
+{
+ SaveContentData *scd = ptr;
+
+ if (scd) {
+ g_clear_object (&scd->stream);
+ g_clear_object (&scd->cancellable);
+ g_slice_free (SaveContentData, scd);
+ }
+}
+
+static void
+e_html_editor_save_content_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ESimpleAsyncResult *simple = user_data;
+ EContentEditorContentHash *content_hash;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+ g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (simple));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ if (content_hash) {
+ const gchar *content;
+
+ content = e_content_editor_util_get_content_data (content_hash, GPOINTER_TO_UINT
(e_simple_async_result_get_op_pointer (simple)));
+
+ if (!content) {
+ g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to obtain
content of editor"));
+ } else {
+ SaveContentData *scd;
+ gsize written;
+
+ scd = e_simple_async_result_get_user_data (simple);
+
+ g_output_stream_write_all (scd->stream, content, strlen (content), &written,
scd->cancellable, &error);
+ }
+
+ e_content_editor_util_free_content_hash (content_hash);
+
+ if (error)
+ e_simple_async_result_take_error (simple, error);
+ } else {
+ e_simple_async_result_take_error (simple, error);
+ }
+
+ e_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
/**
* e_html_editor_save:
* @editor: an #EHTMLEditor
* @filename: file into which to save the content
* @as_html: whether the content should be saved as HTML or plain text
- * @error:[out] a #GError
+ * @cancellable: an optional #GCancellable, or %NULL
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the save is finished
+ * @user_data: (closure callback): user data passed to @callback
*
- * Saves current content of the #EContentEditor into given file. When @as_html
- * is @FALSE, the content is first converted into plain text.
+ * Starts an asynchronous save of the current content of the #EContentEditor
+ * into given file. When @as_html is @FALSE, the content is first converted
+ * into plain text.
*
- * Returns: @TRUE when content is succesfully saved, @FALSE otherwise.
- */
-gboolean
+ * Finish the call with e_html_editor_save_finish() from the @callback.
+ *
+ * Since: 3.36
+ **/
+void
e_html_editor_save (EHTMLEditor *editor,
- const gchar *filename,
- gboolean as_html,
- GError **error)
+ const gchar *filename,
+ gboolean as_html,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
EContentEditor *cnt_editor;
+ ESimpleAsyncResult *simple;
+ EContentEditorGetContentFlags flag;
+ SaveContentData *scd;
GFile *file;
GFileOutputStream *stream;
- gchar *content;
- gsize written;
+ GError *local_error = NULL;
+
+ simple = e_simple_async_result_new (G_OBJECT (editor), callback, user_data, e_html_editor_save);
file = g_file_new_for_path (filename);
- stream = g_file_replace (
- file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
- if ((error && *error) || !stream)
- return FALSE;
+ stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &local_error);
+ if (local_error || !stream) {
+ e_simple_async_result_take_error (simple, local_error);
+ e_simple_async_result_complete_idle (simple);
- cnt_editor = e_html_editor_get_content_editor (editor);
+ g_object_unref (simple);
+ g_object_unref (file);
- if (as_html)
- content = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
- else
- content = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
-
- if (!content || !*content) {
- g_free (content);
- g_set_error (
- error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Failed to obtain content of editor");
- return FALSE;
+ return;
}
- g_output_stream_write_all (
- G_OUTPUT_STREAM (stream), content, strlen (content),
- &written, NULL, error);
+ flag = as_html ? E_CONTENT_EDITOR_GET_TO_SEND_HTML : E_CONTENT_EDITOR_GET_TO_SEND_PLAIN;
+
+ scd = save_content_data_new (G_OUTPUT_STREAM (stream), cancellable);
+
+ e_simple_async_result_set_user_data (simple, scd, save_content_data_free);
+ e_simple_async_result_set_op_pointer (simple, GUINT_TO_POINTER (flag), NULL);
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_get_content (cnt_editor, flag, NULL, cancellable,
e_html_editor_save_content_ready_cb, simple);
- g_free (content);
- g_object_unref (stream);
g_object_unref (file);
+}
- return TRUE;
+/**
+ * e_html_editor_save_finish:
+ * @editor: an #EHTMLEditor
+ * @result: a #GAsyncResult of the operation
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finished the previous call of e_html_editor_save().
+ *
+ * Returns: whether the save succeeded.
+ *
+ * Since: 3.36
+ **/
+gboolean
+e_html_editor_save_finish (EHTMLEditor *editor,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (e_simple_async_result_is_valid (result, G_OBJECT (editor), e_html_editor_save),
FALSE);
+
+ return !e_simple_async_result_propagate_error (E_SIMPLE_ASYNC_RESULT (result), error);
}
diff --git a/src/e-util/e-html-editor.h b/src/e-util/e-html-editor.h
index 6c5a63a62d..121eae7758 100644
--- a/src/e-util/e-html-editor.h
+++ b/src/e-util/e-html-editor.h
@@ -110,9 +110,14 @@ void e_html_editor_update_spell_actions
* High-Level Editing Interface
*****************************************************************************/
-gboolean e_html_editor_save (EHTMLEditor *editor,
+void e_html_editor_save (EHTMLEditor *editor,
const gchar *filename,
gboolean as_html,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_html_editor_save_finish (EHTMLEditor *editor,
+ GAsyncResult *result,
GError **error);
G_END_DECLS
diff --git a/src/e-util/e-mail-signature-editor.c b/src/e-util/e-mail-signature-editor.c
index 4b6c13fae3..e51e3234d5 100644
--- a/src/e-util/e-mail-signature-editor.c
+++ b/src/e-util/e-mail-signature-editor.c
@@ -46,10 +46,13 @@ struct _EMailSignatureEditorPrivate {
};
struct _AsyncContext {
+ ESourceRegistry *registry;
ESource *source;
GCancellable *cancellable;
+ EContentEditorGetContentFlags contents_flag;
gchar *contents;
gsize length;
+ GDestroyNotify destroy_contents;
};
enum {
@@ -86,13 +89,14 @@ G_DEFINE_TYPE (
static void
async_context_free (AsyncContext *async_context)
{
- if (async_context->source != NULL)
- g_object_unref (async_context->source);
-
- if (async_context->cancellable != NULL)
- g_object_unref (async_context->cancellable);
+ g_clear_object (&async_context->registry);
+ g_clear_object (&async_context->source);
+ g_clear_object (&async_context->cancellable);
- g_free (async_context->contents);
+ if (async_context->destroy_contents)
+ async_context->destroy_contents (async_context->contents);
+ else
+ g_free (async_context->contents);
g_slice_free (AsyncContext, async_context);
}
@@ -917,6 +921,55 @@ mail_signature_editor_commit_cb (GObject *object,
simple);
}
+static void
+mail_signature_editor_content_hash_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = user_data;
+ EContentEditorContentHash *content_hash;
+ ESourceMailSignature *extension;
+ AsyncContext *async_context;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ if (!content_hash) {
+ g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ async_context->contents = e_content_editor_util_steal_content_data (content_hash,
+ async_context->contents_flag, &async_context->destroy_contents);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
+ if (!async_context->contents) {
+ g_warning ("%s: Failed to retrieve content", G_STRFUNC);
+
+ async_context->contents = g_strdup ("");
+ async_context->destroy_contents = NULL;
+ }
+
+ async_context->length = strlen (async_context->contents);
+
+ extension = e_source_get_extension (async_context->source, E_SOURCE_EXTENSION_MAIL_SIGNATURE);
+ e_source_mail_signature_set_mime_type (extension,
+ async_context->contents_flag == E_CONTENT_EDITOR_GET_RAW_BODY_HTML ? "text/html" :
"text/plain");
+
+ e_source_registry_commit_source (
+ async_context->registry, async_context->source,
+ async_context->cancellable,
+ mail_signature_editor_commit_cb,
+ simple);
+}
+
void
e_mail_signature_editor_commit (EMailSignatureEditor *window,
GCancellable *cancellable,
@@ -925,12 +978,8 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
{
GSimpleAsyncResult *simple;
AsyncContext *async_context;
- ESourceMailSignature *extension;
ESourceRegistry *registry;
ESource *source;
- const gchar *extension_name;
- const gchar *mime_type;
- gchar *contents;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
@@ -942,26 +991,10 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
editor = e_mail_signature_editor_get_editor (window);
cnt_editor = e_html_editor_get_content_editor (editor);
- mime_type = "text/html";
- contents = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_BODY,
- NULL, NULL);
-
- if (!contents) {
- g_warning ("%s: Failed to retrieve content", G_STRFUNC);
- contents = g_strdup ("");
- }
-
- extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
- extension = e_source_get_extension (source, extension_name);
- e_source_mail_signature_set_mime_type (extension, mime_type);
-
async_context = g_slice_new0 (AsyncContext);
+ async_context->registry = g_object_ref (registry);
async_context->source = g_object_ref (source);
- async_context->contents = contents; /* takes ownership */
- async_context->length = strlen (contents);
+ async_context->contents_flag = e_content_editor_get_html_mode (cnt_editor) ?
E_CONTENT_EDITOR_GET_RAW_BODY_HTML : E_CONTENT_EDITOR_GET_TO_SEND_PLAIN;
if (G_IS_CANCELLABLE (cancellable))
async_context->cancellable = g_object_ref (cancellable);
@@ -973,11 +1006,8 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
g_simple_async_result_set_op_res_gpointer (
simple, async_context, (GDestroyNotify) async_context_free);
- e_source_registry_commit_source (
- registry, source,
- async_context->cancellable,
- mail_signature_editor_commit_cb,
- simple);
+ e_content_editor_get_content (cnt_editor, async_context->contents_flag, NULL,
+ cancellable, mail_signature_editor_content_hash_ready_cb, simple);
}
gboolean
diff --git a/src/e-util/e-util-enums.h b/src/e-util/e-util-enums.h
index b4090d55a6..432bc1ccb2 100644
--- a/src/e-util/e-util-enums.h
+++ b/src/e-util/e-util-enums.h
@@ -164,22 +164,29 @@ typedef enum {
/**
* EContentEditorGetContentFlags:
- * @E_CONTENT_EDITOR_GET_BODY:
- * @E_CONTENT_EDITOR_GET_INLINE_IMAGES:
- * @E_CONTENT_EDITOR_GET_PROCESSED: raw or processed
- * @E_CONTENT_EDITOR_GET_TEXT_HTML:
- * @E_CONTENT_EDITOR_GET_TEXT_PLAIN:
- * @E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE:
+ * @E_CONTENT_EDITOR_GET_INLINE_IMAGES: Return also list of inline images
+ * @E_CONTENT_EDITOR_GET_RAW_BODY_HTML: text/html version of the body only, as used by the editor
+ * @E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN: text/plain version of the body only, as used by the editor
+ * @E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED: text/plain version of the body only, without signature, quoted
text and such
+ * @E_CONTENT_EDITOR_GET_RAW_DRAFT: a version of the content, to use as draft message
+ * @E_CONTENT_EDITOR_GET_TO_SEND_HTML: text/html version of the content, suitable to be sent
+ * @E_CONTENT_EDITOR_GET_TO_SEND_PLAIN: text/plain version of the content, suitable to be sent
+ * @E_CONTENT_EDITOR_GET_ALL: a shortcut for all flags
+ *
+ * Influences what content should be returned. Each flag means one
+ * version, or part, of the content.
*
- * Since: 3.22
+ * Since: 3.36
**/
typedef enum {
- E_CONTENT_EDITOR_GET_BODY = 1 << 0,
- E_CONTENT_EDITOR_GET_INLINE_IMAGES = 1 << 1,
- E_CONTENT_EDITOR_GET_PROCESSED = 1 << 2, /* raw or processed */
- E_CONTENT_EDITOR_GET_TEXT_HTML = 1 << 3,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN = 1 << 4,
- E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE = 1 << 5
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES = 1 << 0,
+ E_CONTENT_EDITOR_GET_RAW_BODY_HTML = 1 << 1,
+ E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN = 1 << 2,
+ E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED = 1 << 3,
+ E_CONTENT_EDITOR_GET_RAW_DRAFT = 1 << 4,
+ E_CONTENT_EDITOR_GET_TO_SEND_HTML = 1 << 5,
+ E_CONTENT_EDITOR_GET_TO_SEND_PLAIN = 1 << 6,
+ E_CONTENT_EDITOR_GET_ALL = ~0
} EContentEditorGetContentFlags;
/**
diff --git a/src/e-util/test-html-editor-units-utils.c b/src/e-util/test-html-editor-units-utils.c
index 1f7e5eb4f0..a0c72ed4f7 100644
--- a/src/e-util/test-html-editor-units-utils.c
+++ b/src/e-util/test-html-editor-units-utils.c
@@ -83,6 +83,50 @@ test_utils_free_global_memory (void)
g_clear_object (&global_web_context);
}
+typedef struct _GetContentData {
+ EContentEditorContentHash *content_hash;
+ gpointer async_data;
+} GetContentData;
+
+static void
+get_editor_content_hash_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GetContentData *gcd = user_data;
+ GError *error = NULL;
+
+ g_assert_nonnull (gcd);
+ g_assert (E_IS_CONTENT_EDITOR (source_object));
+
+ gcd->content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result,
&error);
+
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+
+ test_utils_async_call_finish (gcd->async_data);
+}
+
+static EContentEditorContentHash *
+test_utils_get_editor_content_hash_sync (EContentEditor *cnt_editor,
+ guint32 flags)
+{
+ GetContentData gcd;
+
+ g_assert (E_IS_CONTENT_EDITOR (cnt_editor));
+
+ gcd.content_hash = NULL;
+ gcd.async_data = test_utils_async_call_prepare ();
+
+ e_content_editor_get_content (cnt_editor, flags, "test-domain", NULL,
get_editor_content_hash_ready_cb, &gcd);
+
+ g_assert (test_utils_async_call_wait (gcd.async_data, MAX (event_processing_delay_ms / 25, 1) + 1));
+ g_assert_nonnull (gcd.content_hash);
+
+ return gcd.content_hash;
+}
+
typedef struct _UndoContent {
gchar *html;
gchar *plain;
@@ -92,16 +136,20 @@ static UndoContent *
undo_content_new (TestFixture *fixture)
{
EContentEditor *cnt_editor;
+ EContentEditorContentHash *content_hash;
UndoContent *uc;
g_return_val_if_fail (fixture != NULL, NULL);
g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), NULL);
cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ content_hash = test_utils_get_editor_content_hash_sync (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_HTML
| E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
uc = g_new0 (UndoContent, 1);
- uc->html = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
- uc->plain = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ uc->html = e_content_editor_util_steal_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_HTML,
NULL);
+ uc->plain = e_content_editor_util_steal_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN, NULL);
+
+ e_content_editor_util_free_content_hash (content_hash);
g_warn_if_fail (uc->html != NULL);
g_warn_if_fail (uc->plain != NULL);
@@ -127,15 +175,17 @@ undo_content_test (TestFixture *fixture,
gint cmd_index)
{
EContentEditor *cnt_editor;
- gchar *text;
+ EContentEditorContentHash *content_hash;
+ const gchar *text;
g_return_val_if_fail (fixture != NULL, FALSE);
g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
g_return_val_if_fail (uc != NULL, FALSE);
cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ content_hash = test_utils_get_editor_content_hash_sync (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_HTML
| E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_HTML);
g_return_val_if_fail (text != NULL, FALSE);
if (!test_utils_html_equal (fixture, text, uc->html)) {
@@ -143,13 +193,13 @@ undo_content_test (TestFixture *fixture,
g_printerr ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do not match
at command %d\n", G_STRFUNC, text, uc->html, cmd_index);
else
g_warning ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do not match
at command %d", G_STRFUNC, text, uc->html, cmd_index);
- g_free (text);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
return FALSE;
}
- g_free (text);
-
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
g_return_val_if_fail (text != NULL, FALSE);
if (!test_utils_html_equal (fixture, text, uc->plain)) {
@@ -157,11 +207,13 @@ undo_content_test (TestFixture *fixture,
g_printerr ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do not
match at command %d\n", G_STRFUNC, text, uc->plain, cmd_index);
else
g_warning ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do not
match at command %d", G_STRFUNC, text, uc->plain, cmd_index);
- g_free (text);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
return FALSE;
}
- g_free (text);
+ e_content_editor_util_free_content_hash (content_hash);
return TRUE;
}
@@ -1028,7 +1080,8 @@ test_utils_run_simple_test (TestFixture *fixture,
const gchar *expected_plain)
{
EContentEditor *cnt_editor;
- gchar *text;
+ EContentEditorContentHash *content_hash;
+ const gchar *text;
g_return_val_if_fail (fixture != NULL, FALSE);
g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
@@ -1039,8 +1092,10 @@ test_utils_run_simple_test (TestFixture *fixture,
if (!test_utils_process_commands (fixture, commands))
return FALSE;
+ content_hash = test_utils_get_editor_content_hash_sync (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_HTML
| E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
+
if (expected_html) {
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_HTML);
g_return_val_if_fail (text != NULL, FALSE);
if (!test_utils_html_equal (fixture, text, expected_html)) {
@@ -1048,15 +1103,15 @@ test_utils_run_simple_test (TestFixture *fixture,
g_printerr ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do
not match\n", G_STRFUNC, text, expected_html);
else
g_warning ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do
not match", G_STRFUNC, text, expected_html);
- g_free (text);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
return FALSE;
}
-
- g_free (text);
}
if (expected_plain) {
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
g_return_val_if_fail (text != NULL, FALSE);
if (!test_utils_html_equal (fixture, text, expected_plain)) {
@@ -1064,13 +1119,15 @@ test_utils_run_simple_test (TestFixture *fixture,
g_printerr ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do
not match\n", G_STRFUNC, text, expected_plain);
else
g_warning ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do
not match", G_STRFUNC, text, expected_plain);
- g_free (text);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
return FALSE;
}
-
- g_free (text);
}
+ e_content_editor_util_free_content_hash (content_hash);
+
return TRUE;
}
diff --git a/src/e-util/test-html-editor.c b/src/e-util/test-html-editor.c
index 84010ff899..9b7eaaf3a1 100644
--- a/src/e-util/test-html-editor.c
+++ b/src/e-util/test-html-editor.c
@@ -139,19 +139,16 @@ save_dialog (EHTMLEditor *editor)
}
static void
-view_source_dialog (EHTMLEditor *editor,
- const gchar *title,
- gboolean plain_text,
- gboolean show_source)
+view_source_dialog_show (EHTMLEditor *editor,
+ const gchar *title,
+ gboolean plain_text,
+ gboolean show_source,
+ const gchar *content_text)
{
GtkWidget *dialog;
GtkWidget *content;
GtkWidget *content_area;
GtkWidget *scrolled_window;
- EContentEditor *cnt_editor;
- gchar * html;
-
- cnt_editor = e_html_editor_get_content_editor (editor);
dialog = gtk_dialog_new_with_buttons (
title,
@@ -176,32 +173,17 @@ view_source_dialog (EHTMLEditor *editor,
gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 6);
gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 300);
- if (plain_text) {
- html = e_content_editor_get_content (cnt_editor,
- E_CONTENT_EDITOR_GET_PROCESSED | E_CONTENT_EDITOR_GET_TEXT_PLAIN,
- NULL, NULL);
- } else {
- GSList *inline_images = NULL;
-
- html = e_content_editor_get_content (cnt_editor,
- E_CONTENT_EDITOR_GET_PROCESSED | E_CONTENT_EDITOR_GET_TEXT_HTML |
E_CONTENT_EDITOR_GET_INLINE_IMAGES,
- "test-domain", &inline_images);
-
- g_slist_free_full (inline_images, g_object_unref);
- }
-
if (show_source || plain_text) {
GtkTextBuffer *buffer;
content = gtk_text_view_new ();
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (content));
- gtk_text_buffer_set_text (buffer, html ? html : "", -1);
+ gtk_text_buffer_set_text (buffer, content_text ? content_text : "", -1);
gtk_text_view_set_editable (GTK_TEXT_VIEW (content), FALSE);
} else {
content = webkit_web_view_new ();
- webkit_web_view_load_html (WEBKIT_WEB_VIEW (content), html ? html : "", "evo-file://");
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (content), content_text ? content_text : "",
"evo-file://");
}
- g_free (html);
gtk_container_add (GTK_CONTAINER (scrolled_window), content);
gtk_widget_show_all (scrolled_window);
@@ -210,6 +192,94 @@ view_source_dialog (EHTMLEditor *editor,
gtk_widget_destroy (dialog);
}
+typedef struct _ViewSourceData {
+ EHTMLEditor *editor;
+ gchar *title;
+ gboolean plain_text;
+ gboolean show_source;
+} ViewSourceData;
+
+static ViewSourceData *
+view_source_data_new (EHTMLEditor *editor,
+ const gchar *title,
+ gboolean plain_text,
+ gboolean show_source)
+{
+ ViewSourceData *vsd;
+
+ vsd = g_slice_new (ViewSourceData);
+ vsd->editor = g_object_ref (editor);
+ vsd->title = g_strdup (title);
+ vsd->plain_text = plain_text;
+ vsd->show_source = show_source;
+
+ return vsd;
+}
+
+static void
+view_source_data_free (gpointer ptr)
+{
+ ViewSourceData *vsd = ptr;
+
+ if (vsd) {
+ g_clear_object (&vsd->editor);
+ g_free (vsd->title);
+ g_slice_free (ViewSourceData, vsd);
+ }
+}
+
+static void
+view_source_dialog_content_hash_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ViewSourceData *vcd = user_data;
+ EContentEditorContentHash *content_hash;
+ GError *error = NULL;
+
+ g_return_if_fail (vcd != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ if (!content_hash) {
+ g_warning ("%s: Failed to get content: %s", G_STRFUNC, error ? error->message : "Unknown
error");
+ } else {
+ view_source_dialog_show (vcd->editor, vcd->title, vcd->plain_text, vcd->show_source,
+ e_content_editor_util_get_content_data (content_hash,
+ vcd->plain_text ? E_CONTENT_EDITOR_GET_TO_SEND_PLAIN :
E_CONTENT_EDITOR_GET_TO_SEND_HTML));
+
+ e_content_editor_util_free_content_hash (content_hash);
+ }
+
+ view_source_data_free (vcd);
+ g_clear_error (&error);
+}
+
+static void
+view_source_dialog (EHTMLEditor *editor,
+ const gchar *title,
+ gboolean plain_text,
+ gboolean show_source)
+{
+ EContentEditor *cnt_editor;
+ ViewSourceData *vcd;
+ guint32 flags;
+
+ vcd = view_source_data_new (editor, title, plain_text, show_source);
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ if (plain_text) {
+ flags = E_CONTENT_EDITOR_GET_TO_SEND_PLAIN;
+ } else {
+ flags = E_CONTENT_EDITOR_GET_INLINE_IMAGES | E_CONTENT_EDITOR_GET_TO_SEND_HTML;
+ }
+
+ e_content_editor_get_content (cnt_editor, flags, "test-domain", NULL,
+ view_source_dialog_content_hash_ready_cb, vcd);
+}
+
static void
action_new_editor_cb (GtkAction *action,
EHTMLEditor *editor)
@@ -240,13 +310,24 @@ action_quit_cb (GtkAction *action,
gtk_main_quit ();
}
+static void
+html_editor_save_done_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error = NULL;
+
+ e_html_editor_save_finish (E_HTML_EDITOR (source_object), result, &error);
+
+ handle_error (&error);
+}
+
static void
action_save_cb (GtkAction *action,
EHTMLEditor *editor)
{
const gchar *filename;
gboolean as_html;
- GError *error = NULL;
if (e_html_editor_get_filename (editor) == NULL)
if (save_dialog (editor) == GTK_RESPONSE_CANCEL)
@@ -255,8 +336,7 @@ action_save_cb (GtkAction *action,
filename = e_html_editor_get_filename (editor);
as_html = (e_content_editor_get_html_mode (e_html_editor_get_content_editor (editor)));
- e_html_editor_save (editor, filename, as_html, &error);
- handle_error (&error);
+ e_html_editor_save (editor, filename, as_html, NULL, html_editor_save_done_cb, NULL);
}
static void
@@ -265,7 +345,6 @@ action_save_as_cb (GtkAction *action,
{
const gchar *filename;
gboolean as_html;
- GError *error = NULL;
if (save_dialog (editor) == GTK_RESPONSE_CANCEL)
return;
@@ -273,8 +352,7 @@ action_save_as_cb (GtkAction *action,
filename = e_html_editor_get_filename (editor);
as_html = (e_content_editor_get_html_mode (e_html_editor_get_content_editor (editor)));
- e_html_editor_save (editor, filename, as_html, &error);
- handle_error (&error);
+ e_html_editor_save (editor, filename, as_html, NULL, html_editor_save_done_cb, NULL);
}
static void
diff --git a/src/mail/e-mail-notes.c b/src/mail/e-mail-notes.c
index b55827d64e..28aaefec86 100644
--- a/src/mail/e-mail-notes.c
+++ b/src/mail/e-mail-notes.c
@@ -289,7 +289,8 @@ e_mail_notes_editor_extract_text_from_message (EMailNotesEditor *notes_editor,
}
static CamelMimeMessage *
-e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
+e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor,
+ EContentEditorContentHash *content_hash)
{
EContentEditor *cnt_editor;
EAttachmentStore *attachment_store;
@@ -301,6 +302,7 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
g_return_val_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor), NULL);
g_return_val_if_fail (notes_editor->editor, NULL);
+ g_return_val_if_fail (content_hash != NULL, NULL);
cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
g_return_val_if_fail (E_IS_CONTENT_EDITOR (cnt_editor), NULL);
@@ -330,24 +332,20 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
CamelMultipart *multipart_body;
CamelMimePart *part;
GSList *inline_images_parts = NULL;
- gchar *text;
+ const gchar *text;
multipart_alternative = camel_multipart_new ();
camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_alternative),
"multipart/alternative");
camel_multipart_set_boundary (multipart_alternative, NULL);
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
if (text && *text) {
- if (!g_str_has_suffix (text, "\r\n")) {
- gchar *tmp = text;
+ gchar *tmp = NULL;
- text = g_strconcat (tmp, "\r\n", NULL);
- g_free (tmp);
+ if (!g_str_has_suffix (text, "\r\n")) {
+ tmp = g_strconcat (text, "\r\n", NULL);
+ text = tmp;
}
part = camel_mime_part_new ();
@@ -355,33 +353,26 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
camel_multipart_add_part (multipart_alternative, part);
g_object_unref (part);
+ g_free (tmp);
has_text = TRUE;
}
- g_free (text);
-
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_PROCESSED |
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_INLINE_IMAGES,
- g_get_host_name (),
- &inline_images_parts);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_HTML);
+ inline_images_parts = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_INLINE_IMAGES);
if (has_attachments && !has_text && (!text || !*text)) {
/* Text is required, thus if there are attachments,
but no text, then store at least a space. */
- g_free (text);
- text = g_strdup ("\r\n");
+ text = "\r\n";
}
if (text && *text) {
- if (!g_str_has_suffix (text, "\r\n")) {
- gchar *tmp = text;
+ gchar *tmp = NULL;
- text = g_strconcat (tmp, "\r\n", NULL);
- g_free (tmp);
+ if (!g_str_has_suffix (text, "\r\n")) {
+ tmp = g_strconcat (text, "\r\n", NULL);
+ text = tmp;
}
part = camel_mime_part_new ();
@@ -389,15 +380,13 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
camel_multipart_add_part (multipart_alternative, part);
g_object_unref (part);
+ g_free (tmp);
has_text = TRUE;
} else {
- g_slist_free_full (inline_images_parts, g_object_unref);
inline_images_parts = NULL;
}
- g_free (text);
-
if (inline_images_parts) {
GSList *link;
@@ -443,31 +432,25 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart_body));
- g_slist_free_full (inline_images_parts, g_object_unref);
g_clear_object (&multipart_alternative);
g_clear_object (&multipart_body);
} else {
- gchar *text;
+ const gchar *text;
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
if (has_attachments && !has_text && (!text || !*text)) {
/* Text is required, thus if there are attachments,
but no text, then store at least a space. */
- g_free (text);
- text = g_strdup ("\r\n");
+ text = "\r\n";
}
if (text && *text) {
- if (!g_str_has_suffix (text, "\r\n")) {
- gchar *tmp = text;
+ gchar *tmp = NULL;
- text = g_strconcat (tmp, "\r\n", NULL);
- g_free (tmp);
+ if (!g_str_has_suffix (text, "\r\n")) {
+ tmp = g_strconcat (text, "\r\n", NULL);
+ text = tmp;
}
if (has_attachments) {
@@ -491,10 +474,11 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
} else {
camel_mime_part_set_content (CAMEL_MIME_PART (message), text, strlen (text),
"text/plain");
}
+
has_text = TRUE;
- }
- g_free (text);
+ g_free (tmp);
+ }
}
if (has_text) {
@@ -790,9 +774,22 @@ action_close_cb (GtkAction *action,
typedef struct {
EMailNotesEditor *notes_editor;
CamelMimeMessage *inner_message;
+ EActivity *activity;
+ GError *error;
gboolean success;
} SaveAndCloseData;
+static SaveAndCloseData *
+save_and_close_data_new (EMailNotesEditor *notes_editor)
+{
+ SaveAndCloseData *scd;
+
+ scd = g_slice_new0 (SaveAndCloseData);
+ scd->notes_editor = g_object_ref (notes_editor);
+
+ return scd;
+}
+
static void
save_and_close_data_free (gpointer ptr)
{
@@ -804,7 +801,9 @@ save_and_close_data_free (gpointer ptr)
else
g_clear_object (&scd->notes_editor);
g_clear_object (&scd->inner_message);
- g_free (scd);
+ g_clear_object (&scd->activity);
+ g_clear_error (&scd->error);
+ g_slice_free (SaveAndCloseData, scd);
}
}
@@ -819,6 +818,12 @@ e_mail_notes_store_changes_thread (EAlertSinkThreadJobData *job_data,
g_return_if_fail (scd != NULL);
+ if (scd->error) {
+ g_propagate_error (error, scd->error);
+ scd->error = NULL;
+ return;
+ }
+
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return;
@@ -841,35 +846,76 @@ e_mail_notes_store_changes_thread (EAlertSinkThreadJobData *job_data,
}
static void
-action_save_and_close_cb (GtkAction *action,
- EMailNotesEditor *notes_editor)
+mail_notes_get_content_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- SaveAndCloseData *scd;
- gchar *full_display_name;
+ SaveAndCloseData *scd = user_data;
+ EContentEditorContentHash *content_hash;
EActivityBar *activity_bar;
EActivity *activity;
+ gchar *full_display_name;
+ GError *error = NULL;
- g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+ g_return_if_fail (scd != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
- scd = g_new0 (SaveAndCloseData, 1);
- scd->notes_editor = g_object_ref (notes_editor);
- scd->inner_message = e_mail_notes_editor_encode_text_to_message (notes_editor);
- scd->success = FALSE;
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
- full_display_name = e_mail_folder_to_full_display_name (notes_editor->folder, NULL);
+ if (content_hash) {
+ scd->inner_message = e_mail_notes_editor_encode_text_to_message (scd->notes_editor,
content_hash);
- activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
- activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (notes_editor->editor),
+ if (!scd->inner_message)
+ scd->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to convert
text to message"));
+ } else {
+ scd->error = error;
+
+ if (!scd->error)
+ scd->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, _("Unknown error"));
+ }
+
+ g_clear_object (&scd->activity);
+
+ full_display_name = e_mail_folder_to_full_display_name (scd->notes_editor->folder, NULL);
+
+ activity_bar = e_html_editor_get_activity_bar (scd->notes_editor->editor);
+ activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (scd->notes_editor->editor),
_("Storing changes…"), "mail:failed-store-note",
- full_display_name ? full_display_name : camel_folder_get_display_name (notes_editor->folder),
+ full_display_name ? full_display_name : camel_folder_get_display_name
(scd->notes_editor->folder),
e_mail_notes_store_changes_thread,
scd, save_and_close_data_free);
e_activity_bar_set_activity (activity_bar, activity);
g_clear_object (&activity);
+ e_content_editor_util_free_content_hash (content_hash);
g_free (full_display_name);
}
+static void
+action_save_and_close_cb (GtkAction *action,
+ EMailNotesEditor *notes_editor)
+{
+ SaveAndCloseData *scd;
+ EActivity *activity;
+ EContentEditor *cnt_editor;
+
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (cnt_editor));
+
+ activity = e_html_editor_new_activity (notes_editor->editor);
+ e_activity_set_text (activity, _("Storing changes…"));
+
+ scd = save_and_close_data_new (notes_editor);
+ scd->activity = activity; /* takes ownership */
+
+ e_content_editor_get_content (cnt_editor,
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES | E_CONTENT_EDITOR_GET_TO_SEND_HTML |
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN,
+ g_get_host_name (), e_activity_get_cancellable (activity),
+ mail_notes_get_content_ready_cb, scd);
+}
+
static void
e_mail_notes_editor_dispose (GObject *object)
{
diff --git a/src/modules/composer-to-meeting/e-composer-to-meeting.c
b/src/modules/composer-to-meeting/e-composer-to-meeting.c
index 8bc2b52bfc..04a328ce61 100644
--- a/src/modules/composer-to-meeting/e-composer-to-meeting.c
+++ b/src/modules/composer-to-meeting/e-composer-to-meeting.c
@@ -64,11 +64,10 @@ GType e_composer_to_meeting_get_type (void) G_GNUC_CONST;
G_DEFINE_DYNAMIC_TYPE (EComposerToMeeting, e_composer_to_meeting, E_TYPE_EXTENSION)
static ECalComponent *
-composer_to_meeting_component (EMsgComposer *composer)
+composer_to_meeting_component (EMsgComposer *composer,
+ EContentEditorContentHash *content_hash)
{
ECalComponent *comp;
- EHTMLEditor *html_editor;
- EContentEditor *cnt_editor;
EComposerHeaderTable *header_table;
EDestination **destinations_array[3];
ESource *source;
@@ -210,20 +209,12 @@ composer_to_meeting_component (EMsgComposer *composer)
g_slist_free_full (attendees, e_cal_component_attendee_free);
/* Description */
- html_editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (html_editor);
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ text = content_hash ? e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) : NULL;
+
if (text && *text) {
ECalComponentText *description;
GSList *descr_list = NULL;
- if (!g_str_has_suffix (text, "\r\n")) {
- gchar *tmp = text;
-
- text = g_strconcat (tmp, "\r\n", NULL);
- g_free (tmp);
- }
-
description = e_cal_component_text_new (text, NULL);
descr_list = g_slist_append (descr_list, description);
@@ -232,7 +223,6 @@ composer_to_meeting_component (EMsgComposer *composer)
g_slist_free_full (descr_list, e_cal_component_text_free);
}
- g_free (text);
return comp;
}
@@ -270,38 +260,102 @@ composer_to_meeting_copy_attachments (EMsgComposer *composer,
g_list_free_full (attachments, g_object_unref);
}
+typedef struct _AsyncContext {
+ EMsgComposer *composer;
+ EActivity *activity;
+} AsyncContext;
+
+static AsyncContext *
+async_context_new (EMsgComposer *composer, /* adds reference */
+ EActivity *activity) /* assumes ownership */
+{
+ AsyncContext *async_context;
+
+ async_context = g_slice_new (AsyncContext);
+ async_context->composer = g_object_ref (composer);
+ async_context->activity = activity;
+
+ return async_context;
+}
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+ if (async_context) {
+ g_clear_object (&async_context->composer);
+ g_clear_object (&async_context->activity);
+ g_slice_free (AsyncContext, async_context);
+ }
+}
+
+static void
+compose_to_meeting_content_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ EContentEditorContentHash *content_hash;
+ ECalComponent *comp;
+ GError *error = NULL;
+
+ g_return_if_fail (async_context != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ comp = composer_to_meeting_component (async_context->composer, content_hash);
+
+ if (comp) {
+ ECompEditor *comp_editor;
+ ECompEditorFlags flags;
+
+ flags = E_COMP_EDITOR_FLAG_IS_NEW |
+ E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER |
+ E_COMP_EDITOR_FLAG_WITH_ATTENDEES;
+
+ comp_editor = e_comp_editor_open_for_component (NULL, e_msg_composer_get_shell
(async_context->composer),
+ NULL, e_cal_component_get_icalcomponent (comp), flags);
+
+ /* Attachments */
+ composer_to_meeting_copy_attachments (async_context->composer, comp_editor);
+
+ gtk_window_present (GTK_WINDOW (comp_editor));
+
+ g_object_unref (comp);
+
+ gtk_widget_destroy (GTK_WIDGET (async_context->composer));
+ }
+
+ e_content_editor_util_free_content_hash (content_hash);
+ async_context_free (async_context);
+ g_clear_error (&error);
+}
+
static void
action_composer_to_meeting_cb (GtkAction *action,
EMsgComposer *composer)
{
- ECalComponent *comp;
- ECompEditor *comp_editor;
- ECompEditorFlags flags;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ EActivity *activity;
+ AsyncContext *async_context;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
if (!e_util_prompt_user (GTK_WINDOW (composer), NULL, NULL,
"mail-composer:prompt-composer-to-meeting", NULL))
return;
- comp = composer_to_meeting_component (composer);
- if (!comp)
- return;
-
- flags = E_COMP_EDITOR_FLAG_IS_NEW |
- E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER |
- E_COMP_EDITOR_FLAG_WITH_ATTENDEES;
-
- comp_editor = e_comp_editor_open_for_component (NULL, e_msg_composer_get_shell (composer),
- NULL, e_cal_component_get_icalcomponent (comp), flags);
-
- /* Attachments */
- composer_to_meeting_copy_attachments (composer, comp_editor);
+ editor = e_msg_composer_get_editor (composer);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- gtk_window_present (GTK_WINDOW (comp_editor));
+ activity = e_html_editor_new_activity (editor);
+ e_activity_set_text (activity, _("Reading text content…"));
- g_object_unref (comp);
+ async_context = async_context_new (composer, activity);
- gtk_widget_destroy (GTK_WIDGET (composer));
+ e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_PLAIN, NULL,
+ e_activity_get_cancellable (activity),
+ compose_to_meeting_content_ready_cb, async_context);
}
static void
diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index c133f8f12c..670fe30578 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -1775,147 +1775,150 @@ webkit_editor_insert_content (EContentEditor *editor,
g_warning ("Unsupported flags combination (%d) in (%s)", flags, G_STRFUNC);
}
-static CamelMimePart *
-create_part_for_inline_image_from_element_data (const gchar *element_src,
- const gchar *name,
- const gchar *id)
+static void
+webkit_editor_get_content (EContentEditor *editor,
+ guint32 flags, /* bit-or of EContentEditorGetContentFlags */
+ const gchar *inline_images_from_domain,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- CamelStream *stream;
- CamelDataWrapper *wrapper;
- CamelMimePart *part = NULL;
- gsize decoded_size;
- gssize size;
- gchar *mime_type = NULL;
- const gchar *base64_encoded_data;
- guchar *base64_decoded_data = NULL;
-
- base64_encoded_data = strstr (element_src, ";base64,");
- if (!base64_encoded_data)
- goto out;
+ gchar *script, *cid_uid_prefix;
- mime_type = g_strndup (
- element_src + 5,
- base64_encoded_data - (strstr (element_src, "data:") + 5));
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
- /* Move to actual data */
- base64_encoded_data += 8;
+ cid_uid_prefix = camel_header_msgid_generate (inline_images_from_domain ? inline_images_from_domain :
"");
+ script = e_web_view_jsc_printf_script ("EvoEditor.GetContent(%d, %s)", flags, cid_uid_prefix);
- base64_decoded_data = g_base64_decode (base64_encoded_data, &decoded_size);
+ webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (editor), script, cancellable, callback, user_data);
- stream = camel_stream_mem_new ();
- size = camel_stream_write (
- stream, (gchar *) base64_decoded_data, decoded_size, NULL, NULL);
+ g_free (cid_uid_prefix);
+ g_free (script);
+}
- if (size == -1)
- goto out;
+static EContentEditorContentHash *
+webkit_editor_get_content_finish (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error)
+{
+ WebKitJavascriptResult *js_result;
+ EContentEditorContentHash *content_hash = NULL;
+ GError *local_error = NULL;
- wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_construct_from_stream_sync (
- wrapper, stream, NULL, NULL);
- g_object_unref (stream);
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (editor), NULL);
+ g_return_val_if_fail (result != NULL, NULL);
- camel_data_wrapper_set_mime_type (wrapper, mime_type);
+ js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (editor), result, &local_error);
- part = camel_mime_part_new ();
- camel_medium_set_content (CAMEL_MEDIUM (part), wrapper);
- g_object_unref (wrapper);
+ if (local_error) {
+ g_propagate_error (error, local_error);
- camel_mime_part_set_content_id (part, id);
- camel_mime_part_set_filename (part, name);
- camel_mime_part_set_disposition (part, "inline");
- camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
-out:
- g_free (mime_type);
- g_free (base64_decoded_data);
+ if (js_result)
+ webkit_javascript_result_unref (js_result);
- return part;
-}
+ return NULL;
+ }
-static GSList *
-webkit_editor_get_parts_for_inline_images (GVariant *images)
-{
- const gchar *element_src, *name, *id;
- GVariantIter *iter;
- GSList *parts = NULL;
+ if (js_result) {
+ JSCException *exception;
+ JSCValue *value;
- if (g_variant_check_format_string (images, "a(sss)", FALSE)) {
- g_variant_get (images, "a(sss)", &iter);
- while (g_variant_iter_loop (iter, "(&s&s&s)", &element_src, &name, &id)) {
- CamelMimePart *part;
+ value = webkit_javascript_result_get_js_value (js_result);
+ exception = jsc_context_get_exception (jsc_value_get_context (value));
- part = create_part_for_inline_image_from_element_data (
- element_src, name, id);
- parts = g_slist_prepend (parts, part);
+ if (exception) {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "EvoEditor.GetContent() call
failed: %s", jsc_exception_get_message (exception));
+ jsc_context_clear_exception (jsc_value_get_context (value));
+ webkit_javascript_result_unref (js_result);
+ return NULL;
}
- g_variant_iter_free (iter);
- }
- return parts ? g_slist_reverse (parts) : NULL;
-}
+ if (jsc_value_is_object (value)) {
+ struct _formats {
+ const gchar *name;
+ guint32 flags;
+ } formats[] = {
+ { "raw-body-html", E_CONTENT_EDITOR_GET_RAW_BODY_HTML },
+ { "raw-body-plain", E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN },
+ { "raw-body-stripped", E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED },
+ { "raw-draft", E_CONTENT_EDITOR_GET_RAW_DRAFT },
+ { "to-send-html", E_CONTENT_EDITOR_GET_TO_SEND_HTML },
+ { "to-send-plain", E_CONTENT_EDITOR_GET_TO_SEND_PLAIN }
+ };
+ JSCValue *images_value;
+ gint ii;
+
+ content_hash = e_content_editor_util_new_content_hash ();
+
+ for (ii = 0; ii < G_N_ELEMENTS (formats); ii++) {
+ gchar *cnt;
+
+ cnt = e_web_view_jsc_get_object_property_string (value, formats[ii].name,
NULL);
+ if (cnt)
+ e_content_editor_util_take_content_data (content_hash,
formats[ii].flags, cnt, g_free);
+ }
-static gchar *
-webkit_editor_get_content (EContentEditor *editor,
- EContentEditorGetContentFlags flags,
- const gchar *inline_images_from_domain,
- GSList **inline_images_parts)
-{
- EWebKitEditor *wk_editor;
- GVariant *result;
- GError *local_error = NULL;
+ images_value = jsc_value_object_get_property (value, "images");
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy)
- return NULL;
+ if (images_value) {
+ if (jsc_value_is_array (images_value)) {
+ GSList *image_parts = NULL;
+ gint length;
- if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
- !(flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
- !(flags & E_CONTENT_EDITOR_GET_BODY))
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMEmbedStyleSheet",
- g_variant_new (
- "(ts)",
- current_page_id (wk_editor),
- wk_editor->priv->current_user_stylesheet),
- wk_editor->priv->cancellable);
+ length = e_web_view_jsc_get_object_property_int32 (images_value,
"length", 0);
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper (
- wk_editor->priv->web_extension_proxy,
- "DOMGetContent",
- g_variant_new (
- "(tsi)",
- current_page_id (wk_editor),
- inline_images_from_domain ? inline_images_from_domain : "",
- (gint32) flags),
- wk_editor->priv->cancellable,
- &local_error);
+ for (ii = 0; ii < length; ii++) {
+ JSCValue *item_value;
- webkit_editor_set_last_error (wk_editor, local_error);
- g_clear_error (&local_error);
+ item_value = jsc_value_object_get_property_at_index
(images_value, ii);
- if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
- !(flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
- !(flags & E_CONTENT_EDITOR_GET_BODY))
- webkit_editor_call_simple_extension_function (
- wk_editor, "DOMRemoveEmbeddedStyleSheet");
+ if (!item_value ||
+ jsc_value_is_null (item_value) ||
+ jsc_value_is_undefined (item_value)) {
+ g_warn_if_reached ();
+ g_clear_object (&item_value);
+ break;
+ }
- if (result) {
- GVariant *images = NULL;
- gchar *value = NULL;
+ if (jsc_value_is_object (item_value)) {
+ gchar *src, *cid;
- g_variant_get (result, "(sv)", &value, &images);
- if (inline_images_parts)
- *inline_images_parts = webkit_editor_get_parts_for_inline_images (images);
+ src = e_web_view_jsc_get_object_property_string
(item_value, "src", NULL);
+ cid = e_web_view_jsc_get_object_property_string
(item_value, "cid", NULL);
- if (images)
- g_variant_unref (images);
+ if (src && *src && cid && *cid) {
+ CamelMimePart *part;
- g_variant_unref (result);
+ part =
e_content_editor_util_create_data_mimepart (src, cid, TRUE, NULL, NULL,
+ E_WEBKIT_EDITOR
(editor)->priv->cancellable);
+
+ if (part)
+ image_parts = g_slist_prepend
(image_parts, part);
+ }
+
+ g_free (src);
+ g_free (cid);
+ }
+
+ g_clear_object (&item_value);
+ }
+
+ if (image_parts)
+ e_content_editor_util_take_content_data_images (content_hash,
image_parts);
+ } else {
+ g_warn_if_reached ();
+ }
- return value;
+ g_clear_object (&images_value);
+ }
+ } else {
+ g_warn_if_reached ();
+ }
+
+ webkit_javascript_result_unref (js_result);
}
- return NULL;
+ return content_hash;
}
static gboolean
@@ -2397,60 +2400,38 @@ webkit_editor_insert_signature (EContentEditor *editor,
return ret_val;
}
-static guint
-webkit_editor_get_caret_position (EContentEditor *editor)
+static void
+webkit_editor_get_caret_position (EContentEditor *editor,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
EWebKitEditor *wk_editor;
- GVariant *result;
- guint ret_val = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- printf ("EHTMLEditorWebExtension not ready at %s!\n", G_STRFUNC);
- return 0;
- }
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMGetCaretPosition",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
- if (result) {
- g_variant_get (result, "(u)", &ret_val);
- g_variant_unref (result);
- }
+ wk_editor = E_WEBKIT_EDITOR (editor);
- return ret_val;
+ /* TODO */
}
-static guint
-webkit_editor_get_caret_offset (EContentEditor *editor)
+static gboolean
+webkit_editor_get_caret_position_finish (EContentEditor *editor,
+ GAsyncResult *result,
+ guint *out_position,
+ guint *out_offset,
+ GError **error)
{
EWebKitEditor *wk_editor;
- GVariant *result;
- guint ret_val = 0;
+ gboolean success = FALSE;
- wk_editor = E_WEBKIT_EDITOR (editor);
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (editor), FALSE);
- if (!wk_editor->priv->web_extension_proxy) {
- printf ("EHTMLEditorWebExtension not ready at %s!\n", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMGetCaretOffset",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
+ wk_editor = E_WEBKIT_EDITOR (editor);
- if (result) {
- g_variant_get (result, "(u)", &ret_val);
- g_variant_unref (result);
- }
+ /* TODO */
- return ret_val;
+ return success;
}
static void
@@ -6498,6 +6479,7 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->update_styles = webkit_editor_update_styles;
iface->insert_content = webkit_editor_insert_content;
iface->get_content = webkit_editor_get_content;
+ iface->get_content_finish = webkit_editor_get_content_finish;
iface->insert_image = webkit_editor_insert_image;
iface->insert_image_from_mime_part = webkit_editor_insert_image_from_mime_part;
iface->insert_emoticon = webkit_editor_insert_emoticon;
@@ -6525,7 +6507,7 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->selection_restore = webkit_editor_selection_restore;
iface->selection_wrap = webkit_editor_selection_wrap;
iface->get_caret_position = webkit_editor_get_caret_position;
- iface->get_caret_offset = webkit_editor_get_caret_offset;
+ iface->get_caret_position_finish = webkit_editor_get_caret_position_finish;
iface->get_current_signature_uid = webkit_editor_get_current_signature_uid;
iface->is_ready = webkit_editor_is_ready;
iface->insert_signature = webkit_editor_insert_signature;
diff --git a/src/plugins/external-editor/external-editor.c b/src/plugins/external-editor/external-editor.c
index 51d91109c3..2c838250df 100644
--- a/src/plugins/external-editor/external-editor.c
+++ b/src/plugins/external-editor/external-editor.c
@@ -56,9 +56,6 @@ static gboolean key_press_cb (GtkWidget *widget,
GdkEventKey *event,
EMsgComposer *composer);
-/* used to track when the external editor is active */
-static GThread *editor_thread;
-
gint e_plugin_lib_enable (EPlugin *ep, gint enable);
gint
@@ -201,7 +198,7 @@ enable_composer_idle (gpointer user_data)
struct ExternalEditorData {
EMsgComposer *composer;
gchar *content;
- gint cursor_position, cursor_offset;
+ guint cursor_position, cursor_offset;
};
/* needed because the new thread needs to call g_idle_add () */
@@ -410,7 +407,60 @@ finished:
return NULL;
}
-static void launch_editor (GtkAction *action, EMsgComposer *composer)
+static void
+launch_editor_caret_position_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ struct ExternalEditorData *eed = user_data;
+ GThread *editor_thread;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+ g_return_if_fail (eed != NULL);
+
+ if (!e_content_editor_get_caret_position_finish (E_CONTENT_EDITOR (source_object),
+ result, &eed->cursor_position, &eed->cursor_offset, &error)) {
+ g_warning ("%s: Failed to get caret position: %s", G_STRFUNC, error ? error->message :
"Unknown error");
+ }
+
+ editor_thread = g_thread_new (NULL, external_editor_thread, eed);
+ g_thread_unref (editor_thread);
+ g_clear_error (&error);
+}
+
+static void
+launch_editor_content_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ struct ExternalEditorData *eed = user_data;
+ EContentEditor *cnt_editor;
+ EContentEditorContentHash *content_hash;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+ g_return_if_fail (eed != NULL);
+
+ cnt_editor = E_CONTENT_EDITOR (source_object);
+
+ content_hash = e_content_editor_get_content_finish (cnt_editor, result, &error);
+
+ if (!content_hash)
+ g_warning ("%s: Faild to get content: %s", G_STRFUNC, error ? error->message : "Unknown
error");
+
+ eed->content = content_hash ? e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) : NULL;
+
+ e_content_editor_get_caret_position (cnt_editor, NULL,
+ launch_editor_caret_position_ready_cb, eed);
+
+ e_content_editor_util_free_content_hash (content_hash);
+ g_clear_error (&error);
+}
+
+static void
+launch_editor (GtkAction *action,
+ EMsgComposer *composer)
{
struct ExternalEditorData *eed;
EHTMLEditor *editor;
@@ -435,16 +485,9 @@ static void launch_editor (GtkAction *action, EMsgComposer *composer)
eed = g_new0 (struct ExternalEditorData, 1);
eed->composer = g_object_ref (composer);
- eed->content = e_content_editor_get_content (cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
- eed->cursor_position = e_content_editor_get_caret_position (cnt_editor);
- if (eed->cursor_position > 0)
- eed->cursor_offset = e_content_editor_get_caret_offset (cnt_editor);
- editor_thread = g_thread_new (NULL, external_editor_thread, eed);
- g_thread_unref (editor_thread);
+ e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_PLAIN, NULL, NULL,
+ launch_editor_content_ready_cb, eed);
}
static GtkActionEntry entries[] = {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]