aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2014-09-09 19:25:18 +0800
committerMilan Crha <mcrha@redhat.com>2014-09-09 19:25:18 +0800
commitb10ef4f2725440f51b9a1136781b42176abacde7 (patch)
treeb50d2cd7cf8784d0461b4a1e02ea77037bdcdacb
parentb05e2a5f53c184c0ff47858916269e27eb9d51f3 (diff)
downloadgsoc2013-evolution-b10ef4f2725440f51b9a1136781b42176abacde7.tar
gsoc2013-evolution-b10ef4f2725440f51b9a1136781b42176abacde7.tar.gz
gsoc2013-evolution-b10ef4f2725440f51b9a1136781b42176abacde7.tar.bz2
gsoc2013-evolution-b10ef4f2725440f51b9a1136781b42176abacde7.tar.lz
gsoc2013-evolution-b10ef4f2725440f51b9a1136781b42176abacde7.tar.xz
gsoc2013-evolution-b10ef4f2725440f51b9a1136781b42176abacde7.tar.zst
gsoc2013-evolution-b10ef4f2725440f51b9a1136781b42176abacde7.zip
Bug 724909 - Highlight module hangs on large attachments
-rw-r--r--modules/text-highlight/e-mail-formatter-text-highlight.c176
1 files changed, 66 insertions, 110 deletions
diff --git a/modules/text-highlight/e-mail-formatter-text-highlight.c b/modules/text-highlight/e-mail-formatter-text-highlight.c
index 5946615c27..c35f90a44b 100644
--- a/modules/text-highlight/e-mail-formatter-text-highlight.c
+++ b/modules/text-highlight/e-mail-formatter-text-highlight.c
@@ -22,10 +22,6 @@
#include "e-mail-formatter-text-highlight.h"
#include "languages.h"
-/* FIXME Delete these once we can use GSubprocess. */
-#include <gio/gunixinputstream.h>
-#include <gio/gunixoutputstream.h>
-
#include <em-format/e-mail-formatter-extension.h>
#include <em-format/e-mail-formatter.h>
#include <em-format/e-mail-part-utils.h>
@@ -35,7 +31,6 @@
#include <libedataserver/libedataserver.h>
#include <glib/gi18n-lib.h>
-#include <X11/Xlib.h>
#include <camel/camel.h>
typedef EMailFormatterExtension EMailFormatterTextHighlight;
@@ -47,9 +42,10 @@ typedef EExtensionClass EMailFormatterTextHighlightLoaderClass;
typedef struct _TextHighlightClosure TextHighlightClosure;
struct _TextHighlightClosure {
- GMainLoop *main_loop;
- GError *input_error;
- GError *output_error;
+ CamelStream *read_stream;
+ GOutputStream *output_stream;
+ GCancellable *cancellable;
+ GError *error;
};
GType e_mail_formatter_text_highlight_get_type (void);
@@ -122,30 +118,29 @@ get_syntax (EMailPart *part,
return syntax;
}
-static void
-text_highlight_input_spliced (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+static gpointer
+text_hightlight_read_data_thread (gpointer user_data)
{
TextHighlightClosure *closure = user_data;
+ gchar buffer[10240];
- g_output_stream_splice_finish (
- G_OUTPUT_STREAM (source_object),
- result, &closure->input_error);
-}
+ g_return_val_if_fail (closure != NULL, NULL);
-static void
-text_highlight_output_spliced (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- TextHighlightClosure *closure = user_data;
+ while (!camel_stream_eos (closure->read_stream) &&
+ !g_cancellable_set_error_if_cancelled (closure->cancellable, &closure->error)) {
+ gssize read;
+ gsize wrote = 0;
- g_output_stream_splice_finish (
- G_OUTPUT_STREAM (source_object),
- result, &closure->output_error);
+ read = camel_stream_read (closure->read_stream, buffer, 10240, closure->cancellable, &closure->error);
+ if (read < 0 || closure->error)
+ break;
+
+ if (!g_output_stream_write_all (closure->output_stream, buffer, read, &wrote, closure->cancellable, &closure->error) ||
+ (gssize) wrote != read || closure->error)
+ break;
+ }
- g_main_loop_quit (closure->main_loop);
+ return NULL;
}
static gboolean
@@ -157,105 +152,66 @@ text_highlight_feed_data (GOutputStream *output_stream,
GError **error)
{
TextHighlightClosure closure;
- GInputStream *input_stream = NULL;
- GOutputStream *temp_stream = NULL;
- GInputStream *stdout_stream = NULL;
- GOutputStream *stdin_stream = NULL;
- GMainContext *main_context;
- gchar *utf8_data;
- gconstpointer data;
- gsize size;
- gboolean success;
-
- /* We need to dump CamelDataWrapper to a buffer, force the content
- * to valid UTF-8, feed the UTF-8 data to the 'highlight' process,
- * read the converted data back and feed it to the CamelStream. */
-
- /* FIXME Use GSubprocess once we can require GLib 2.40. */
-
- temp_stream = g_memory_output_stream_new_resizable ();
-
- success = camel_data_wrapper_decode_to_output_stream_sync (
- data_wrapper, temp_stream, cancellable, error);
-
- if (!success)
- goto exit;
-
- main_context = g_main_context_new ();
-
- closure.main_loop = g_main_loop_new (main_context, FALSE);
- closure.input_error = NULL;
- closure.output_error = NULL;
+ CamelContentType *content_type;
+ CamelStream *write_stream;
+ gboolean success = TRUE;
+ GThread *thread;
- g_main_context_push_thread_default (main_context);
+ closure.read_stream = camel_stream_fs_new_with_fd (pipe_stdout);
+ closure.output_stream = output_stream;
+ closure.cancellable = cancellable;
+ closure.error = NULL;
- data = g_memory_output_stream_get_data (
- G_MEMORY_OUTPUT_STREAM (temp_stream));
- size = g_memory_output_stream_get_data_size (
- G_MEMORY_OUTPUT_STREAM (temp_stream));
+ write_stream = camel_stream_fs_new_with_fd (pipe_stdin);
- /* FIXME Write a GConverter that does this so we can decode
- * straight to the stdin pipe and skip all this extra
- * buffering. */
- utf8_data = e_util_utf8_data_make_valid ((gchar *) data, size);
+ thread = g_thread_new (NULL, text_hightlight_read_data_thread, &closure);
- g_clear_object (&temp_stream);
+ content_type = camel_data_wrapper_get_mime_type_field (data_wrapper);
+ if (content_type) {
+ const gchar *charset = camel_content_type_param (content_type, "charset");
- /* Takes ownership of the UTF-8 string. */
- input_stream = g_memory_input_stream_new_from_data (
- utf8_data, -1, (GDestroyNotify) g_free);
+ /* Convert to UTF-8 charset, if needed, which the 'highlight' expects;
+ it can cope with non-UTF-8 letters, thus no need for a content UTF-8-validation */
+ if (charset && g_ascii_strcasecmp (charset, "utf-8") != 0) {
+ CamelMimeFilter *filter;
- stdin_stream = g_unix_output_stream_new (pipe_stdin, TRUE);
- stdout_stream = g_unix_input_stream_new (pipe_stdout, TRUE);
+ filter = camel_mime_filter_charset_new (charset, "UTF-8");
+ if (filter != NULL) {
+ CamelStream *filtered = camel_stream_filter_new (write_stream);
- /* Splice the streams together. */
+ if (filtered) {
+ camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered), filter);
+ g_object_unref (write_stream);
+ write_stream = filtered;
+ }
- /* GCancellable is only supposed to be used in one operation
- * at a time. Skip it here and use it for reading converted
- * data, since that operation terminates the main loop. */
- g_output_stream_splice_async (
- stdin_stream, input_stream,
- G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
- G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
- G_PRIORITY_DEFAULT, NULL,
- text_highlight_input_spliced,
- &closure);
-
- g_output_stream_splice_async (
- output_stream, stdout_stream,
- G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
- G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
- G_PRIORITY_DEFAULT, cancellable,
- text_highlight_output_spliced,
- &closure);
+ g_object_unref (filter);
+ }
+ }
+ }
- g_main_loop_run (closure.main_loop);
+ if (camel_data_wrapper_decode_to_stream_sync (data_wrapper, write_stream, cancellable, error) < 0) {
+ g_cancellable_cancel (cancellable);
+ success = FALSE;
+ } else {
+ /* Close the stream, thus the highlight knows no more data will come */
+ g_clear_object (&write_stream);
+ }
- g_main_context_pop_thread_default (main_context);
+ g_thread_join (thread);
- g_main_context_unref (main_context);
- g_main_loop_unref (closure.main_loop);
+ g_clear_object (&closure.read_stream);
+ g_clear_object (&write_stream);
- g_clear_object (&input_stream);
- g_clear_object (&stdin_stream);
- g_clear_object (&stdout_stream);
+ if (closure.error) {
+ if (error && !*error)
+ g_propagate_error (error, closure.error);
+ else
+ g_clear_error (&closure.error);
- if (closure.input_error != NULL) {
- g_propagate_error (error, closure.input_error);
- g_clear_error (&closure.output_error);
- success = FALSE;
- goto exit;
+ return FALSE;
}
- if (closure.output_error != NULL) {
- g_propagate_error (error, closure.output_error);
- success = FALSE;
- goto exit;
- }
-
-exit:
- g_clear_object (&temp_stream);
-
return success;
}