[evolution] Fix archives support in attachments



commit b5681c51321045e0a509e5b656301e1032d8c4aa
Author: Razvan Chitu <razvan ch95 gmail com>
Date:   Fri Aug 26 14:55:12 2016 +0300

    Fix archives support in attachments
    
    The API of gnome-autoar was recently modified so compression and extraction
    were no longer working. Replace autoar preferences objects with two shell
    settings. Save memory file to disk before extracting it. Handle generation of
    unique file names internally.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=770380

 configure.ac                                  |    4 +-
 data/org.gnome.evolution.shell.gschema.xml.in |   10 +
 e-util/e-attachment-store.c                   |   78 ++++----
 e-util/e-attachment.c                         |  280 ++++++++++++++++++-------
 4 files changed, 254 insertions(+), 118 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index a1ba2c0..a841591 100644
--- a/configure.ac
+++ b/configure.ac
@@ -368,8 +368,8 @@ AC_ARG_ENABLE([autoar],
 if test x"$enable_autoar" = xyes; then
        PKG_CHECK_MODULES(
                [AUTOAR],
-               [gnome-autoar >= gnome_autoar_minimum_version
-                gnome-autoar-gtk >= gnome_autoar_minimum_version],,
+               [gnome-autoar-0 >= gnome_autoar_minimum_version
+                gnome-autoar-gtk-0 >= gnome_autoar_minimum_version],,
                [AC_MSG_ERROR([
 
        gnome-autoar or gnome-autoar-gtk not found
diff --git a/data/org.gnome.evolution.shell.gschema.xml.in b/data/org.gnome.evolution.shell.gschema.xml.in
index 18ece74..02a5a18 100644
--- a/data/org.gnome.evolution.shell.gschema.xml.in
+++ b/data/org.gnome.evolution.shell.gschema.xml.in
@@ -15,6 +15,16 @@
       <_summary>Initial file chooser folder</_summary>
       <_description>Initial folder for GtkFileChooser dialogs.</_description>
     </key>
+    <key name="autoar-format" type="s">
+      <default>''</default>
+      <_summary>Compression format used by autoar</_summary>
+      <_description>Compression format used when compressing attached directories with autoar.</_description>
+    </key>
+    <key name="autoar-filter" type="s">
+      <default>''</default>
+      <_summary>Compression filter used by autoar</_summary>
+      <_description>Compression filter used when compressing attached directories with autoar.</_description>
+    </key>
     <key name="start-offline" type="b">
       <default>false</default>
       <_summary>Start in offline mode</_summary>
diff --git a/e-util/e-attachment-store.c b/e-util/e-attachment-store.c
index 85fa19a..05e4809 100644
--- a/e-util/e-attachment-store.c
+++ b/e-util/e-attachment-store.c
@@ -29,7 +29,7 @@
 #include <glib/gi18n.h>
 
 #ifdef HAVE_AUTOAR
-#include <gnome-autoar/autoar.h>
+#include <gnome-autoar/gnome-autoar.h>
 #include <gnome-autoar/autoar-gtk.h>
 #endif
 
@@ -648,8 +648,10 @@ e_attachment_store_run_load_dialog (EAttachmentStore *store,
 
 #ifdef HAVE_AUTOAR
        GSettings *settings;
-       AutoarPref *arpref;
-       gint format, filter;
+       char *format_string;
+       char *filter_string;
+       gint format;
+       gint filter;
 #endif
 
        g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
@@ -699,14 +701,23 @@ e_attachment_store_run_load_dialog (EAttachmentStore *store,
        option_format_box = GTK_BOX (option_format_box_widget);
        gtk_box_pack_start (extra_box, option_format_box_widget, FALSE, FALSE, 0);
 
-       settings = e_util_ref_settings (AUTOAR_PREF_DEFAULT_GSCHEMA_ID);
-       arpref = autoar_pref_new_with_gsettings (settings);
+       settings = e_util_ref_settings ("org.gnome.evolution.shell");
+
+       format_string = g_settings_get_string (settings, "autoar-format");
+       filter_string = g_settings_get_string (settings, "autoar-filter");
+
+       if (!e_enum_from_string (AUTOAR_TYPE_FORMAT, format_string, &format)) {
+               format = AUTOAR_FORMAT_ZIP;
+       }
+       if (!e_enum_from_string (AUTOAR_TYPE_FILTER, filter_string, &filter)) {
+               filter = AUTOAR_FILTER_NONE;
+       }
 
        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));
+               format,
+               filter);
        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
@@ -729,8 +740,23 @@ e_attachment_store_run_load_dialog (EAttachmentStore *store,
 
 #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);
+
+       if (!e_enum_to_string (AUTOAR_TYPE_FORMAT, format)) {
+               format = AUTOAR_FORMAT_ZIP;
+       }
+
+       if (!e_enum_to_string (AUTOAR_TYPE_FORMAT, filter)) {
+               filter = AUTOAR_FILTER_NONE;
+       }
+
+       g_settings_set_string (
+               settings,
+               "autoar-format",
+               e_enum_to_string (AUTOAR_TYPE_FORMAT, format));
+       g_settings_set_string (
+               settings,
+               "autoar-filter",
+               e_enum_to_string (AUTOAR_TYPE_FILTER, filter));
 #endif
 
        for (iter = files; iter != NULL; iter = g_slist_next (iter)) {
@@ -742,11 +768,6 @@ e_attachment_store_run_load_dialog (EAttachmentStore *store,
                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);
@@ -760,7 +781,8 @@ exit:
        gtk_widget_destroy (dialog);
 #ifdef HAVE_AUTOAR
        g_object_unref (settings);
-       g_object_unref (arpref);
+       g_free (format_string);
+       g_free (filter_string);
 #endif
 }
 
@@ -848,8 +870,6 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
                const gchar *name = NULL;
 
 #ifdef HAVE_AUTOAR
-               AutoarPref *arpref;
-               GSettings *settings;
                gchar *mime_type;
 #endif
 
@@ -867,15 +887,10 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
 
 #ifdef HAVE_AUTOAR
                mime_type = e_attachment_dup_mime_type (attachment);
-               settings = e_util_ref_settings (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)) {
+               if (!autoar_check_mime_type_supported (mime_type)) {
                        gtk_widget_hide (extra_box_widget);
                }
 
-               g_clear_object (&settings);
-               g_clear_object (&arpref);
                g_free (mime_type);
 #endif
 
@@ -903,27 +918,16 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
                        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 = e_util_ref_settings (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)) {
+                               if (autoar_check_mime_type_supported (mime_type)) {
                                        e_attachment_set_save_self (attachment, save_self);
                                        e_attachment_set_save_extracted (attachment, save_extracted);
                                } else {
@@ -931,12 +935,8 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
                                        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 {
diff --git a/e-util/e-attachment.c b/e-util/e-attachment.c
index d451f18..21dec66 100644
--- a/e-util/e-attachment.c
+++ b/e-util/e-attachment.c
@@ -29,8 +29,7 @@
 #include <glib/gstdio.h>
 
 #ifdef HAVE_AUTOAR
-#include <gnome-autoar/autoar.h>
-#include <gnome-autoar/autoar-gtk.h>
+#include <gnome-autoar/gnome-autoar.h>
 #endif
 
 #include <libedataserver/libedataserver.h>
@@ -2027,7 +2026,7 @@ attachment_load_file_read_cb (GFile *file,
 
 #ifdef HAVE_AUTOAR
 static void
-attachment_load_created_decide_dest_cb (AutoarCreate *arcreate,
+attachment_load_created_decide_dest_cb (AutoarCompressor *compressor,
                                         GFile *destination,
                                         EAttachment *attachment)
 {
@@ -2035,23 +2034,23 @@ attachment_load_created_decide_dest_cb (AutoarCreate *arcreate,
 }
 
 static void
-attachment_load_created_cancelled_cb (AutoarCreate *arcreate,
+attachment_load_created_cancelled_cb (AutoarCompressor *compressor,
                                       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);
+       g_object_unref (compressor);
 }
 
 static void
-attachment_load_created_completed_cb (AutoarCreate *arcreate,
+attachment_load_created_completed_cb (AutoarCompressor *compressor,
                                       LoadContext *load_context)
 {
        EAttachment *attachment;
        GFile *file;
 
-       g_object_unref (arcreate);
+       g_object_unref (compressor);
 
        /* We have set the file to the created temporary archive, so we can
         * query info again and use the regular procedure to load the
@@ -2068,12 +2067,12 @@ attachment_load_created_completed_cb (AutoarCreate *arcreate,
 }
 
 static void
-attachment_load_created_error_cb (AutoarCreate *arcreate,
+attachment_load_created_error_cb (AutoarCompressor *compressor,
                                   GError *error,
                                   LoadContext *load_context)
 {
        attachment_load_check_for_error (load_context, g_error_copy (error));
-       g_object_unref (arcreate);
+       g_object_unref (compressor);
 }
 #endif
 
@@ -2101,25 +2100,49 @@ attachment_load_query_info_cb (GFile *file,
 
 #ifdef HAVE_AUTOAR
        if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) {
-               AutoarCreate *arcreate;
-               AutoarPref *arpref; /* Do not unref */
+               AutoarCompressor *compressor;
                GFile *temporary;
+               GSettings *settings;
+               GList *files = NULL;
+               char *format_string;
+               char *filter_string;
+               gint format;
+               gint filter;
 
-               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",
+
+               settings = e_util_ref_settings ("org.gnome.evolution.shell");
+
+               format_string = g_settings_get_string (settings, "autoar-format");
+               filter_string = g_settings_get_string (settings, "autoar-filter");
+
+               if (!e_enum_from_string (AUTOAR_TYPE_FORMAT, format_string, &format)) {
+                       format = AUTOAR_FORMAT_ZIP;
+               }
+               if (!e_enum_from_string (AUTOAR_TYPE_FILTER, filter_string, &filter)) {
+                       filter = AUTOAR_FILTER_NONE;
+               }
+
+               files = g_list_prepend (files, file);
+
+               compressor = autoar_compressor_new (
+                       files, temporary, format, filter, FALSE);
+               g_signal_connect (compressor, "decide-dest",
                        G_CALLBACK (attachment_load_created_decide_dest_cb), attachment);
-               g_signal_connect (arcreate, "cancelled",
+               g_signal_connect (compressor, "cancelled",
                        G_CALLBACK (attachment_load_created_cancelled_cb), load_context);
-               g_signal_connect (arcreate, "completed",
+               g_signal_connect (compressor, "completed",
                        G_CALLBACK (attachment_load_created_completed_cb), load_context);
-               g_signal_connect (arcreate, "error",
+               g_signal_connect (compressor, "error",
                        G_CALLBACK (attachment_load_created_error_cb), load_context);
-               autoar_create_start_async (arcreate, cancellable);
+               autoar_compressor_start_async (compressor, cancellable);
 
+               g_object_unref (settings);
+               g_free (format_string);
+               g_free (filter_string);
+               g_list_free (files);
                g_object_unref (temporary);
        } else {
 #endif
@@ -2752,6 +2775,7 @@ struct _SaveContext {
 
        GByteArray *input_buffer;
        gchar *suggested_destname;
+       GFile *temporary_file;
 
        guint total_tasks : 2;
        guint completed_tasks : 2;
@@ -2815,6 +2839,9 @@ attachment_save_context_free (SaveContext *save_context)
        if (save_context->suggested_destname != NULL)
                g_free (save_context->suggested_destname);
 
+       if (save_context->temporary_file != NULL)
+               g_clear_object (&save_context->temporary_file);
+
        g_mutex_clear (&(save_context->completed_tasks_mutex));
        g_mutex_clear (&(save_context->prepared_tasks_mutex));
 
@@ -2872,6 +2899,33 @@ attachment_save_complete (SaveContext *save_context) {
        }
 }
 
+static gchar *
+get_new_name_with_count (const gchar *initial_name,
+                         gint count)
+{
+       GString *string;
+       const gchar *ext;
+       gsize length;
+
+       if (count == 0) {
+               return g_strdup (initial_name);
+       }
+
+       string = g_string_sized_new (strlen (initial_name));
+       ext = g_utf8_strchr (initial_name, -1, '.');
+
+       if (ext != NULL)
+               length = ext - initial_name;
+       else
+               length = strlen (initial_name);
+
+       g_string_append_len (string, initial_name, length);
+       g_string_append_printf (string, " (%d)", count);
+       g_string_append (string, (ext != NULL) ? ext : "");
+
+       return g_string_free (string, FALSE);
+}
+
 static GFile *
 attachment_save_new_candidate (SaveContext *save_context)
 {
@@ -2890,27 +2944,7 @@ attachment_save_new_candidate (SaveContext *save_context)
                /* Translators: Default attachment filename. */
                display_name = _("attachment.dat");
 
-       if (save_context->count == 0)
-               basename = g_strdup (display_name);
-       else {
-               GString *string;
-               const gchar *ext;
-               gsize length;
-
-               string = g_string_sized_new (strlen (display_name));
-               ext = g_utf8_strchr (display_name, -1, '.');
-
-               if (ext != NULL)
-                       length = ext - display_name;
-               else
-                       length = strlen (display_name);
-
-               g_string_append_len (string, display_name, length);
-               g_string_append_printf (string, " (%d)", save_context->count);
-               g_string_append (string, (ext != NULL) ? ext : "");
-
-               basename = g_string_free (string, FALSE);
-       }
+       basename = get_new_name_with_count (display_name, save_context->count);
 
        save_context->count++;
 
@@ -3009,43 +3043,151 @@ attachment_save_read_cb (GInputStream *input_stream,
 }
 
 #ifdef HAVE_AUTOAR
+static GFile*
+attachment_save_extracted_decide_destination_cb (AutoarExtractor *extractor,
+                                                 GFile *destination,
+                                                 GList *files,
+                                                 SaveContext *save_context)
+{
+       gchar *basename;
+       GFile *destination_directory;
+       GFile *new_destination;
+       gint count = 0;
+
+       basename = g_file_get_basename (destination);
+       destination_directory = g_file_get_parent (destination);
+
+       new_destination = g_object_ref (destination);
+
+       while (g_file_query_exists (new_destination, NULL)) {
+               gchar *new_basename;
+
+               new_basename = get_new_name_with_count (basename, ++count);
+
+               g_object_unref (new_destination);
+
+               new_destination = g_file_get_child (
+                       destination_directory, new_basename);
+
+               g_free (new_basename);
+       }
+
+       g_object_unref (destination_directory);
+       g_free (basename);
+
+       return new_destination;
+}
+
 static void
-attachment_save_extracted_progress_cb (AutoarExtract *arextract,
+attachment_save_extracted_progress_cb (AutoarExtractor *extractor,
                                        guint64 completed_size,
                                        guint completed_files,
                                        SaveContext *save_context)
 {
        attachment_progress_cb (
-               autoar_extract_get_size (arextract),
+               autoar_extractor_get_total_size (extractor),
                completed_size, save_context->attachment);
 }
 
 static void
-attachment_save_extracted_cancelled_cb (AutoarExtract *arextract,
+attachment_save_extracted_cancelled_cb (AutoarExtractor *extractor,
                                         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);
+       g_object_unref (extractor);
 }
 
 static void
-attachment_save_extracted_completed_cb (AutoarExtract *arextract,
+attachment_save_extracted_completed_cb (AutoarExtractor *extractor,
                                         SaveContext *save_context)
 {
        attachment_save_complete (save_context);
-       g_object_unref (arextract);
+       g_object_unref (extractor);
 }
 
 static void
-attachment_save_extracted_error_cb (AutoarExtract *arextract,
+attachment_save_extracted_error_cb (AutoarExtractor *extractor,
                                     GError *error,
                                     SaveContext *save_context)
 {
        attachment_save_check_for_error (save_context, g_error_copy (error));
-       g_object_unref (arextract);
+       g_object_unref (extractor);
 }
+
+static void
+attachament_save_write_archive_cb (GOutputStream *output_stream,
+                                   GAsyncResult *result,
+                                   SaveContext *save_context)
+{
+       AutoarExtractor *extractor;
+       GError *error = NULL;
+       gsize bytes_written;
+
+       g_output_stream_write_all_finish (
+               output_stream, result, &bytes_written, &error);
+
+       g_object_unref (output_stream);
+
+       if (attachment_save_check_for_error (save_context, error)) {
+               return;
+       }
+
+       extractor = autoar_extractor_new (
+               save_context->temporary_file, save_context->directory);
+
+       autoar_extractor_set_delete_after_extraction (extractor, TRUE);
+
+       g_signal_connect (extractor, "decide-destination",
+               G_CALLBACK (attachment_save_extracted_decide_destination_cb),
+               save_context);
+       g_signal_connect (extractor, "progress",
+               G_CALLBACK (attachment_save_extracted_progress_cb),
+               save_context);
+       g_signal_connect (extractor, "cancelled",
+               G_CALLBACK (attachment_save_extracted_cancelled_cb),
+               save_context);
+       g_signal_connect (extractor, "error",
+               G_CALLBACK (attachment_save_extracted_error_cb),
+               save_context);
+       g_signal_connect (extractor, "completed",
+               G_CALLBACK (attachment_save_extracted_completed_cb),
+               save_context);
+
+       autoar_extractor_start_async (
+               extractor, save_context->attachment->priv->cancellable);
+
+       /* We do not g_object_unref (extractor); here because
+        * autoar_extractor_run_start_async () does not increase the
+        * reference count of extractor. We unref the object in
+        * callbacks instead. */
+}
+
+static void
+attachment_save_create_archive_cb (GFile *file,
+                                   GAsyncResult *result,
+                                   SaveContext *save_context)
+{
+       GFileOutputStream *output_stream;
+       GError *error = NULL;
+
+       output_stream = g_file_create_finish (file, result, &error);
+
+       if (attachment_save_check_for_error (save_context, error)) {
+               return;
+       }
+
+       g_output_stream_write_all_async (
+               G_OUTPUT_STREAM (output_stream),
+               save_context->input_buffer->data,
+               save_context->input_buffer->len,
+               G_PRIORITY_DEFAULT,
+               save_context->attachment->priv->cancellable,
+               (GAsyncReadyCallback) attachament_save_write_archive_cb,
+               save_context);
+}
+
 #endif
 
 static void
@@ -3097,41 +3239,25 @@ attachment_save_got_output_stream (SaveContext *save_context)
 
 #ifdef HAVE_AUTOAR
        if (attachment->priv->save_extracted) {
-               GSettings *settings;
-               AutoarPref *arpref;
-               AutoarExtract *arextract;
+               GFile *temporary_directory;
+               GError *error = NULL;
 
-               settings = e_util_ref_settings (AUTOAR_PREF_DEFAULT_GSCHEMA_ID);
-               arpref = autoar_pref_new_with_gsettings (settings);
-               autoar_pref_set_delete_if_succeed (arpref, FALSE);
+               temporary_directory = attachment_get_temporary (&error);
+               if (attachment_save_check_for_error (save_context, error))
+                       return;
 
-               arextract = autoar_extract_new_memory_file (
-                       buffer->data, buffer->len,
-                       save_context->suggested_destname,
-                       save_context->directory, arpref);
+               save_context->temporary_file = g_file_get_child (
+                       temporary_directory, save_context->suggested_destname);
 
-               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),
+               g_file_create_async (
+                       save_context->temporary_file,
+                       G_FILE_CREATE_NONE,
+                       G_PRIORITY_DEFAULT,
+                       cancellable,
+                       (GAsyncReadyCallback) attachment_save_create_archive_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. */
+               g_object_unref (temporary_directory);
        }
 #endif
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]