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 | |
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')
-rw-r--r-- | e-util/Makefile.am | 2 | ||||
-rw-r--r-- | e-util/e-attachment-store.c | 207 | ||||
-rw-r--r-- | e-util/e-attachment.c | 523 | ||||
-rw-r--r-- | e-util/e-attachment.h | 6 |
4 files changed, 657 insertions, 81 deletions
diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 8e91dc8068..61ee3f8b5e 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -104,6 +104,7 @@ libevolution_util_la_CPPFLAGS = \ $(ENCHANT_CFLAGS) \ $(GTKSPELL_CFLAGS) \ $(CODE_COVERAGE_CFLAGS) \ + $(AUTOAR_CFLAGS) \ $(NULL) evolution_util_include_HEADERS = \ @@ -649,6 +650,7 @@ libevolution_util_la_LIBADD = \ $(GEO_LIBS) \ $(ENCHANT_LIBS) \ $(GTKSPELL_LIBS) \ + $(AUTOAR_LIBS) \ $(INTLLIBS) \ $(MATH_LIB) \ $(NULL) diff --git a/e-util/e-attachment-store.c b/e-util/e-attachment-store.c index e867327e47..10970bb8cc 100644 --- a/e-util/e-attachment-store.c +++ b/e-util/e-attachment-store.c @@ -28,6 +28,11 @@ #include <errno.h> #include <glib/gi18n.h> +#ifdef HAVE_AUTOAR +#include <gnome-autoar/autoar.h> +#include <gnome-autoar/autoar-gtk.h> +#endif + #include "e-mktemp.h" #define E_ATTACHMENT_STORE_GET_PRIVATE(obj) \ @@ -448,26 +453,56 @@ e_attachment_store_run_load_dialog (EAttachmentStore *store, { GtkFileChooser *file_chooser; GtkWidget *dialog; - GtkWidget *option; + + GtkBox *extra_box; + GtkWidget *extra_box_widget; + GtkWidget *option_display; + +#ifdef HAVE_AUTOAR + GtkBox *option_format_box; + GtkWidget *option_format_box_widget; + GtkWidget *option_format_label; + GtkWidget *option_format_combo; +#endif + GtkImage *preview; + GSList *files, *iter; const gchar *disposition; gboolean active; gint response; +#ifdef HAVE_AUTOAR + GSettings *settings; + AutoarPref *arpref; + gint format, filter; +#endif + g_return_if_fail (E_IS_ATTACHMENT_STORE (store)); g_return_if_fail (GTK_IS_WINDOW (parent)); dialog = gtk_file_chooser_dialog_new ( _("Add Attachment"), parent, GTK_FILE_CHOOSER_ACTION_OPEN, +#ifdef HAVE_AUTOAR + _("_Open"), GTK_RESPONSE_OK, +#endif _("_Cancel"), GTK_RESPONSE_CANCEL, - _("A_ttach"), GTK_RESPONSE_OK, NULL); +#ifdef HAVE_AUTOAR + _("A_ttach"), GTK_RESPONSE_CLOSE, +#else + _("A_ttach"), GTK_RESPONSE_OK, +#endif + NULL); file_chooser = GTK_FILE_CHOOSER (dialog); gtk_file_chooser_set_local_only (file_chooser, FALSE); gtk_file_chooser_set_select_multiple (file_chooser, TRUE); +#ifdef HAVE_AUTOAR + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); +#else gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +#endif gtk_window_set_icon_name (GTK_WINDOW (dialog), "mail-attachment"); preview = GTK_IMAGE (gtk_image_new ()); @@ -478,20 +513,52 @@ e_attachment_store_run_load_dialog (EAttachmentStore *store, file_chooser, "update-preview", G_CALLBACK (update_preview_cb), preview); - option = gtk_check_button_new_with_mnemonic ( + extra_box_widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + extra_box = GTK_BOX (extra_box_widget); + + option_display = gtk_check_button_new_with_mnemonic ( _("_Suggest automatic display of attachment")); - gtk_file_chooser_set_extra_widget (file_chooser, option); - gtk_widget_show (option); + gtk_box_pack_start (extra_box, option_display, FALSE, FALSE, 0); + +#ifdef HAVE_AUTOAR + option_format_box_widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + option_format_box = GTK_BOX (option_format_box_widget); + gtk_box_pack_start (extra_box, option_format_box_widget, FALSE, FALSE, 0); + + settings = g_settings_new (AUTOAR_PREF_DEFAULT_GSCHEMA_ID); + arpref = autoar_pref_new_with_gsettings (settings); + + option_format_label = gtk_label_new ( + _("Archive selected directories using this format:")); + option_format_combo = autoar_gtk_chooser_simple_new ( + autoar_pref_get_default_format (arpref), + autoar_pref_get_default_filter (arpref)); + gtk_box_pack_start (option_format_box, option_format_label, FALSE, FALSE, 0); + gtk_box_pack_start (option_format_box, option_format_combo, FALSE, FALSE, 0); +#endif + + gtk_file_chooser_set_extra_widget (file_chooser, extra_box_widget); + gtk_widget_show_all (extra_box_widget); response = gtk_dialog_run (GTK_DIALOG (dialog)); +#ifdef HAVE_AUTOAR + if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_CLOSE) +#else if (response != GTK_RESPONSE_OK) +#endif goto exit; files = gtk_file_chooser_get_files (file_chooser); - active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option)); + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option_display)); disposition = active ? "inline" : "attachment"; +#ifdef HAVE_AUTOAR + autoar_gtk_chooser_simple_get (option_format_combo, &format, &filter); + autoar_pref_set_default_format (arpref, format); + autoar_pref_set_default_filter (arpref, filter); +#endif + for (iter = files; iter != NULL; iter = g_slist_next (iter)) { EAttachment *attachment; GFile *file = iter->data; @@ -500,6 +567,12 @@ e_attachment_store_run_load_dialog (EAttachmentStore *store, e_attachment_set_file (attachment, file); e_attachment_set_disposition (attachment, disposition); e_attachment_store_add_attachment (store, attachment); + +#ifdef HAVE_AUTOAR + g_object_set_data_full (G_OBJECT (attachment), + "autoar-pref", g_object_ref (arpref), g_object_unref); +#endif + e_attachment_load_async ( attachment, (GAsyncReadyCallback) e_attachment_load_handle_error, parent); @@ -511,6 +584,10 @@ e_attachment_store_run_load_dialog (EAttachmentStore *store, exit: gtk_widget_destroy (dialog); +#ifdef HAVE_AUTOAR + g_object_unref (settings); + g_object_unref (arpref); +#endif } GFile * @@ -521,6 +598,18 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store, GtkFileChooser *file_chooser; GtkFileChooserAction action; GtkWidget *dialog; + +#ifdef HAVE_AUTOAR + GtkBox *extra_box; + GtkWidget *extra_box_widget; + + GtkBox *extract_box; + GtkWidget *extract_box_widget; + + GSList *extract_group; + GtkWidget *extract_dont, *extract_only, *extract_org; +#endif + GFile *destination; const gchar *title; gint response; @@ -551,11 +640,45 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store, gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); gtk_window_set_icon_name (GTK_WINDOW (dialog), "mail-attachment"); +#ifdef HAVE_AUTOAR + extra_box_widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + extra_box = GTK_BOX (extra_box_widget); + + extract_box_widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + extract_box = GTK_BOX (extract_box_widget); + gtk_box_pack_start (extra_box, extract_box_widget, FALSE, FALSE, 5); + + extract_dont = gtk_radio_button_new_with_mnemonic (NULL, + _("Do _not extract files from the attachment")); + gtk_box_pack_start (extract_box, extract_dont, FALSE, FALSE, 0); + + extract_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (extract_dont)); + extract_only = gtk_radio_button_new_with_mnemonic (extract_group, + _("Save extracted files _only")); + gtk_box_pack_start (extract_box, extract_only, FALSE, FALSE, 0); + + extract_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (extract_only)); + extract_org = gtk_radio_button_new_with_mnemonic (extract_group, + _("Save extracted files and the original _archive")); + gtk_box_pack_start (extract_box, extract_org, FALSE, FALSE, 0); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (extract_dont), TRUE); + + gtk_widget_show_all (extra_box_widget); + gtk_file_chooser_set_extra_widget (file_chooser, extra_box_widget); +#endif + if (action == GTK_FILE_CHOOSER_ACTION_SAVE) { EAttachment *attachment; GFileInfo *file_info; const gchar *name = NULL; +#ifdef HAVE_AUTOAR + AutoarPref *arpref; + GSettings *settings; + gchar *mime_type; +#endif + attachment = attachment_list->data; file_info = e_attachment_ref_file_info (attachment); @@ -568,15 +691,83 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store, gtk_file_chooser_set_current_name (file_chooser, name); +#ifdef HAVE_AUTOAR + mime_type = e_attachment_dup_mime_type (attachment); + settings = g_settings_new (AUTOAR_PREF_DEFAULT_GSCHEMA_ID); + arpref = autoar_pref_new_with_gsettings (settings); + if (!autoar_pref_check_file_name (arpref, name) && + !autoar_pref_check_mime_type_d (arpref, mime_type)) { + gtk_widget_hide (extra_box_widget); + } + + g_clear_object (&settings); + g_clear_object (&arpref); + g_free (mime_type); +#endif + g_clear_object (&file_info); } response = gtk_dialog_run (GTK_DIALOG (dialog)); - if (response == GTK_RESPONSE_OK) + if (response == GTK_RESPONSE_OK) { +#ifdef HAVE_AUTOAR + gboolean save_self, save_extracted; +#endif + destination = gtk_file_chooser_get_file (file_chooser); - else + +#ifdef HAVE_AUTOAR + save_self = + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (extract_dont)) || + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (extract_org)); + save_extracted = + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (extract_only)) || + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (extract_org)); + + if (action == GTK_FILE_CHOOSER_ACTION_SAVE) { + e_attachment_set_save_self (attachment_list->data, save_self); + e_attachment_set_save_extracted (attachment_list->data, save_extracted); + } else { + AutoarPref *arpref; + GSettings *settings; + GList *iter; + + settings = g_settings_new (AUTOAR_PREF_DEFAULT_GSCHEMA_ID); + arpref = autoar_pref_new_with_gsettings (settings); + + for (iter = attachment_list; iter != NULL; iter = iter->next) { + EAttachment *attachment; + GFileInfo *file_info; + const gchar *name; + gchar *mime_type; + + attachment = iter->data; + file_info = e_attachment_ref_file_info (attachment); + name = g_file_info_get_display_name (file_info); + mime_type = e_attachment_dup_mime_type (attachment); + + if ((name != NULL && + autoar_pref_check_file_name (arpref, name)) || + autoar_pref_check_mime_type_d (arpref, mime_type)) { + e_attachment_set_save_self (attachment, save_self); + e_attachment_set_save_extracted (attachment, save_extracted); + } else { + e_attachment_set_save_self (attachment, TRUE); + e_attachment_set_save_extracted (attachment, FALSE); + } + + g_object_unref (file_info); + g_free (mime_type); + } + + g_object_unref (settings); + g_object_unref (arpref); + } +#endif + } else { destination = NULL; + } gtk_widget_destroy (dialog); 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); diff --git a/e-util/e-attachment.h b/e-util/e-attachment.h index cfacbf335b..9fc4ea04b4 100644 --- a/e-util/e-attachment.h +++ b/e-util/e-attachment.h @@ -99,6 +99,12 @@ gboolean e_attachment_get_saving (EAttachment *attachment); gboolean e_attachment_get_shown (EAttachment *attachment); void e_attachment_set_shown (EAttachment *attachment, gboolean shown); +gboolean e_attachment_get_save_self (EAttachment *attachment); +void e_attachment_set_save_self (EAttachment *attachment, + gboolean save_self); +gboolean e_attachment_get_save_extracted (EAttachment *attachment); +void e_attachment_set_save_extracted (EAttachment *attachment, + gboolean save_extracted); camel_cipher_validity_encrypt_t e_attachment_get_encrypted (EAttachment *attachment); void e_attachment_set_encrypted (EAttachment *attachment, |