aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTing-Wei Lan <lantw44@gmail.com>2013-08-20 02:55:40 +0800
committerLAN-TW <lantw44@gmail.com>2013-08-20 02:56:31 +0800
commitc44b5c5cd564134755eba7904b2efb894c2ea513 (patch)
tree54501abe01ed65a111635b6cdceab129ea85fc0b
parent5486a2614516daec62327431c511099728d14b2b (diff)
downloadgsoc2013-evolution-c44b5c5cd564134755eba7904b2efb894c2ea513.tar
gsoc2013-evolution-c44b5c5cd564134755eba7904b2efb894c2ea513.tar.gz
gsoc2013-evolution-c44b5c5cd564134755eba7904b2efb894c2ea513.tar.bz2
gsoc2013-evolution-c44b5c5cd564134755eba7904b2efb894c2ea513.tar.lz
gsoc2013-evolution-c44b5c5cd564134755eba7904b2efb894c2ea513.tar.xz
gsoc2013-evolution-c44b5c5cd564134755eba7904b2efb894c2ea513.tar.zst
gsoc2013-evolution-c44b5c5cd564134755eba7904b2efb894c2ea513.zip
Add simple archive extraction support
-rw-r--r--e-util/e-attachment-store.c42
-rw-r--r--e-util/e-attachment.c276
2 files changed, 265 insertions, 53 deletions
diff --git a/e-util/e-attachment-store.c b/e-util/e-attachment-store.c
index 0f0ddf2138..a0794d9e04 100644
--- a/e-util/e-attachment-store.c
+++ b/e-util/e-attachment-store.c
@@ -633,7 +633,6 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (response == GTK_RESPONSE_OK) {
- GList *iter;
gboolean save_self, save_extracted;
destination = gtk_file_chooser_get_file (file_chooser);
@@ -641,9 +640,44 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
!gtk_toggle_button_get_active (extract_only_toggle);
save_extracted = gtk_toggle_button_get_active (extract_yes_toggle);
- for (iter = attachment_list; iter != NULL; iter = iter->next) {
- e_attachment_set_save_self (iter->data, save_self);
- e_attachment_set_save_extracted (iter->data, save_extracted);
+ 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);
}
} else {
destination = NULL;
diff --git a/e-util/e-attachment.c b/e-util/e-attachment.c
index b34cc0aa4a..0de66333dc 100644
--- a/e-util/e-attachment.c
+++ b/e-util/e-attachment.c
@@ -28,6 +28,7 @@
#include <errno.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
+#include <gnome-autoar/autoar.h>
#include <libedataserver/libedataserver.h>
@@ -2709,6 +2710,16 @@ struct _SaveContext {
gssize bytes_read;
gchar buffer[4096];
gint count;
+
+ GByteArray *input_buffer;
+ char *suggested_destname;
+
+ guint total_tasks : 2;
+ guint completed_tasks : 2;
+ guint prepared_tasks : 2;
+
+ GMutex completed_tasks_mutex;
+ GMutex prepared_tasks_mutex;
};
/* Forward Declaration */
@@ -2733,6 +2744,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;
@@ -2756,6 +2770,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);
}
@@ -2770,13 +2793,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)
{
@@ -2891,20 +2947,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;
}
@@ -2927,6 +2970,44 @@ attachment_save_read_cb (GInputStream *input_stream,
}
static void
+attachment_save_extracted_progress_cb (AutoarExtract *arextract,
+ gdouble fraction_size,
+ gdouble fraction_files,
+ SaveContext *save_context)
+{
+ attachment_progress_cb (
+ autoar_extract_get_completed_size (arextract),
+ autoar_extract_get_size (arextract),
+ 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, ""));
+ 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);
+}
+
+static void
attachment_save_got_output_stream (SaveContext *save_context)
{
GCancellable *cancellable;
@@ -2951,25 +3032,65 @@ 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);
+ }
+
+ 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. */
+ }
g_clear_object (&mime_part);
}
@@ -3009,7 +3130,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
@@ -3028,7 +3153,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
@@ -3061,26 +3190,70 @@ 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);
+ }
+
+ if (attachment->priv->save_extracted) {
+ EAttachment *attachment;
+ GFileInfo *info;
+ char *suggested;
+
+ attachment = save_context->attachment;
+ 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));
+ }
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);
+ }
+
+ 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));
+ }
}
void
@@ -3123,6 +3296,11 @@ e_attachment_save_async (EAttachment *attachment,
save_context = attachment_save_context_new (
attachment, callback, user_data);
+ if (attachment->priv->save_self)
+ save_context->total_tasks++;
+ if (attachment->priv->save_extracted)
+ save_context->total_tasks++;
+
cancellable = attachment->priv->cancellable;
g_cancellable_reset (cancellable);