aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTing-Wei Lan <lantw@src.gnome.org>2014-09-03 15:10:11 +0800
committerMilan Crha <mcrha@redhat.com>2014-09-03 15:10:11 +0800
commit2d345f3d94a85360e92ef566257c1bc738b6cdc2 (patch)
tree686b5cdcb87a4651523b9784e97078a6db546de5
parent707ba2751903f08369d2c8fa7779140b49f6051b (diff)
downloadgsoc2013-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
-rw-r--r--configure.ac30
-rw-r--r--e-util/Makefile.am2
-rw-r--r--e-util/e-attachment-store.c207
-rw-r--r--e-util/e-attachment.c523
-rw-r--r--e-util/e-attachment.h6
5 files changed, 687 insertions, 81 deletions
diff --git a/configure.ac b/configure.ac
index 2a7e4bbd44..c4243dc93a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,6 +63,7 @@ m4_define([geoclue_minimum_version], [0.12.0])
m4_define([geocode_glib_minimum_version], [3.10])
m4_define([gladeui_minimum_version], [3.10.0])
m4_define([gweather_minimum_version], [3.8])
+m4_define([gnome_autoar_minimum_version], [0.1])
m4_define([libcanberra_gtk_minimum_version], [0.25])
m4_define([libnotify_minimum_version], [0.7])
@@ -340,6 +341,34 @@ fi
AC_SUBST(CANBERRA_CFLAGS)
AC_SUBST(CANBERRA_LIBS)
+dnl ***********************************
+dnl Archives Integration / gnome-autoar
+dnl ***********************************
+AC_ARG_ENABLE([autoar],
+ [AS_HELP_STRING([--enable-autoar],
+ [Enable archives support in attachments @<:@default=yes@:>@])],
+ [enable_autoar="$enableval"], [enable_autoar=yes])
+
+if test x"$enable_autoar" = xyes; then
+ PKG_CHECK_MODULES(
+ [AUTOAR],
+ [gnome-autoar >= gnome_autoar_minimum_version
+ gnome-autoar-gtk >= gnome_autoar_minimum_version],,
+ [AC_MSG_ERROR([
+
+ gnome-autoar or gnome-autoar-gtk not found
+ (or version < gnome_autoar_minimum_version)
+
+ If you want to disable support for automatic archives handling,
+ please append --disable-autoar to configure.
+
+ ])])
+
+ AC_DEFINE(HAVE_AUTOAR, 1, [Define if gnome-autoar is enabled])
+fi
+AC_SUBST(AUTOAR_CFLAGS)
+AC_SUBST(AUTOAR_LIBS)
+
dnl ******************
dnl User Documentation
dnl ******************
@@ -1612,6 +1641,7 @@ echo "
LDAP support: $msg_ldap
Contact Maps: $enable_contact_maps
Libcryptui: $enable_libcryptui
+ Archives support: $enable_autoar
Libnotify: $HAVE_LIBNOTIFY
SSL support: $msg_ssl
SMIME support: $msg_smime
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,