diff options
author | Ting-Wei Lan <lantw@src.gnome.org> | 2014-09-03 15:10:11 +0800 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2014-09-03 15:10:11 +0800 |
commit | 2d345f3d94a85360e92ef566257c1bc738b6cdc2 (patch) | |
tree | 686b5cdcb87a4651523b9784e97078a6db546de5 /e-util/e-attachment.c | |
parent | 707ba2751903f08369d2c8fa7779140b49f6051b (diff) | |
download | gsoc2013-evolution-2d345f3d94a85360e92ef566257c1bc738b6cdc2.tar gsoc2013-evolution-2d345f3d94a85360e92ef566257c1bc738b6cdc2.tar.gz gsoc2013-evolution-2d345f3d94a85360e92ef566257c1bc738b6cdc2.tar.bz2 gsoc2013-evolution-2d345f3d94a85360e92ef566257c1bc738b6cdc2.tar.lz gsoc2013-evolution-2d345f3d94a85360e92ef566257c1bc738b6cdc2.tar.xz gsoc2013-evolution-2d345f3d94a85360e92ef566257c1bc738b6cdc2.tar.zst gsoc2013-evolution-2d345f3d94a85360e92ef566257c1bc738b6cdc2.zip |
Bug 707647 - gnome-autoar integration in attachments
Diffstat (limited to 'e-util/e-attachment.c')
-rw-r--r-- | e-util/e-attachment.c | 523 |
1 files changed, 450 insertions, 73 deletions
diff --git a/e-util/e-attachment.c b/e-util/e-attachment.c index 1ce400767d..97287f4a40 100644 --- a/e-util/e-attachment.c +++ b/e-util/e-attachment.c @@ -28,6 +28,11 @@ #include <glib/gi18n.h> #include <glib/gstdio.h> +#ifdef HAVE_AUTOAR +#include <gnome-autoar/autoar.h> +#include <gnome-autoar/autoar-gtk.h> +#endif + #include <libedataserver/libedataserver.h> #include "e-attachment-store.h" @@ -74,6 +79,9 @@ struct _EAttachmentPrivate { guint saving : 1; guint shown : 1; + guint save_self : 1; + guint save_extracted : 1; + camel_cipher_validity_encrypt_t encrypted; camel_cipher_validity_sign_t signed_; @@ -103,6 +111,8 @@ enum { PROP_MIME_PART, PROP_PERCENT, PROP_REFERENCE, + PROP_SAVE_SELF, + PROP_SAVE_EXTRACTED, PROP_SAVING, PROP_SHOWN, PROP_SIGNED @@ -202,6 +212,38 @@ attachment_get_default_charset (void) return charset; } +static GFile* +attachment_get_temporary (GError **error) +{ + gchar *template; + gchar *path; + GFile *temp_directory; + + errno = 0; + + /* Save the file to a temporary directory. + * We use a directory so the files can retain their basenames. + * XXX This could trigger a blocking temp directory cleanup. */ + template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ()); + path = e_mkdtemp (template); + g_free (template); + + /* XXX Let's hope errno got set properly. */ + if (path == NULL) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s", g_strerror (errno)); + return NULL; + } + + temp_directory = g_file_new_for_path (path); + g_free (path); + + return temp_directory; +} + + static gboolean attachment_update_file_info_columns_idle_cb (gpointer weak_ref) { @@ -671,6 +713,18 @@ attachment_set_property (GObject *object, E_ATTACHMENT (object), g_value_get_int (value)); return; + + case PROP_SAVE_SELF: + e_attachment_set_save_self ( + E_ATTACHMENT (object), + g_value_get_boolean (value)); + return; + + case PROP_SAVE_EXTRACTED: + e_attachment_set_save_extracted ( + E_ATTACHMENT (object), + g_value_get_boolean (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -760,6 +814,20 @@ attachment_get_property (GObject *object, E_ATTACHMENT (object))); return; + case PROP_SAVE_SELF: + g_value_set_boolean ( + value, + e_attachment_get_save_self ( + E_ATTACHMENT (object))); + return; + + case PROP_SAVE_EXTRACTED: + g_value_set_boolean ( + value, + e_attachment_get_save_extracted ( + E_ATTACHMENT (object))); + return; + case PROP_SAVING: g_value_set_boolean ( value, @@ -953,6 +1021,26 @@ e_attachment_class_init (EAttachmentClass *class) g_object_class_install_property ( object_class, + PROP_SAVE_SELF, + g_param_spec_boolean ( + "save-self", + "Save self", + NULL, + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_SAVE_EXTRACTED, + g_param_spec_boolean ( + "save-extracted", + "Save extracted", + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, PROP_SAVING, g_param_spec_boolean ( "saving", @@ -1531,6 +1619,40 @@ e_attachment_set_shown (EAttachment *attachment, g_object_notify (G_OBJECT (attachment), "shown"); } +gboolean +e_attachment_get_save_self (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), TRUE); + + return attachment->priv->save_self; +} + +void +e_attachment_set_save_self (EAttachment *attachment, + gboolean save_self) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + attachment->priv->save_self = save_self; +} + +gboolean +e_attachment_get_save_extracted (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + + return attachment->priv->save_extracted; +} + +void +e_attachment_set_save_extracted (EAttachment *attachment, + gboolean save_extracted) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + attachment->priv->save_extracted = save_extracted; +} + camel_cipher_validity_encrypt_t e_attachment_get_encrypted (EAttachment *attachment) { @@ -1699,6 +1821,10 @@ static void attachment_load_stream_read_cb (GInputStream *input_stream, GAsyncResult *result, LoadContext *load_context); +static void +attachment_load_query_info_cb (GFile *file, + GAsyncResult *result, + LoadContext *load_context); static LoadContext * attachment_load_context_new (EAttachment *attachment, @@ -1960,6 +2086,58 @@ attachment_load_file_read_cb (GFile *file, load_context); } +#ifdef HAVE_AUTOAR +static void +attachment_load_created_decide_dest_cb (AutoarCreate *arcreate, + GFile *destination, + EAttachment *attachment) +{ + e_attachment_set_file (attachment, destination); +} + +static void +attachment_load_created_cancelled_cb (AutoarCreate *arcreate, + LoadContext *load_context) +{ + attachment_load_check_for_error (load_context, + g_error_new_literal ( + G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled"))); + g_object_unref (arcreate); +} + +static void +attachment_load_created_completed_cb (AutoarCreate *arcreate, + LoadContext *load_context) +{ + EAttachment *attachment; + GFile *file; + + g_object_unref (arcreate); + + /* We have set the file to the created temporary archive, so we can + * query info again and use the regular procedure to load the + * attachment. */ + attachment = load_context->attachment; + file = e_attachment_ref_file (attachment); + g_file_query_info_async ( + file, ATTACHMENT_QUERY, + G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, + attachment->priv->cancellable, (GAsyncReadyCallback) + attachment_load_query_info_cb, load_context); + + g_clear_object (&file); +} + +static void +attachment_load_created_error_cb (AutoarCreate *arcreate, + GError *error, + LoadContext *load_context) +{ + attachment_load_check_for_error (load_context, g_error_copy (error)); + g_object_unref (arcreate); +} +#endif + static void attachment_load_query_info_cb (GFile *file, GAsyncResult *result, @@ -1982,10 +2160,37 @@ attachment_load_query_info_cb (GFile *file, load_context->total_num_bytes = g_file_info_get_size (file_info); - g_file_read_async ( - file, G_PRIORITY_DEFAULT, - cancellable, (GAsyncReadyCallback) - attachment_load_file_read_cb, load_context); +#ifdef HAVE_AUTOAR + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { + AutoarCreate *arcreate; + AutoarPref *arpref; /* Do not unref */ + GFile *temporary; + + arpref = g_object_get_data (G_OBJECT (attachment), "autoar-pref"); + temporary = attachment_get_temporary (&error); + if (attachment_load_check_for_error (load_context, error)) + return; + arcreate = autoar_create_new_file (arpref, temporary, file, NULL); + g_signal_connect (arcreate, "decide-dest", + G_CALLBACK (attachment_load_created_decide_dest_cb), attachment); + g_signal_connect (arcreate, "cancelled", + G_CALLBACK (attachment_load_created_cancelled_cb), load_context); + g_signal_connect (arcreate, "completed", + G_CALLBACK (attachment_load_created_completed_cb), load_context); + g_signal_connect (arcreate, "error", + G_CALLBACK (attachment_load_created_error_cb), load_context); + autoar_create_start_async (arcreate, cancellable); + + g_object_unref (temporary); + } else { +#endif + g_file_read_async ( + file, G_PRIORITY_DEFAULT, + cancellable, (GAsyncReadyCallback) + attachment_load_file_read_cb, load_context); +#ifdef HAVE_AUTOAR + } +#endif } #define ATTACHMENT_LOAD_CONTEXT "attachment-load-context-data" @@ -2453,39 +2658,20 @@ static void attachment_open_save_temporary (OpenContext *open_context) { GFile *temp_directory; - gchar *template; - gchar *path; GError *error = NULL; - errno = 0; - - /* Save the file to a temporary directory. - * We use a directory so the files can retain their basenames. - * XXX This could trigger a blocking temp directory cleanup. */ - template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ()); - path = e_mkdtemp (template); - g_free (template); - - /* XXX Let's hope errno got set properly. */ - if (path == NULL) - g_set_error ( - &error, G_FILE_ERROR, - g_file_error_from_errno (errno), - "%s", g_strerror (errno)); + temp_directory = attachment_get_temporary (&error); /* We already know if there's an error, but this does the cleanup. */ if (attachment_open_check_for_error (open_context, error)) return; - temp_directory = g_file_new_for_path (path); - e_attachment_save_async ( open_context->attachment, temp_directory, (GAsyncReadyCallback) attachment_open_save_finished_cb, open_context); g_object_unref (temp_directory); - g_free (path); } void @@ -2635,6 +2821,16 @@ struct _SaveContext { gssize bytes_read; gchar buffer[4096]; gint count; + + GByteArray *input_buffer; + gchar *suggested_destname; + + guint total_tasks : 2; + guint completed_tasks : 2; + guint prepared_tasks : 2; + + GMutex completed_tasks_mutex; + GMutex prepared_tasks_mutex; }; /* Forward Declaration */ @@ -2659,6 +2855,9 @@ attachment_save_context_new (EAttachment *attachment, save_context->attachment = g_object_ref (attachment); save_context->simple = simple; + g_mutex_init (&(save_context->completed_tasks_mutex)); + g_mutex_init (&(save_context->prepared_tasks_mutex)); + attachment_set_saving (save_context->attachment, TRUE); return save_context; @@ -2682,6 +2881,15 @@ attachment_save_context_free (SaveContext *save_context) if (save_context->output_stream != NULL) g_object_unref (save_context->output_stream); + if (save_context->input_buffer != NULL) + g_byte_array_unref (save_context->input_buffer); + + if (save_context->suggested_destname != NULL) + g_free (save_context->suggested_destname); + + g_mutex_clear (&(save_context->completed_tasks_mutex)); + g_mutex_clear (&(save_context->prepared_tasks_mutex)); + g_slice_free (SaveContext, save_context); } @@ -2696,13 +2904,46 @@ attachment_save_check_for_error (SaveContext *save_context, simple = save_context->simple; g_simple_async_result_take_error (simple, error); - g_simple_async_result_complete (simple); - attachment_save_context_free (save_context); + g_mutex_lock (&(save_context->completed_tasks_mutex)); + if (++save_context->completed_tasks >= save_context->total_tasks) { + g_simple_async_result_complete (simple); + g_mutex_unlock (&(save_context->completed_tasks_mutex)); + attachment_save_context_free (save_context); + } else { + g_mutex_unlock (&(save_context->completed_tasks_mutex)); + } return TRUE; } +static void +attachment_save_complete (SaveContext *save_context) { + g_mutex_lock (&(save_context->completed_tasks_mutex)); + if (++save_context->completed_tasks >= save_context->total_tasks) { + GSimpleAsyncResult *simple; + GFile *result; + + /* Steal the destination. */ + result = save_context->destination; + save_context->destination = NULL; + + if (result == NULL) { + result = save_context->directory; + save_context->directory = NULL; + } + + simple = save_context->simple; + g_simple_async_result_set_op_res_gpointer ( + simple, result, (GDestroyNotify) g_object_unref); + g_simple_async_result_complete (simple); + g_mutex_unlock (&(save_context->completed_tasks_mutex)); + attachment_save_context_free (save_context); + } else { + g_mutex_unlock (&(save_context->completed_tasks_mutex)); + } +} + static GFile * attachment_save_new_candidate (SaveContext *save_context) { @@ -2817,20 +3058,7 @@ attachment_save_read_cb (GInputStream *input_stream, return; if (bytes_read == 0) { - GSimpleAsyncResult *simple; - GFile *destination; - - /* Steal the destination. */ - destination = save_context->destination; - save_context->destination = NULL; - - simple = save_context->simple; - g_simple_async_result_set_op_res_gpointer ( - simple, destination, (GDestroyNotify) g_object_unref); - g_simple_async_result_complete (simple); - - attachment_save_context_free (save_context); - + attachment_save_complete (save_context); return; } @@ -2852,6 +3080,46 @@ attachment_save_read_cb (GInputStream *input_stream, save_context); } +#ifdef HAVE_AUTOAR +static void +attachment_save_extracted_progress_cb (AutoarExtract *arextract, + guint64 completed_size, + guint completed_files, + SaveContext *save_context) +{ + attachment_progress_cb ( + autoar_extract_get_size (arextract), + completed_size, save_context->attachment); +} + +static void +attachment_save_extracted_cancelled_cb (AutoarExtract *arextract, + SaveContext *save_context) +{ + attachment_save_check_for_error (save_context, + g_error_new_literal ( + G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled"))); + g_object_unref (arextract); +} + +static void +attachment_save_extracted_completed_cb (AutoarExtract *arextract, + SaveContext *save_context) +{ + attachment_save_complete (save_context); + g_object_unref (arextract); +} + +static void +attachment_save_extracted_error_cb (AutoarExtract *arextract, + GError *error, + SaveContext *save_context) +{ + attachment_save_check_for_error (save_context, g_error_copy (error)); + g_object_unref (arextract); +} +#endif + static void attachment_save_got_output_stream (SaveContext *save_context) { @@ -2877,25 +3145,67 @@ attachment_save_got_output_stream (SaveContext *save_context) camel_data_wrapper_decode_to_stream_sync (wrapper, stream, NULL, NULL); g_object_unref (stream); - /* Load the buffer into a GMemoryInputStream. - * But watch out for zero length MIME parts. */ - input_stream = g_memory_input_stream_new (); - if (buffer->len > 0) - g_memory_input_stream_add_data ( - G_MEMORY_INPUT_STREAM (input_stream), - buffer->data, (gssize) buffer->len, - (GDestroyNotify) g_free); - save_context->input_stream = input_stream; - save_context->total_num_bytes = (goffset) buffer->len; - g_byte_array_free (buffer, FALSE); + save_context->input_buffer = buffer; - g_input_stream_read_async ( - input_stream, - save_context->buffer, - sizeof (save_context->buffer), - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_save_read_cb, - save_context); + if (attachment->priv->save_self) { + /* Load the buffer into a GMemoryInputStream. + * But watch out for zero length MIME parts. */ + input_stream = g_memory_input_stream_new (); + if (buffer->len > 0) + g_memory_input_stream_add_data ( + G_MEMORY_INPUT_STREAM (input_stream), + buffer->data, (gssize) buffer->len, NULL); + save_context->input_stream = input_stream; + save_context->total_num_bytes = (goffset) buffer->len; + + g_input_stream_read_async ( + input_stream, + save_context->buffer, + sizeof (save_context->buffer), + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_read_cb, + save_context); + } + +#ifdef HAVE_AUTOAR + if (attachment->priv->save_extracted) { + GSettings *settings; + AutoarPref *arpref; + AutoarExtract *arextract; + + settings = g_settings_new (AUTOAR_PREF_DEFAULT_GSCHEMA_ID); + arpref = autoar_pref_new_with_gsettings (settings); + autoar_pref_set_delete_if_succeed (arpref, FALSE); + + arextract = autoar_extract_new_memory_file ( + buffer->data, buffer->len, + save_context->suggested_destname, + save_context->directory, arpref); + + g_signal_connect (arextract, "progress", + G_CALLBACK (attachment_save_extracted_progress_cb), + save_context); + g_signal_connect (arextract, "cancelled", + G_CALLBACK (attachment_save_extracted_cancelled_cb), + save_context); + g_signal_connect (arextract, "error", + G_CALLBACK (attachment_save_extracted_error_cb), + save_context); + g_signal_connect (arextract, "completed", + G_CALLBACK (attachment_save_extracted_completed_cb), + save_context); + + autoar_extract_start_async (arextract, cancellable); + + g_object_unref (settings); + g_object_unref (arpref); + + /* We do not g_object_unref (arextract); here because + * autoar_extract_run_start_async () do not increase the + * reference count of arextract. We unref the object in + * callbacks instead. */ + } +#endif g_clear_object (&mime_part); } @@ -2935,7 +3245,11 @@ attachment_save_create_cb (GFile *destination, return; save_context->destination = g_object_ref (destination); - attachment_save_got_output_stream (save_context); + + g_mutex_lock (&(save_context->prepared_tasks_mutex)); + if (++save_context->prepared_tasks >= save_context->total_tasks) + attachment_save_got_output_stream (save_context); + g_mutex_unlock (&(save_context->prepared_tasks_mutex)); } static void @@ -2954,7 +3268,11 @@ attachment_save_replace_cb (GFile *destination, return; save_context->destination = g_object_ref (destination); - attachment_save_got_output_stream (save_context); + + g_mutex_lock (&(save_context->prepared_tasks_mutex)); + if (++save_context->prepared_tasks >= save_context->total_tasks) + attachment_save_got_output_stream (save_context); + g_mutex_unlock (&(save_context->prepared_tasks_mutex)); } static void @@ -2987,26 +3305,74 @@ attachment_save_query_info_cb (GFile *destination, if (file_type == G_FILE_TYPE_DIRECTORY) { save_context->directory = g_object_ref (destination); - destination = attachment_save_new_candidate (save_context); - g_file_create_async ( - destination, G_FILE_CREATE_NONE, - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_save_create_cb, - save_context); + if (attachment->priv->save_self) { + destination = attachment_save_new_candidate (save_context); - g_object_unref (destination); + g_file_create_async ( + destination, G_FILE_CREATE_NONE, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_create_cb, + save_context); + g_object_unref (destination); + } + +#ifdef HAVE_AUTOAR + if (attachment->priv->save_extracted) { + EAttachment *attachment; + GFileInfo *info; + gchar *suggested; + + attachment = save_context->attachment; + suggested = NULL; + info = e_attachment_ref_file_info (attachment); + if (info != NULL) + suggested = g_strdup ( + g_file_info_get_display_name (info)); + if (suggested == NULL) + suggested = g_strdup (_("attachment.dat")); + + save_context->suggested_destname = suggested; + + g_mutex_lock (&(save_context->prepared_tasks_mutex)); + if (++save_context->prepared_tasks >= save_context->total_tasks) + attachment_save_got_output_stream (save_context); + g_mutex_unlock (&(save_context->prepared_tasks_mutex)); + } +#endif return; } replace: - g_file_replace_async ( - destination, NULL, FALSE, - G_FILE_CREATE_REPLACE_DESTINATION, - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_save_replace_cb, - save_context); + if (attachment->priv->save_self) { + g_file_replace_async ( + destination, NULL, FALSE, + G_FILE_CREATE_REPLACE_DESTINATION, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_replace_cb, + save_context); + } + +#ifdef HAVE_AUTOAR + if (attachment->priv->save_extracted) { + /* We can safely use save_context->directory here because + * attachment_save_replace_cb never calls + * attachment_save_new_candidate, the only function using + * the value of save_context->directory. */ + + save_context->suggested_destname = + g_file_get_basename (destination); + save_context->directory = g_file_get_parent (destination); + if (save_context->directory == NULL) + save_context->directory = g_object_ref (destination); + + g_mutex_lock (&(save_context->prepared_tasks_mutex)); + if (++save_context->prepared_tasks >= save_context->total_tasks) + attachment_save_got_output_stream (save_context); + g_mutex_unlock (&(save_context->prepared_tasks_mutex)); + } +#endif } void @@ -3049,6 +3415,17 @@ e_attachment_save_async (EAttachment *attachment, save_context = attachment_save_context_new ( attachment, callback, user_data); + /* No task is not allowed. */ + if (!attachment->priv->save_self && !attachment->priv->save_extracted) + attachment->priv->save_self = TRUE; + + if (attachment->priv->save_self) + save_context->total_tasks++; +#ifdef HAVE_AUTOAR + if (attachment->priv->save_extracted) + save_context->total_tasks++; +#endif + cancellable = attachment->priv->cancellable; g_cancellable_reset (cancellable); |