[evolution] I#353 - [Prefer Plain] Generate plain text from text/html, if not available
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] I#353 - [Prefer Plain] Generate plain text from text/html, if not available
- Date: Fri, 11 Sep 2020 06:39:32 +0000 (UTC)
commit bf38f23d01739e4e8a485a01245f1e9a7edd4701
Author: Milan Crha <mcrha redhat com>
Date: Fri Sep 11 08:38:44 2020 +0200
I#353 - [Prefer Plain] Generate plain text from text/html, if not available
Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/353
src/mail/e-http-request.c | 15 +-
.../prefer-plain/e-mail-parser-prefer-plain.c | 197 +++++++++++++++++++--
src/web-extensions/e-web-extension.c | 7 +-
3 files changed, 197 insertions(+), 22 deletions(-)
---
diff --git a/src/mail/e-http-request.c b/src/mail/e-http-request.c
index d8690b7545..bd5f8d44e4 100644
--- a/src/mail/e-http-request.c
+++ b/src/mail/e-http-request.c
@@ -188,6 +188,7 @@ e_http_request_process_sync (EContentRequest *request,
gchar *mail_uri = NULL;
GInputStream *stream;
gboolean force_load_images = FALSE;
+ gboolean disable_remote_content = FALSE;
EImageLoadingPolicy image_policy;
gchar *uri_md5;
EShell *shell;
@@ -341,9 +342,17 @@ e_http_request_process_sync (EContentRequest *request,
if (!e_shell_get_online (shell))
goto cleanup;
- settings = e_util_ref_settings ("org.gnome.evolution.mail");
- image_policy = g_settings_get_enum (settings, "image-loading-policy");
- g_object_unref (settings);
+ if (WEBKIT_IS_WEB_VIEW (requester))
+ disable_remote_content = g_strcmp0 (webkit_web_view_get_uri (WEBKIT_WEB_VIEW (requester)),
"evo://disable-remote-content") == 0;
+
+ if (disable_remote_content) {
+ force_load_images = FALSE;
+ image_policy = E_IMAGE_LOADING_POLICY_NEVER;
+ } else {
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ image_policy = g_settings_get_enum (settings, "image-loading-policy");
+ g_object_unref (settings);
+ }
/* Item not found in cache, but image loading policy allows us to fetch
* it from the interwebs */
diff --git a/src/modules/prefer-plain/e-mail-parser-prefer-plain.c
b/src/modules/prefer-plain/e-mail-parser-prefer-plain.c
index af84ef9af6..823b4240a1 100644
--- a/src/modules/prefer-plain/e-mail-parser-prefer-plain.c
+++ b/src/modules/prefer-plain/e-mail-parser-prefer-plain.c
@@ -18,8 +18,6 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
-#include "e-mail-parser-prefer-plain.h"
-
#include <em-format/e-mail-extension-registry.h>
#include <em-format/e-mail-parser-extension.h>
#include <em-format/e-mail-part.h>
@@ -28,14 +26,11 @@
#include <libebackend/libebackend.h>
#include <e-util/e-util.h>
-#define d(x)
+#include "e-mail-parser-prefer-plain.h"
typedef struct _EMailParserPreferPlain EMailParserPreferPlain;
typedef struct _EMailParserPreferPlainClass EMailParserPreferPlainClass;
-typedef EExtension EMailParserPreferPlainLoader;
-typedef EExtensionClass EMailParserPreferPlainLoaderClass;
-
struct _EMailParserPreferPlain {
EMailParserExtension parent;
@@ -57,10 +52,7 @@ enum {
ONLY_PLAIN
};
-G_DEFINE_DYNAMIC_TYPE (
- EMailParserPreferPlain,
- e_mail_parser_prefer_plain,
- E_TYPE_MAIL_PARSER_EXTENSION)
+G_DEFINE_DYNAMIC_TYPE (EMailParserPreferPlain, e_mail_parser_prefer_plain, E_TYPE_MAIL_PARSER_EXTENSION)
static const gchar *parser_mime_types[] = {
"multipart/alternative",
@@ -196,6 +188,150 @@ hide_parts (GQueue *work_queue)
}
}
+static gchar *
+mail_parser_prefer_plain_dup_part_text (CamelMimePart *mime_part,
+ GCancellable *cancellable)
+{
+ CamelDataWrapper *data_wrapper;
+ CamelMedium *medium;
+ CamelStream *stream;
+ GByteArray *array;
+ gchar *content;
+
+ if (!mime_part)
+ return NULL;
+
+ array = g_byte_array_new ();
+ medium = CAMEL_MEDIUM (mime_part);
+
+ /* Stream takes ownership of the byte array. */
+ stream = camel_stream_mem_new_with_byte_array (array);
+ data_wrapper = camel_medium_get_content (medium);
+ camel_data_wrapper_decode_to_stream_sync (
+ data_wrapper, stream, NULL, NULL);
+
+ content = g_strndup ((gchar *) array->data, array->len);
+
+ g_object_unref (stream);
+
+ return content;
+}
+
+typedef struct _AsyncContext {
+ gchar *text_input;
+ gchar *text_output;
+ GCancellable *cancellable;
+ EFlag *flag;
+ WebKitWebView *web_view;
+} AsyncContext;
+
+static void
+mail_parser_prefer_plain_convert_jsc_call_done_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ WebKitJavascriptResult *js_result;
+ AsyncContext *async_context = user_data;
+ GError *error = NULL;
+
+ g_return_if_fail (async_context != NULL);
+
+ js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source), result, &error);
+
+ if (error) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+ (!g_error_matches (error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED)
||
+ /* WebKit can return empty error message, thus ignore those. */
+ (error->message && *(error->message))))
+ g_warning ("%s: JSC call failed: %s:%d: %s", G_STRFUNC, g_quark_to_string
(error->domain), error->code, error->message);
+ g_clear_error (&error);
+ }
+
+ if (js_result) {
+ JSCException *exception;
+ JSCValue *value;
+
+ value = webkit_javascript_result_get_js_value (js_result);
+ exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+ if (exception) {
+ g_warning ("%s: JSC call failed: %s", G_STRFUNC, jsc_exception_get_message
(exception));
+ jsc_context_clear_exception (jsc_value_get_context (value));
+ } else if (jsc_value_is_string (value)) {
+ async_context->text_output = jsc_value_to_string (value);
+ }
+
+ webkit_javascript_result_unref (js_result);
+ }
+
+ g_clear_object (&async_context->web_view);
+
+ e_flag_set (async_context->flag);
+}
+
+static gboolean
+mail_parser_prefer_plain_convert_text (gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ gchar *script;
+
+ g_return_val_if_fail (async_context != NULL, FALSE);
+
+ async_context->web_view = g_object_ref_sink (e_web_view_new ());
+
+ e_web_view_load_uri (E_WEB_VIEW (async_context->web_view), "evo://disable-remote-content");
+
+ script = e_web_view_jsc_printf_script (
+ "var elem;\n"
+ "elem = document.createElement('X-EVO-CONVERT');\n"
+ "elem.innerHTML = %s;\n"
+ "EvoConvert.ToPlainText(elem, -1);",
+ async_context->text_input);
+
+ webkit_web_view_run_javascript (async_context->web_view, script, async_context->cancellable,
+ mail_parser_prefer_plain_convert_jsc_call_done_cb, async_context);
+
+ g_free (script);
+
+ return FALSE;
+}
+
+static gchar *
+mail_parser_prefer_plain_convert_content_sync (CamelMimePart *mime_part,
+ GCancellable *cancellable)
+{
+ AsyncContext async_context;
+ gchar *res = NULL;
+
+ memset (&async_context, 0, sizeof (AsyncContext));
+
+ async_context.text_input = mail_parser_prefer_plain_dup_part_text (mime_part, cancellable);
+
+ if (!async_context.text_input || g_cancellable_is_cancelled (cancellable)) {
+ g_free (async_context.text_input);
+ return NULL;
+ }
+
+ async_context.flag = e_flag_new ();
+ async_context.cancellable = cancellable;
+
+ /* Run it in the main/GUI thread */
+ g_timeout_add (1, mail_parser_prefer_plain_convert_text, &async_context);
+
+ e_flag_wait (async_context.flag);
+ e_flag_free (async_context.flag);
+
+ if (async_context.text_output) {
+ res = async_context.text_output;
+ async_context.text_output = NULL;
+ }
+
+ g_free (async_context.text_input);
+ g_free (async_context.text_output);
+
+ return res;
+}
+
static gboolean
empe_prefer_plain_parse (EMailParserExtension *extension,
EMailParser *parser,
@@ -250,12 +386,40 @@ empe_prefer_plain_parse (EMailParserExtension *extension,
if (emp_pp->mode != ONLY_PLAIN)
return FALSE;
- /* Enforcing text/plain but got only HTML part, so add it
- * as attachment to not show empty message preview, which
- * is confusing. */
- make_part_attachment (
- parser, part, part_id, TRUE,
- cancellable, out_mail_parts);
+ if (!e_mail_part_is_attachment (part)) {
+ gchar *content;
+
+ partidlen = part_id->len;
+
+ g_string_truncate (part_id, partidlen);
+ g_string_append_printf (part_id, ".alternative-prefer-plain.%d.converted", -1);
+
+ content = mail_parser_prefer_plain_convert_content_sync (part, cancellable);
+
+ if (content) {
+ EMailPart *mail_part;
+ CamelMimePart *text_part;
+
+ text_part = camel_mime_part_new ();
+ camel_mime_part_set_content (text_part, content, strlen (content),
"application/vnd.evolution.plaintext");
+ mail_part = e_mail_part_new (text_part, part_id->str);
+ e_mail_part_set_mime_type (mail_part, "application/vnd.evolution.plaintext");
+ g_free (content);
+
+ g_queue_push_tail (out_mail_parts, mail_part);
+ }
+
+ g_string_truncate (part_id, partidlen);
+ }
+
+ if (emp_pp->show_suppressed || e_mail_part_is_attachment (part)) {
+ /* Enforcing text/plain but got only HTML part, so add it
+ * as attachment to not show empty message preview, which
+ * is confusing. */
+ make_part_attachment (
+ parser, part, part_id, TRUE,
+ cancellable, out_mail_parts);
+ }
return TRUE;
}
@@ -565,4 +729,3 @@ e_mail_parser_prefer_plain_type_register (GTypeModule *type_module)
{
e_mail_parser_prefer_plain_register_type (type_module);
}
-
diff --git a/src/web-extensions/e-web-extension.c b/src/web-extensions/e-web-extension.c
index 979818a67c..deea1bdaa7 100644
--- a/src/web-extensions/e-web-extension.c
+++ b/src/web-extensions/e-web-extension.c
@@ -104,11 +104,14 @@ web_page_send_request_cb (WebKitWebPage *web_page,
request_uri = webkit_uri_request_get_uri (request);
page_uri = webkit_web_page_get_uri (web_page);
+ if (!request_uri)
+ return FALSE;
+
/* Always load the main resource. */
if (g_strcmp0 (request_uri, page_uri) == 0 ||
/* Do not influence real pages, like those with eds OAuth sign-in */
- g_str_has_prefix (page_uri, "http:") ||
- g_str_has_prefix (page_uri, "https:"))
+ (page_uri && (g_str_has_prefix (page_uri, "http:") ||
+ g_str_has_prefix (page_uri, "https:"))))
return FALSE;
if (g_str_has_prefix (request_uri, "http:") ||
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]