From d09d8de870b6697c8a8b262e7e077b871a69b315 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Mon, 10 Dec 2012 08:09:59 -0500 Subject: Consolidate base utility libraries into libeutil. Evolution consists of entirely too many small utility libraries, which increases linking and loading time, places a burden on higher layers of the application (e.g. modules) which has to remember to link to all the small in-tree utility libraries, and makes it difficult to generate API documentation for these utility libraries in one Gtk-Doc module. Merge the following utility libraries under the umbrella of libeutil, and enforce a single-include policy on libeutil so we can reorganize the files as desired without disrupting its pseudo-public API. libemail-utils/libemail-utils.la libevolution-utils/libevolution-utils.la filter/libfilter.la widgets/e-timezone-dialog/libetimezonedialog.la widgets/menus/libmenus.la widgets/misc/libemiscwidgets.la widgets/table/libetable.la widgets/text/libetext.la This also merges libedataserverui from the Evolution-Data-Server module, since Evolution is its only consumer nowadays, and I'd like to make some improvements to those APIs without concern for backward-compatibility. And finally, start a Gtk-Doc module for libeutil. It's going to be a project just getting all the symbols _listed_ much less _documented_. But the skeletal structure is in place and I'm off to a good start. --- widgets/misc/e-attachment.c | 2883 ------------------------------------------- 1 file changed, 2883 deletions(-) delete mode 100644 widgets/misc/e-attachment.c (limited to 'widgets/misc/e-attachment.c') diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c deleted file mode 100644 index 4ebaef3747..0000000000 --- a/widgets/misc/e-attachment.c +++ /dev/null @@ -1,2883 +0,0 @@ -/* - * e-attachment.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "e-attachment.h" - -#include -#include -#include - -#include - -#include "e-util/e-icon-factory.h" -#include "e-util/e-util.h" -#include "e-util/e-mktemp.h" -#include "e-attachment-store.h" - -#define E_ATTACHMENT_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate)) - -/* Fallback Icon */ -#define DEFAULT_ICON_NAME "mail-attachment" - -/* Emblems */ -#define EMBLEM_CANCELLED "gtk-cancel" -#define EMBLEM_LOADING "emblem-downloads" -#define EMBLEM_SAVING "document-save" -#define EMBLEM_ENCRYPT_WEAK "security-low" -#define EMBLEM_ENCRYPT_STRONG "security-high" -#define EMBLEM_ENCRYPT_UNKNOWN "security-medium" -#define EMBLEM_SIGN_BAD "stock_signature-bad" -#define EMBLEM_SIGN_GOOD "stock_signature-ok" -#define EMBLEM_SIGN_UNKNOWN "stock_signature" - -/* Attributes needed for EAttachmentStore columns. */ -#define ATTACHMENT_QUERY "standard::*,preview::*,thumbnail::*" - -struct _EAttachmentPrivate { - GFile *file; - GIcon *icon; - GFileInfo *file_info; - GCancellable *cancellable; - CamelMimePart *mime_part; - guint emblem_timeout_id; - gchar *disposition; - gint percent; - gint64 last_percent_notify; /* to avoid excessive notifications */ - - guint can_show : 1; - guint loading : 1; - guint saving : 1; - guint shown : 1; - - camel_cipher_validity_encrypt_t encrypted; - camel_cipher_validity_sign_t signed_; - - /* This is a reference to our row in an EAttachmentStore, - * serving as a means of broadcasting "row-changed" signals. - * If we are removed from the store, we lazily free the - * reference when it is found to be to be invalid. */ - GtkTreeRowReference *reference; -}; - -enum { - PROP_0, - PROP_CAN_SHOW, - PROP_DISPOSITION, - PROP_ENCRYPTED, - PROP_FILE, - PROP_FILE_INFO, - PROP_ICON, - PROP_LOADING, - PROP_MIME_PART, - PROP_PERCENT, - PROP_REFERENCE, - PROP_SAVING, - PROP_SHOWN, - PROP_SIGNED -}; - -G_DEFINE_TYPE ( - EAttachment, - e_attachment, - G_TYPE_OBJECT) - -static gboolean -create_system_thumbnail (EAttachment *attachment, - GIcon **icon) -{ - GFile *file; - GFile *icon_file; - gchar *thumbnail = NULL; - - g_return_val_if_fail (attachment != NULL, FALSE); - g_return_val_if_fail (icon != NULL, FALSE); - - file = e_attachment_get_file (attachment); - - if (file && g_file_has_uri_scheme (file, "file")) { - gchar *path = g_file_get_path (file); - if (path) { - thumbnail = e_icon_factory_create_thumbnail (path); - g_free (path); - } - } - - if (thumbnail == NULL) - return FALSE; - - icon_file = g_file_new_for_path (thumbnail); - - if (*icon) - g_object_unref (*icon); - - *icon = g_file_icon_new (icon_file); - - g_object_unref (icon_file); - - if (file) { - GFileInfo *file_info; - const gchar *attribute; - - file_info = e_attachment_get_file_info (attachment); - attribute = G_FILE_ATTRIBUTE_THUMBNAIL_PATH; - - if (file_info != NULL) - g_file_info_set_attribute_byte_string ( - file_info, attribute, thumbnail); - } - - g_free (thumbnail); - - return TRUE; -} - -static gchar * -attachment_get_default_charset (void) -{ - GSettings *settings; - gchar *charset; - - /* XXX This doesn't really belong here. */ - - settings = g_settings_new ("org.gnome.evolution.mail"); - charset = g_settings_get_string (settings, "composer-charset"); - if (charset == NULL || *charset == '\0') { - g_free (charset); - /* FIXME This was "/apps/evolution/mail/format/charset", - * not sure it relates to "charset" */ - charset = g_settings_get_string (settings, "charset"); - if (charset == NULL || *charset == '\0') { - g_free (charset); - charset = NULL; - } - } - g_object_unref (settings); - - if (charset == NULL) - charset = g_strdup (camel_iconv_locale_charset ()); - - if (charset == NULL) - charset = g_strdup ("us-ascii"); - - return charset; -} - -static void -attachment_update_file_info_columns (EAttachment *attachment) -{ - GtkTreeRowReference *reference; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - GFileInfo *file_info; - const gchar *content_type; - const gchar *description; - const gchar *display_name; - gchar *content_desc; - gchar *display_size; - gchar *caption; - goffset size; - - reference = e_attachment_get_reference (attachment); - if (!gtk_tree_row_reference_valid (reference)) - return; - - file_info = e_attachment_get_file_info (attachment); - if (file_info == NULL) - return; - - model = gtk_tree_row_reference_get_model (reference); - path = gtk_tree_row_reference_get_path (reference); - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - - content_type = g_file_info_get_content_type (file_info); - display_name = g_file_info_get_display_name (file_info); - size = g_file_info_get_size (file_info); - - content_desc = g_content_type_get_description (content_type); - display_size = g_format_size (size); - - description = e_attachment_get_description (attachment); - if (description == NULL || *description == '\0') - description = display_name; - - if (size > 0) - caption = g_strdup_printf ( - "%s\n(%s)", description, display_size); - else - caption = g_strdup (description); - - gtk_list_store_set ( - GTK_LIST_STORE (model), &iter, - E_ATTACHMENT_STORE_COLUMN_CAPTION, caption, - E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_desc, - E_ATTACHMENT_STORE_COLUMN_DESCRIPTION, description, - E_ATTACHMENT_STORE_COLUMN_SIZE, size, - -1); - - g_free (content_desc); - g_free (display_size); - g_free (caption); -} - -static void -attachment_update_icon_column (EAttachment *attachment) -{ - GtkTreeRowReference *reference; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - GFileInfo *file_info; - GCancellable *cancellable; - GIcon *icon = NULL; - const gchar *emblem_name = NULL; - const gchar *thumbnail_path = NULL; - - reference = e_attachment_get_reference (attachment); - if (!gtk_tree_row_reference_valid (reference)) - return; - - model = gtk_tree_row_reference_get_model (reference); - path = gtk_tree_row_reference_get_path (reference); - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - - cancellable = attachment->priv->cancellable; - file_info = e_attachment_get_file_info (attachment); - - if (file_info != NULL) { - icon = g_file_info_get_icon (file_info); - thumbnail_path = g_file_info_get_attribute_byte_string ( - file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH); - } - - /* Prefer the thumbnail if we have one. */ - if (thumbnail_path != NULL && *thumbnail_path != '\0') { - GFile *file; - - file = g_file_new_for_path (thumbnail_path); - icon = g_file_icon_new (file); - g_object_unref (file); - - /* Try the system thumbnailer. */ - } else if (create_system_thumbnail (attachment, &icon)) { - /* Nothing to do, just use the icon. */ - - /* Else use the standard icon for the content type. */ - } else if (icon != NULL) - g_object_ref (icon); - - /* Last ditch fallback. (GFileInfo not yet loaded?) */ - else - icon = g_themed_icon_new (DEFAULT_ICON_NAME); - - /* Pick an emblem, limit one. Choices listed by priority. */ - - if (g_cancellable_is_cancelled (cancellable)) - emblem_name = EMBLEM_CANCELLED; - - else if (e_attachment_get_loading (attachment)) - emblem_name = EMBLEM_LOADING; - - else if (e_attachment_get_saving (attachment)) - emblem_name = EMBLEM_SAVING; - - else if (e_attachment_get_encrypted (attachment)) - switch (e_attachment_get_encrypted (attachment)) { - case CAMEL_CIPHER_VALIDITY_ENCRYPT_WEAK: - emblem_name = EMBLEM_ENCRYPT_WEAK; - break; - - case CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED: - emblem_name = EMBLEM_ENCRYPT_UNKNOWN; - break; - - case CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG: - emblem_name = EMBLEM_ENCRYPT_STRONG; - break; - - default: - g_warn_if_reached (); - break; - } - - else if (e_attachment_get_signed (attachment)) - switch (e_attachment_get_signed (attachment)) { - case CAMEL_CIPHER_VALIDITY_SIGN_GOOD: - emblem_name = EMBLEM_SIGN_GOOD; - break; - - case CAMEL_CIPHER_VALIDITY_SIGN_BAD: - emblem_name = EMBLEM_SIGN_BAD; - break; - - case CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN: - case CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY: - emblem_name = EMBLEM_SIGN_UNKNOWN; - break; - - default: - g_warn_if_reached (); - break; - } - - if (emblem_name != NULL) { - GIcon *emblemed_icon; - GEmblem *emblem; - - emblemed_icon = g_themed_icon_new (emblem_name); - emblem = g_emblem_new (emblemed_icon); - g_object_unref (emblemed_icon); - - emblemed_icon = g_emblemed_icon_new (icon, emblem); - g_object_unref (emblem); - g_object_unref (icon); - - icon = emblemed_icon; - } - - gtk_list_store_set ( - GTK_LIST_STORE (model), &iter, - E_ATTACHMENT_STORE_COLUMN_ICON, icon, - -1); - - /* Cache the icon to reuse for things like drag-n-drop. */ - if (attachment->priv->icon != NULL) - g_object_unref (attachment->priv->icon); - attachment->priv->icon = icon; - g_object_notify (G_OBJECT (attachment), "icon"); -} - -static void -attachment_update_progress_columns (EAttachment *attachment) -{ - GtkTreeRowReference *reference; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - gboolean loading; - gboolean saving; - gint percent; - - reference = e_attachment_get_reference (attachment); - if (!gtk_tree_row_reference_valid (reference)) - return; - - model = gtk_tree_row_reference_get_model (reference); - path = gtk_tree_row_reference_get_path (reference); - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - - /* Don't show progress bars until we have progress to report. */ - percent = e_attachment_get_percent (attachment); - loading = e_attachment_get_loading (attachment) && (percent > 0); - saving = e_attachment_get_saving (attachment) && (percent > 0); - - gtk_list_store_set ( - GTK_LIST_STORE (model), &iter, - E_ATTACHMENT_STORE_COLUMN_LOADING, loading, - E_ATTACHMENT_STORE_COLUMN_PERCENT, percent, - E_ATTACHMENT_STORE_COLUMN_SAVING, saving, - -1); -} - -static void -attachment_set_loading (EAttachment *attachment, - gboolean loading) -{ - GtkTreeRowReference *reference; - - reference = e_attachment_get_reference (attachment); - - attachment->priv->percent = 0; - attachment->priv->loading = loading; - attachment->priv->last_percent_notify = 0; - - g_object_freeze_notify (G_OBJECT (attachment)); - g_object_notify (G_OBJECT (attachment), "percent"); - g_object_notify (G_OBJECT (attachment), "loading"); - g_object_thaw_notify (G_OBJECT (attachment)); - - if (gtk_tree_row_reference_valid (reference)) { - GtkTreeModel *model; - model = gtk_tree_row_reference_get_model (reference); - g_object_notify (G_OBJECT (model), "num-loading"); - } -} - -static void -attachment_set_saving (EAttachment *attachment, - gboolean saving) -{ - attachment->priv->percent = 0; - attachment->priv->saving = saving; - attachment->priv->last_percent_notify = 0; - - g_object_freeze_notify (G_OBJECT (attachment)); - g_object_notify (G_OBJECT (attachment), "percent"); - g_object_notify (G_OBJECT (attachment), "saving"); - g_object_thaw_notify (G_OBJECT (attachment)); -} - -static void -attachment_progress_cb (goffset current_num_bytes, - goffset total_num_bytes, - EAttachment *attachment) -{ - gint new_percent; - - /* Avoid dividing by zero. */ - if (total_num_bytes == 0) - return; - - /* do not notify too often, 5 times per second is sufficient */ - if (g_get_monotonic_time () - attachment->priv->last_percent_notify < 200000) - return; - - attachment->priv->last_percent_notify = g_get_monotonic_time (); - - new_percent = (current_num_bytes * 100) / total_num_bytes; - - if (new_percent != attachment->priv->percent) { - attachment->priv->percent = new_percent; - g_object_notify (G_OBJECT (attachment), "percent"); - } -} - -static gboolean -attachment_cancelled_timeout_cb (EAttachment *attachment) -{ - attachment->priv->emblem_timeout_id = 0; - g_cancellable_reset (attachment->priv->cancellable); - - attachment_update_icon_column (attachment); - - return FALSE; -} - -static void -attachment_cancelled_cb (EAttachment *attachment) -{ - /* Reset the GCancellable after one second. This causes a - * cancel emblem to be briefly shown on the attachment icon - * as visual feedback that an operation was cancelled. */ - - if (attachment->priv->emblem_timeout_id > 0) - g_source_remove (attachment->priv->emblem_timeout_id); - - attachment->priv->emblem_timeout_id = g_timeout_add_seconds ( - 1, (GSourceFunc) attachment_cancelled_timeout_cb, attachment); - - attachment_update_icon_column (attachment); -} - -static void -attachment_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CAN_SHOW: - e_attachment_set_can_show ( - E_ATTACHMENT (object), - g_value_get_boolean (value)); - return; - - case PROP_DISPOSITION: - e_attachment_set_disposition ( - E_ATTACHMENT (object), - g_value_get_string (value)); - return; - - case PROP_ENCRYPTED: - e_attachment_set_encrypted ( - E_ATTACHMENT (object), - g_value_get_int (value)); - return; - - case PROP_FILE: - e_attachment_set_file ( - E_ATTACHMENT (object), - g_value_get_object (value)); - return; - - case PROP_SHOWN: - e_attachment_set_shown ( - E_ATTACHMENT (object), - g_value_get_boolean (value)); - return; - - case PROP_MIME_PART: - e_attachment_set_mime_part ( - E_ATTACHMENT (object), - g_value_get_boxed (value)); - return; - - case PROP_REFERENCE: - e_attachment_set_reference ( - E_ATTACHMENT (object), - g_value_get_boxed (value)); - return; - - case PROP_SIGNED: - e_attachment_set_signed ( - E_ATTACHMENT (object), - g_value_get_int (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -attachment_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CAN_SHOW: - g_value_set_boolean ( - value, e_attachment_get_can_show ( - E_ATTACHMENT (object))); - return; - - case PROP_DISPOSITION: - g_value_set_string ( - value, e_attachment_get_disposition ( - E_ATTACHMENT (object))); - return; - - case PROP_ENCRYPTED: - g_value_set_int ( - value, e_attachment_get_encrypted ( - E_ATTACHMENT (object))); - return; - - case PROP_FILE: - g_value_set_object ( - value, e_attachment_get_file ( - E_ATTACHMENT (object))); - return; - - case PROP_FILE_INFO: - g_value_set_object ( - value, e_attachment_get_file_info ( - E_ATTACHMENT (object))); - return; - - case PROP_ICON: - g_value_set_object ( - value, e_attachment_get_icon ( - E_ATTACHMENT (object))); - return; - - case PROP_SHOWN: - g_value_set_boolean ( - value, e_attachment_get_shown ( - E_ATTACHMENT (object))); - return; - - case PROP_LOADING: - g_value_set_boolean ( - value, e_attachment_get_loading ( - E_ATTACHMENT (object))); - return; - - case PROP_MIME_PART: - g_value_set_boxed ( - value, e_attachment_get_mime_part ( - E_ATTACHMENT (object))); - return; - - case PROP_PERCENT: - g_value_set_int ( - value, e_attachment_get_percent ( - E_ATTACHMENT (object))); - return; - - case PROP_REFERENCE: - g_value_set_boxed ( - value, e_attachment_get_reference ( - E_ATTACHMENT (object))); - return; - - case PROP_SAVING: - g_value_set_boolean ( - value, e_attachment_get_saving ( - E_ATTACHMENT (object))); - return; - - case PROP_SIGNED: - g_value_set_int ( - value, e_attachment_get_signed ( - E_ATTACHMENT (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -attachment_dispose (GObject *object) -{ - EAttachmentPrivate *priv; - - priv = E_ATTACHMENT_GET_PRIVATE (object); - - if (priv->file != NULL) { - g_object_unref (priv->file); - priv->file = NULL; - } - - if (priv->icon != NULL) { - g_object_unref (priv->icon); - priv->icon = NULL; - } - - if (priv->file_info != NULL) { - g_object_unref (priv->file_info); - priv->file_info = NULL; - } - - if (priv->cancellable != NULL) { - g_object_unref (priv->cancellable); - priv->cancellable = NULL; - } - - if (priv->mime_part != NULL) { - g_object_unref (priv->mime_part); - priv->mime_part = NULL; - } - - if (priv->emblem_timeout_id > 0) { - g_source_remove (priv->emblem_timeout_id); - priv->emblem_timeout_id = 0; - } - - /* This accepts NULL arguments. */ - gtk_tree_row_reference_free (priv->reference); - priv->reference = NULL; - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_attachment_parent_class)->dispose (object); -} - -static void -attachment_finalize (GObject *object) -{ - EAttachmentPrivate *priv; - - priv = E_ATTACHMENT_GET_PRIVATE (object); - - g_free (priv->disposition); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_attachment_parent_class)->finalize (object); -} - -static void -e_attachment_class_init (EAttachmentClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private (class, sizeof (EAttachmentPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = attachment_set_property; - object_class->get_property = attachment_get_property; - object_class->dispose = attachment_dispose; - object_class->finalize = attachment_finalize; - - g_object_class_install_property ( - object_class, - PROP_CAN_SHOW, - g_param_spec_boolean ( - "can-show", - "Can Show", - NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_DISPOSITION, - g_param_spec_string ( - "disposition", - "Disposition", - NULL, - "attachment", - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - /* FIXME Define a GEnumClass for this. */ - g_object_class_install_property ( - object_class, - PROP_ENCRYPTED, - g_param_spec_int ( - "encrypted", - "Encrypted", - NULL, - CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE, - CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG, - CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_FILE, - g_param_spec_object ( - "file", - "File", - NULL, - G_TYPE_FILE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_FILE_INFO, - g_param_spec_object ( - "file-info", - "File Info", - NULL, - G_TYPE_FILE_INFO, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_ICON, - g_param_spec_object ( - "icon", - "Icon", - NULL, - G_TYPE_ICON, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_LOADING, - g_param_spec_boolean ( - "loading", - "Loading", - NULL, - FALSE, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_MIME_PART, - g_param_spec_object ( - "mime-part", - "MIME Part", - NULL, - CAMEL_TYPE_MIME_PART, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_PERCENT, - g_param_spec_int ( - "percent", - "Percent", - NULL, - 0, - 100, - 0, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_REFERENCE, - g_param_spec_boxed ( - "reference", - "Reference", - NULL, - GTK_TYPE_TREE_ROW_REFERENCE, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SAVING, - g_param_spec_boolean ( - "saving", - "Saving", - NULL, - FALSE, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_SHOWN, - g_param_spec_boolean ( - "shown", - "Shown", - NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - /* FIXME Define a GEnumClass for this. */ - g_object_class_install_property ( - object_class, - PROP_SIGNED, - g_param_spec_int ( - "signed", - "Signed", - NULL, - CAMEL_CIPHER_VALIDITY_SIGN_NONE, - CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY, - CAMEL_CIPHER_VALIDITY_SIGN_NONE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); -} - -static void -e_attachment_init (EAttachment *attachment) -{ - attachment->priv = E_ATTACHMENT_GET_PRIVATE (attachment); - attachment->priv->cancellable = g_cancellable_new (); - attachment->priv->encrypted = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE; - attachment->priv->signed_ = CAMEL_CIPHER_VALIDITY_SIGN_NONE; - - g_signal_connect ( - attachment, "notify::encrypted", - G_CALLBACK (attachment_update_icon_column), NULL); - - g_signal_connect ( - attachment, "notify::file-info", - G_CALLBACK (attachment_update_file_info_columns), NULL); - - g_signal_connect ( - attachment, "notify::file-info", - G_CALLBACK (attachment_update_icon_column), NULL); - - g_signal_connect ( - attachment, "notify::loading", - G_CALLBACK (attachment_update_icon_column), NULL); - - g_signal_connect ( - attachment, "notify::loading", - G_CALLBACK (attachment_update_progress_columns), NULL); - - g_signal_connect ( - attachment, "notify::percent", - G_CALLBACK (attachment_update_progress_columns), NULL); - - g_signal_connect ( - attachment, "notify::reference", - G_CALLBACK (attachment_update_file_info_columns), NULL); - - g_signal_connect ( - attachment, "notify::reference", - G_CALLBACK (attachment_update_icon_column), NULL); - - g_signal_connect ( - attachment, "notify::reference", - G_CALLBACK (attachment_update_progress_columns), NULL); - - g_signal_connect ( - attachment, "notify::saving", - G_CALLBACK (attachment_update_icon_column), NULL); - - g_signal_connect ( - attachment, "notify::saving", - G_CALLBACK (attachment_update_progress_columns), NULL); - - g_signal_connect ( - attachment, "notify::signed", - G_CALLBACK (attachment_update_icon_column), NULL); - - g_signal_connect_swapped ( - attachment->priv->cancellable, "cancelled", - G_CALLBACK (attachment_cancelled_cb), attachment); -} - -EAttachment * -e_attachment_new (void) -{ - return g_object_new (E_TYPE_ATTACHMENT, NULL); -} - -EAttachment * -e_attachment_new_for_path (const gchar *path) -{ - EAttachment *attachment; - GFile *file; - - g_return_val_if_fail (path != NULL, NULL); - - file = g_file_new_for_path (path); - attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL); - g_object_unref (file); - - return attachment; -} - -EAttachment * -e_attachment_new_for_uri (const gchar *uri) -{ - EAttachment *attachment; - GFile *file; - - g_return_val_if_fail (uri != NULL, NULL); - - file = g_file_new_for_uri (uri); - attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL); - g_object_unref (file); - - return attachment; -} - -EAttachment * -e_attachment_new_for_message (CamelMimeMessage *message) -{ - CamelDataWrapper *wrapper; - CamelMimePart *mime_part; - EAttachment *attachment; - GString *description; - const gchar *subject; - - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); - - mime_part = camel_mime_part_new (); - camel_mime_part_set_disposition (mime_part, "inline"); - subject = camel_mime_message_get_subject (message); - - /* To Translators: This text is set as a description of an attached - * message when, for example, attaching it to a composer. When the - * message to be attached has also filled Subject, then this text is - * of form "Attached message - Subject", otherwise it's left as is. */ - description = g_string_new (_("Attached message")); - if (subject != NULL) - g_string_append_printf (description, " - %s", subject); - camel_mime_part_set_description (mime_part, description->str); - g_string_free (description, TRUE); - - wrapper = CAMEL_DATA_WRAPPER (message); - camel_medium_set_content (CAMEL_MEDIUM (mime_part), wrapper); - camel_mime_part_set_content_type (mime_part, "message/rfc822"); - - attachment = e_attachment_new (); - e_attachment_set_mime_part (attachment, mime_part); - g_object_unref (mime_part); - - return attachment; -} - -void -e_attachment_add_to_multipart (EAttachment *attachment, - CamelMultipart *multipart, - const gchar *default_charset) -{ - CamelContentType *content_type; - CamelDataWrapper *wrapper; - CamelMimePart *mime_part; - - /* XXX EMsgComposer might be a better place for this function. */ - - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - g_return_if_fail (CAMEL_IS_MULTIPART (multipart)); - - /* Still loading? Too bad. */ - mime_part = e_attachment_get_mime_part (attachment); - if (mime_part == NULL) - return; - - content_type = camel_mime_part_get_content_type (mime_part); - wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); - - if (CAMEL_IS_MULTIPART (wrapper)) - goto exit; - - /* For text content, determine the best encoding and character set. */ - if (camel_content_type_is (content_type, "text", "*")) { - CamelTransferEncoding encoding; - CamelStream *filtered_stream; - CamelMimeFilter *filter; - CamelStream *stream; - const gchar *charset; - - charset = camel_content_type_param (content_type, "charset"); - - /* Determine the best encoding by writing the MIME - * part to a NULL stream with a "bestenc" filter. */ - stream = camel_stream_null_new (); - filtered_stream = camel_stream_filter_new (stream); - filter = camel_mime_filter_bestenc_new ( - CAMEL_BESTENC_GET_ENCODING); - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filtered_stream), - CAMEL_MIME_FILTER (filter)); - camel_data_wrapper_decode_to_stream_sync ( - wrapper, filtered_stream, NULL, NULL); - g_object_unref (filtered_stream); - g_object_unref (stream); - - /* Retrieve the best encoding from the filter. */ - encoding = camel_mime_filter_bestenc_get_best_encoding ( - CAMEL_MIME_FILTER_BESTENC (filter), - CAMEL_BESTENC_8BIT); - camel_mime_part_set_encoding (mime_part, encoding); - g_object_unref (filter); - - if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) { - /* The text fits within us-ascii, so this is safe. - * FIXME Check that this isn't iso-2022-jp? */ - default_charset = "us-ascii"; - - } else if (charset == NULL && default_charset == NULL) { - default_charset = attachment_get_default_charset (); - /* FIXME Check that this fits within the - * default_charset and if not, find one - * that does and/or allow the user to - * specify. */ - } - - if (charset == NULL) { - gchar *type; - - camel_content_type_set_param ( - content_type, "charset", default_charset); - type = camel_content_type_format (content_type); - camel_mime_part_set_content_type (mime_part, type); - g_free (type); - } - - /* Otherwise, unless it's a message/rfc822, Base64 encode it. */ - } else if (!CAMEL_IS_MIME_MESSAGE (wrapper)) - camel_mime_part_set_encoding ( - mime_part, CAMEL_TRANSFER_ENCODING_BASE64); - -exit: - camel_multipart_add_part (multipart, mime_part); -} - -void -e_attachment_cancel (EAttachment *attachment) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - g_cancellable_cancel (attachment->priv->cancellable); -} - -gboolean -e_attachment_get_can_show (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - - return attachment->priv->can_show; -} - -void -e_attachment_set_can_show (EAttachment *attachment, - gboolean can_show) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - attachment->priv->can_show = can_show; - - g_object_notify (G_OBJECT (attachment), "can-show"); -} - -const gchar * -e_attachment_get_disposition (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - return attachment->priv->disposition; -} - -void -e_attachment_set_disposition (EAttachment *attachment, - const gchar *disposition) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - g_free (attachment->priv->disposition); - attachment->priv->disposition = g_strdup (disposition); - - g_object_notify (G_OBJECT (attachment), "disposition"); -} - -GFile * -e_attachment_get_file (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - return attachment->priv->file; -} - -void -e_attachment_set_file (EAttachment *attachment, - GFile *file) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - if (file != NULL) { - g_return_if_fail (G_IS_FILE (file)); - g_object_ref (file); - } - - if (attachment->priv->file != NULL) - g_object_unref (attachment->priv->file); - - attachment->priv->file = file; - - g_object_notify (G_OBJECT (attachment), "file"); -} - -GFileInfo * -e_attachment_get_file_info (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - return attachment->priv->file_info; -} - -void -e_attachment_set_file_info (EAttachment *attachment, - GFileInfo *file_info) -{ - GtkTreeRowReference *reference; - GIcon *icon; - - reference = e_attachment_get_reference (attachment); - - if (file_info != NULL) - g_object_ref (file_info); - - if (attachment->priv->file_info != NULL) - g_object_unref (attachment->priv->file_info); - - attachment->priv->file_info = file_info; - - /* If the GFileInfo contains a GThemedIcon, append a - * fallback icon name to ensure we display something. */ - icon = g_file_info_get_icon (file_info); - if (G_IS_THEMED_ICON (icon)) - g_themed_icon_append_name ( - G_THEMED_ICON (icon), DEFAULT_ICON_NAME); - - g_object_notify (G_OBJECT (attachment), "file-info"); - - /* Tell the EAttachmentStore its total size changed. */ - if (gtk_tree_row_reference_valid (reference)) { - GtkTreeModel *model; - model = gtk_tree_row_reference_get_model (reference); - g_object_notify (G_OBJECT (model), "total-size"); - } -} - -/** - * e_attachment_get_mime_type: - * - * Returns mime_type part of the file_info as a newly allocated string, - * which should be freed with g_free(). - * Returns NULL, if mime_type not found or set on the attachment. - **/ -gchar * -e_attachment_get_mime_type (EAttachment *attachment) -{ - GFileInfo *file_info; - const gchar *content_type; - gchar *mime_type; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - file_info = e_attachment_get_file_info (attachment); - if (file_info == NULL) - return NULL; - - content_type = g_file_info_get_content_type (file_info); - if (content_type == NULL) - return NULL; - - mime_type = g_content_type_get_mime_type (content_type); - if (!mime_type) - return NULL; - - camel_strdown (mime_type); - - return mime_type; -} - -GIcon * -e_attachment_get_icon (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - return attachment->priv->icon; -} - -gboolean -e_attachment_get_loading (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - - return attachment->priv->loading; -} - -CamelMimePart * -e_attachment_get_mime_part (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - return attachment->priv->mime_part; -} - -void -e_attachment_set_mime_part (EAttachment *attachment, - CamelMimePart *mime_part) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - if (mime_part != NULL) { - g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); - g_object_ref (mime_part); - } - - if (attachment->priv->mime_part != NULL) - g_object_unref (attachment->priv->mime_part); - - attachment->priv->mime_part = mime_part; - - g_object_notify (G_OBJECT (attachment), "mime-part"); -} - -gint -e_attachment_get_percent (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), 0); - - return attachment->priv->percent; -} - -GtkTreeRowReference * -e_attachment_get_reference (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - return attachment->priv->reference; -} - -void -e_attachment_set_reference (EAttachment *attachment, - GtkTreeRowReference *reference) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - if (reference != NULL) - reference = gtk_tree_row_reference_copy (reference); - - gtk_tree_row_reference_free (attachment->priv->reference); - attachment->priv->reference = reference; - - g_object_notify (G_OBJECT (attachment), "reference"); -} - -gboolean -e_attachment_get_saving (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - - return attachment->priv->saving; -} - -gboolean -e_attachment_get_shown (EAttachment *attachment) -{ - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - - return attachment->priv->shown; -} - -void -e_attachment_set_shown (EAttachment *attachment, - gboolean shown) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - attachment->priv->shown = shown; - - g_object_notify (G_OBJECT (attachment), "shown"); -} - -camel_cipher_validity_encrypt_t -e_attachment_get_encrypted (EAttachment *attachment) -{ - g_return_val_if_fail ( - E_IS_ATTACHMENT (attachment), - CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE); - - return attachment->priv->encrypted; -} - -void -e_attachment_set_encrypted (EAttachment *attachment, - camel_cipher_validity_encrypt_t encrypted) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - attachment->priv->encrypted = encrypted; - - g_object_notify (G_OBJECT (attachment), "encrypted"); -} - -camel_cipher_validity_sign_t -e_attachment_get_signed (EAttachment *attachment) -{ - g_return_val_if_fail ( - E_IS_ATTACHMENT (attachment), - CAMEL_CIPHER_VALIDITY_SIGN_NONE); - - return attachment->priv->signed_; -} - -void -e_attachment_set_signed (EAttachment *attachment, - camel_cipher_validity_sign_t signed_) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - attachment->priv->signed_ = signed_; - - g_object_notify (G_OBJECT (attachment), "signed"); -} - -const gchar * -e_attachment_get_description (EAttachment *attachment) -{ - GFileInfo *file_info; - const gchar *attribute; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION; - file_info = e_attachment_get_file_info (attachment); - - if (file_info == NULL) - return NULL; - - return g_file_info_get_attribute_string (file_info, attribute); -} - -const gchar * -e_attachment_get_thumbnail_path (EAttachment *attachment) -{ - GFileInfo *file_info; - const gchar *attribute; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - attribute = G_FILE_ATTRIBUTE_THUMBNAIL_PATH; - file_info = e_attachment_get_file_info (attachment); - - if (file_info == NULL) - return NULL; - - return g_file_info_get_attribute_byte_string (file_info, attribute); -} - -gboolean -e_attachment_is_rfc822 (EAttachment *attachment) -{ - gchar *mime_type; - gboolean is_rfc822; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - - mime_type = e_attachment_get_mime_type (attachment); - is_rfc822 = mime_type && g_ascii_strcasecmp (mime_type, "message/rfc822") == 0; - g_free (mime_type); - - return is_rfc822; -} - -GList * -e_attachment_list_apps (EAttachment *attachment) -{ - GList *app_info_list; - GList *guessed_infos; - GFileInfo *file_info; - const gchar *content_type; - const gchar *display_name; - gboolean type_is_unknown; - gchar *allocated; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - - file_info = e_attachment_get_file_info (attachment); - if (file_info == NULL) - return NULL; - - content_type = g_file_info_get_content_type (file_info); - display_name = g_file_info_get_display_name (file_info); - g_return_val_if_fail (content_type != NULL, NULL); - - app_info_list = g_app_info_get_all_for_type (content_type); - type_is_unknown = g_content_type_is_unknown (content_type); - - if (app_info_list != NULL && !type_is_unknown) - goto exit; - - if (display_name == NULL) - goto exit; - - allocated = g_content_type_guess (display_name, NULL, 0, NULL); - guessed_infos = g_app_info_get_all_for_type (allocated); - app_info_list = g_list_concat (guessed_infos, app_info_list); - g_free (allocated); - -exit: - return app_info_list; -} - -/************************* e_attachment_load_async() *************************/ - -typedef struct _LoadContext LoadContext; - -struct _LoadContext { - EAttachment *attachment; - CamelMimePart *mime_part; - GSimpleAsyncResult *simple; - - GInputStream *input_stream; - GOutputStream *output_stream; - GFileInfo *file_info; - goffset total_num_bytes; - gssize bytes_read; - gchar buffer[4096]; -}; - -/* Forward Declaration */ -static void -attachment_load_stream_read_cb (GInputStream *input_stream, - GAsyncResult *result, - LoadContext *load_context); - -static LoadContext * -attachment_load_context_new (EAttachment *attachment, - GAsyncReadyCallback callback, - gpointer user_data) -{ - LoadContext *load_context; - GSimpleAsyncResult *simple; - - simple = g_simple_async_result_new ( - G_OBJECT (attachment), callback, - user_data, e_attachment_load_async); - - load_context = g_slice_new0 (LoadContext); - load_context->attachment = g_object_ref (attachment); - load_context->simple = simple; - - attachment_set_loading (load_context->attachment, TRUE); - - return load_context; -} - -static void -attachment_load_context_free (LoadContext *load_context) -{ - g_object_unref (load_context->attachment); - - if (load_context->mime_part != NULL) - g_object_unref (load_context->mime_part); - - if (load_context->simple) - g_object_unref (load_context->simple); - - if (load_context->input_stream != NULL) - g_object_unref (load_context->input_stream); - - if (load_context->output_stream != NULL) - g_object_unref (load_context->output_stream); - - if (load_context->file_info != NULL) - g_object_unref (load_context->file_info); - - g_slice_free (LoadContext, load_context); -} - -static gboolean -attachment_load_check_for_error (LoadContext *load_context, - GError *error) -{ - GSimpleAsyncResult *simple; - - if (error == NULL) - return FALSE; - - simple = load_context->simple; - g_simple_async_result_take_error (simple, error); - g_simple_async_result_complete (simple); - - attachment_load_context_free (load_context); - - return TRUE; -} - -static void -attachment_load_finish (LoadContext *load_context) -{ - GFileInfo *file_info; - EAttachment *attachment; - GMemoryOutputStream *output_stream; - GSimpleAsyncResult *simple; - CamelDataWrapper *wrapper; - CamelMimePart *mime_part; - CamelStream *stream; - const gchar *attribute; - const gchar *content_type; - const gchar *display_name; - const gchar *description; - const gchar *disposition; - gchar *mime_type; - gpointer data; - gsize size; - - simple = load_context->simple; - - file_info = load_context->file_info; - attachment = load_context->attachment; - output_stream = G_MEMORY_OUTPUT_STREAM (load_context->output_stream); - - if (e_attachment_is_rfc822 (attachment)) - wrapper = (CamelDataWrapper *) camel_mime_message_new (); - else - wrapper = camel_data_wrapper_new (); - - content_type = g_file_info_get_content_type (file_info); - mime_type = g_content_type_get_mime_type (content_type); - - data = g_memory_output_stream_get_data (output_stream); - size = g_memory_output_stream_get_data_size (output_stream); - - stream = camel_stream_mem_new_with_buffer (data, size); - camel_data_wrapper_construct_from_stream_sync ( - wrapper, stream, NULL, NULL); - camel_data_wrapper_set_mime_type (wrapper, mime_type); - camel_stream_close (stream, NULL, NULL); - g_object_unref (stream); - - mime_part = camel_mime_part_new (); - camel_medium_set_content (CAMEL_MEDIUM (mime_part), wrapper); - - g_object_unref (wrapper); - g_free (mime_type); - - display_name = g_file_info_get_display_name (file_info); - if (display_name != NULL) - camel_mime_part_set_filename (mime_part, display_name); - - attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION; - description = g_file_info_get_attribute_string (file_info, attribute); - if (description != NULL) - camel_mime_part_set_description (mime_part, description); - - disposition = e_attachment_get_disposition (attachment); - if (disposition != NULL) - camel_mime_part_set_disposition (mime_part, disposition); - - /* Correctly report the size of zero length special files. */ - if (g_file_info_get_size (file_info) == 0) - g_file_info_set_size (file_info, size); - - load_context->mime_part = mime_part; - - g_simple_async_result_set_op_res_gpointer ( - simple, load_context, (GDestroyNotify) attachment_load_context_free); - - g_simple_async_result_complete (simple); - - /* make sure it's freed on operation end */ - load_context->simple = NULL; - g_object_unref (simple); -} - -static void -attachment_load_write_cb (GOutputStream *output_stream, - GAsyncResult *result, - LoadContext *load_context) -{ - EAttachment *attachment; - GCancellable *cancellable; - GInputStream *input_stream; - gssize bytes_written; - GError *error = NULL; - - bytes_written = g_output_stream_write_finish ( - output_stream, result, &error); - - if (attachment_load_check_for_error (load_context, error)) - return; - - attachment = load_context->attachment; - cancellable = attachment->priv->cancellable; - input_stream = load_context->input_stream; - - attachment_progress_cb ( - g_seekable_tell (G_SEEKABLE (output_stream)), - load_context->total_num_bytes, attachment); - - if (bytes_written < load_context->bytes_read) { - g_memmove ( - load_context->buffer, - load_context->buffer + bytes_written, - load_context->bytes_read - bytes_written); - load_context->bytes_read -= bytes_written; - - g_output_stream_write_async ( - output_stream, - load_context->buffer, - load_context->bytes_read, - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_load_write_cb, - load_context); - } else - g_input_stream_read_async ( - input_stream, - load_context->buffer, - sizeof (load_context->buffer), - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_load_stream_read_cb, - load_context); -} - -static void -attachment_load_stream_read_cb (GInputStream *input_stream, - GAsyncResult *result, - LoadContext *load_context) -{ - EAttachment *attachment; - GCancellable *cancellable; - GOutputStream *output_stream; - gssize bytes_read; - GError *error = NULL; - - bytes_read = g_input_stream_read_finish ( - input_stream, result, &error); - - if (attachment_load_check_for_error (load_context, error)) - return; - - if (bytes_read == 0) { - attachment_load_finish (load_context); - return; - } - - attachment = load_context->attachment; - cancellable = attachment->priv->cancellable; - output_stream = load_context->output_stream; - load_context->bytes_read = bytes_read; - - g_output_stream_write_async ( - output_stream, - load_context->buffer, - load_context->bytes_read, - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_load_write_cb, - load_context); -} - -static void -attachment_load_file_read_cb (GFile *file, - GAsyncResult *result, - LoadContext *load_context) -{ - EAttachment *attachment; - GCancellable *cancellable; - GFileInputStream *input_stream; - GOutputStream *output_stream; - GError *error = NULL; - - /* Input stream might be NULL, so don't use cast macro. */ - input_stream = g_file_read_finish (file, result, &error); - load_context->input_stream = (GInputStream *) input_stream; - - if (attachment_load_check_for_error (load_context, error)) - return; - - /* Load the contents into a GMemoryOutputStream. */ - output_stream = g_memory_output_stream_new ( - NULL, 0, g_realloc, g_free); - - attachment = load_context->attachment; - cancellable = attachment->priv->cancellable; - load_context->output_stream = output_stream; - - g_input_stream_read_async ( - load_context->input_stream, - load_context->buffer, - sizeof (load_context->buffer), - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_load_stream_read_cb, - load_context); -} - -static void -attachment_load_query_info_cb (GFile *file, - GAsyncResult *result, - LoadContext *load_context) -{ - EAttachment *attachment; - GCancellable *cancellable; - GFileInfo *file_info; - GError *error = NULL; - - attachment = load_context->attachment; - cancellable = attachment->priv->cancellable; - - file_info = g_file_query_info_finish (file, result, &error); - if (attachment_load_check_for_error (load_context, error)) - return; - - e_attachment_set_file_info (attachment, file_info); - load_context->file_info = file_info; - - 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); -} - -#define ATTACHMENT_LOAD_CONTEXT "attachment-load-context-data" - -static void -attachment_load_from_mime_part_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - LoadContext *load_context; - GFileInfo *file_info; - EAttachment *attachment; - CamelContentType *content_type; - CamelMimePart *mime_part; - const gchar *attribute; - const gchar *string; - gchar *allocated; - CamelStream *null; - CamelDataWrapper *dw; - - load_context = g_object_get_data (G_OBJECT (simple), ATTACHMENT_LOAD_CONTEXT); - g_return_if_fail (load_context != NULL); - g_object_set_data (G_OBJECT (simple), ATTACHMENT_LOAD_CONTEXT, NULL); - - attachment = load_context->attachment; - mime_part = e_attachment_get_mime_part (attachment); - - file_info = g_file_info_new (); - load_context->file_info = file_info; - - content_type = camel_mime_part_get_content_type (mime_part); - allocated = camel_content_type_simple (content_type); - if (allocated != NULL) { - GIcon *icon; - gchar *cp; - - /* GIO expects lowercase MIME types. */ - for (cp = allocated; *cp != '\0'; cp++) - *cp = g_ascii_tolower (*cp); - - /* Swap the MIME type for a content type. */ - cp = g_content_type_from_mime_type (allocated); - g_free (allocated); - allocated = cp; - - /* Use the MIME part's filename if we have to. */ - if (g_content_type_is_unknown (allocated)) { - string = camel_mime_part_get_filename (mime_part); - if (string != NULL) { - g_free (allocated); - allocated = g_content_type_guess ( - string, NULL, 0, NULL); - } - } - - g_file_info_set_content_type (file_info, allocated); - - icon = g_content_type_get_icon (allocated); - if (icon != NULL) { - g_file_info_set_icon (file_info, icon); - g_object_unref (icon); - } - } - g_free (allocated); - - /* Strip any path components from the filename. */ - string = camel_mime_part_get_filename (mime_part); - if (string == NULL) - /* Translators: Default attachment filename. */ - string = _("attachment.dat"); - allocated = g_path_get_basename (string); - g_file_info_set_display_name (file_info, allocated); - g_free (allocated); - - attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION; - string = camel_mime_part_get_description (mime_part); - if (string != NULL) - g_file_info_set_attribute_string ( - file_info, attribute, string); - - dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); - null = camel_stream_null_new (); - /* this actually downloads the part and makes it available later */ - camel_data_wrapper_decode_to_stream_sync (dw, null, attachment->priv->cancellable, NULL); - g_file_info_set_size (file_info, CAMEL_STREAM_NULL (null)->written); - g_object_unref (null); - - load_context->mime_part = g_object_ref (mime_part); - - /* make sure it's freed on operation end */ - g_object_unref (load_context->simple); - load_context->simple = NULL; - - g_simple_async_result_set_op_res_gpointer ( - simple, load_context, - (GDestroyNotify) attachment_load_context_free); -} - -void -e_attachment_load_async (EAttachment *attachment, - GAsyncReadyCallback callback, - gpointer user_data) -{ - LoadContext *load_context; - GCancellable *cancellable; - CamelMimePart *mime_part; - GFile *file; - - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - if (e_attachment_get_loading (attachment)) { - g_simple_async_report_error_in_idle ( - G_OBJECT (attachment), callback, user_data, - G_IO_ERROR, G_IO_ERROR_BUSY, - _("A load operation is already in progress")); - return; - } - - if (e_attachment_get_saving (attachment)) { - g_simple_async_report_error_in_idle ( - G_OBJECT (attachment), callback, user_data, - G_IO_ERROR, G_IO_ERROR_BUSY, - _("A save operation is already in progress")); - return; - } - - file = e_attachment_get_file (attachment); - mime_part = e_attachment_get_mime_part (attachment); - g_return_if_fail (file != NULL || mime_part != NULL); - - load_context = attachment_load_context_new ( - attachment, callback, user_data); - - cancellable = attachment->priv->cancellable; - g_cancellable_reset (cancellable); - - if (file != NULL) { - g_file_query_info_async ( - file, ATTACHMENT_QUERY, - G_FILE_QUERY_INFO_NONE,G_PRIORITY_DEFAULT, - cancellable, (GAsyncReadyCallback) - attachment_load_query_info_cb, load_context); - - } else if (mime_part != NULL) { - g_object_set_data (G_OBJECT (load_context->simple), ATTACHMENT_LOAD_CONTEXT, load_context); - - g_simple_async_result_run_in_thread ( - load_context->simple, - attachment_load_from_mime_part_thread, - G_PRIORITY_DEFAULT, - cancellable); - } -} - -gboolean -e_attachment_load_finish (EAttachment *attachment, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - const LoadContext *load_context; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - load_context = g_simple_async_result_get_op_res_gpointer (simple); - if (load_context && load_context->mime_part) { - const gchar *string; - - string = camel_mime_part_get_disposition (load_context->mime_part); - e_attachment_set_disposition (attachment, string); - - e_attachment_set_file_info (attachment, load_context->file_info); - e_attachment_set_mime_part (attachment, load_context->mime_part); - } - - g_simple_async_result_propagate_error (simple, error); - - attachment_set_loading (attachment, FALSE); - - return (load_context != NULL); -} - -void -e_attachment_load_handle_error (EAttachment *attachment, - GAsyncResult *result, - GtkWindow *parent) -{ - GtkWidget *dialog; - GFileInfo *file_info; - GtkTreeRowReference *reference; - const gchar *display_name; - const gchar *primary_text; - GError *error = NULL; - - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - g_return_if_fail (G_IS_ASYNC_RESULT (result)); - g_return_if_fail (!parent || GTK_IS_WINDOW (parent)); - - if (e_attachment_load_finish (attachment, result, &error)) - return; - - /* XXX Calling EAttachmentStore functions from here violates - * the abstraction, but for now it's not hurting anything. */ - reference = e_attachment_get_reference (attachment); - if (gtk_tree_row_reference_valid (reference)) { - GtkTreeModel *model; - - model = gtk_tree_row_reference_get_model (reference); - - e_attachment_store_remove_attachment ( - E_ATTACHMENT_STORE (model), attachment); - } - - /* Ignore cancellations. */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free (error); - return; - } - - file_info = e_attachment_get_file_info (attachment); - - if (file_info != NULL) - display_name = g_file_info_get_display_name (file_info); - else - display_name = NULL; - - if (display_name != NULL) - primary_text = g_strdup_printf ( - _("Could not load '%s'"), display_name); - else - primary_text = g_strdup_printf ( - _("Could not load the attachment")); - - dialog = gtk_message_dialog_new_with_markup ( - parent, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "%s", primary_text); - - gtk_message_dialog_format_secondary_text ( - GTK_MESSAGE_DIALOG (dialog), "%s", error->message); - - gtk_dialog_run (GTK_DIALOG (dialog)); - - gtk_widget_destroy (dialog); - g_error_free (error); -} - -gboolean -e_attachment_load (EAttachment *attachment, - GError **error) -{ - EAsyncClosure *closure; - GAsyncResult *result; - gboolean success; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - - closure = e_async_closure_new (); - - e_attachment_load_async (attachment, e_async_closure_callback, closure); - - result = e_async_closure_wait (closure); - - success = e_attachment_load_finish (attachment, result, error); - - e_async_closure_free (closure); - - return success; -} - -/************************* e_attachment_open_async() *************************/ - -typedef struct _OpenContext OpenContext; - -struct _OpenContext { - EAttachment *attachment; - GSimpleAsyncResult *simple; - - GAppInfo *app_info; -}; - -static OpenContext * -attachment_open_context_new (EAttachment *attachment, - GAsyncReadyCallback callback, - gpointer user_data) -{ - OpenContext *open_context; - GSimpleAsyncResult *simple; - - simple = g_simple_async_result_new ( - G_OBJECT (attachment), callback, - user_data, e_attachment_open_async); - - open_context = g_slice_new0 (OpenContext); - open_context->attachment = g_object_ref (attachment); - open_context->simple = simple; - - return open_context; -} - -static void -attachment_open_context_free (OpenContext *open_context) -{ - g_object_unref (open_context->attachment); - g_object_unref (open_context->simple); - - if (open_context->app_info != NULL) - g_object_unref (open_context->app_info); - - g_slice_free (OpenContext, open_context); -} - -static gboolean -attachment_open_check_for_error (OpenContext *open_context, - GError *error) -{ - GSimpleAsyncResult *simple; - - if (error == NULL) - return FALSE; - - simple = open_context->simple; - g_simple_async_result_take_error (simple, error); - g_simple_async_result_complete (simple); - - attachment_open_context_free (open_context); - - return TRUE; -} - -static void -attachment_open_file (GFile *file, - OpenContext *open_context) -{ - GdkAppLaunchContext *context; - GSimpleAsyncResult *simple; - GdkDisplay *display; - gboolean success; - GError *error = NULL; - - simple = open_context->simple; - - display = gdk_display_get_default (); - context = gdk_display_get_app_launch_context (display); - - if (open_context->app_info != NULL) { - GList *file_list; - - file_list = g_list_prepend (NULL, file); - success = g_app_info_launch ( - open_context->app_info, file_list, - G_APP_LAUNCH_CONTEXT (context), &error); - g_list_free (file_list); - } else { - gchar *uri; - - uri = g_file_get_uri (file); - success = g_app_info_launch_default_for_uri ( - uri, G_APP_LAUNCH_CONTEXT (context), &error); - g_free (uri); - } - - g_object_unref (context); - - g_simple_async_result_set_op_res_gboolean (simple, success); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); - - g_simple_async_result_complete (simple); - attachment_open_context_free (open_context); -} - -static void -attachment_open_save_finished_cb (EAttachment *attachment, - GAsyncResult *result, - OpenContext *open_context) -{ - GFile *file; - gchar *path; - GError *error = NULL; - - file = e_attachment_save_finish (attachment, result, &error); - - if (attachment_open_check_for_error (open_context, error)) - return; - - /* Make the temporary file read-only. - * - * This step is non-critical, so if an error occurs just - * emit a warning and move on. - * - * XXX I haven't figured out how to do this through GIO. - * Attempting to set the "access::can-write" attribute via - * g_file_set_attribute() returned G_IO_ERROR_NOT_SUPPORTED - * and the only other possibility I see is "unix::mode", - * which is obviously not portable. - */ - path = g_file_get_path (file); -#ifndef G_OS_WIN32 - if (g_chmod (path, S_IRUSR | S_IRGRP | S_IROTH) < 0) - g_warning ("%s", g_strerror (errno)); -#endif - g_free (path); - - attachment_open_file (file, open_context); - g_object_unref (file); -} - -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)); - - /* 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 -e_attachment_open_async (EAttachment *attachment, - GAppInfo *app_info, - GAsyncReadyCallback callback, - gpointer user_data) -{ - OpenContext *open_context; - CamelMimePart *mime_part; - GFile *file; - - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - file = e_attachment_get_file (attachment); - mime_part = e_attachment_get_mime_part (attachment); - g_return_if_fail (file != NULL || mime_part != NULL); - - open_context = attachment_open_context_new ( - attachment, callback, user_data); - - if (G_IS_APP_INFO (app_info)) - open_context->app_info = g_object_ref (app_info); - - /* If the attachment already references a GFile, we can launch - * the application directly. Otherwise we have to save the MIME - * part to a temporary file and launch the application from that. */ - if (file != NULL) { - attachment_open_file (file, open_context); - - } else if (mime_part != NULL) - attachment_open_save_temporary (open_context); -} - -gboolean -e_attachment_open_finish (EAttachment *attachment, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - gboolean success; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - success = g_simple_async_result_get_op_res_gboolean (simple); - g_simple_async_result_propagate_error (simple, error); - - return success; -} - -void -e_attachment_open_handle_error (EAttachment *attachment, - GAsyncResult *result, - GtkWindow *parent) -{ - GtkWidget *dialog; - GFileInfo *file_info; - const gchar *display_name; - const gchar *primary_text; - GError *error = NULL; - - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - g_return_if_fail (G_IS_ASYNC_RESULT (result)); - g_return_if_fail (GTK_IS_WINDOW (parent)); - - if (e_attachment_open_finish (attachment, result, &error)) - return; - - /* Ignore cancellations. */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - file_info = e_attachment_get_file_info (attachment); - - if (file_info != NULL) - display_name = g_file_info_get_display_name (file_info); - else - display_name = NULL; - - if (display_name != NULL) - primary_text = g_strdup_printf ( - _("Could not open '%s'"), display_name); - else - primary_text = g_strdup_printf ( - _("Could not open the attachment")); - - dialog = gtk_message_dialog_new_with_markup ( - parent, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "%s", primary_text); - - gtk_message_dialog_format_secondary_text ( - GTK_MESSAGE_DIALOG (dialog), "%s", error->message); - - gtk_dialog_run (GTK_DIALOG (dialog)); - - gtk_widget_destroy (dialog); - g_error_free (error); -} - -gboolean -e_attachment_open (EAttachment *attachment, - GAppInfo *app_info, - GError **error) -{ - EAsyncClosure *closure; - GAsyncResult *result; - gboolean success; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - - closure = e_async_closure_new (); - - e_attachment_open_async (attachment, app_info, e_async_closure_callback, closure); - - result = e_async_closure_wait (closure); - - success = e_attachment_open_finish (attachment, result, error); - - e_async_closure_free (closure); - - return success; -} - -/************************* e_attachment_save_async() *************************/ - -typedef struct _SaveContext SaveContext; - -struct _SaveContext { - EAttachment *attachment; - GSimpleAsyncResult *simple; - - GFile *directory; - GFile *destination; - GInputStream *input_stream; - GOutputStream *output_stream; - goffset total_num_bytes; - gssize bytes_read; - gchar buffer[4096]; - gint count; -}; - -/* Forward Declaration */ -static void -attachment_save_read_cb (GInputStream *input_stream, - GAsyncResult *result, - SaveContext *save_context); - -static SaveContext * -attachment_save_context_new (EAttachment *attachment, - GAsyncReadyCallback callback, - gpointer user_data) -{ - SaveContext *save_context; - GSimpleAsyncResult *simple; - - simple = g_simple_async_result_new ( - G_OBJECT (attachment), callback, - user_data, e_attachment_save_async); - - save_context = g_slice_new0 (SaveContext); - save_context->attachment = g_object_ref (attachment); - save_context->simple = simple; - - attachment_set_saving (save_context->attachment, TRUE); - - return save_context; -} - -static void -attachment_save_context_free (SaveContext *save_context) -{ - g_object_unref (save_context->attachment); - g_object_unref (save_context->simple); - - if (save_context->directory != NULL) - g_object_unref (save_context->directory); - - if (save_context->destination != NULL) - g_object_unref (save_context->destination); - - if (save_context->input_stream != NULL) - g_object_unref (save_context->input_stream); - - if (save_context->output_stream != NULL) - g_object_unref (save_context->output_stream); - - g_slice_free (SaveContext, save_context); -} - -static gboolean -attachment_save_check_for_error (SaveContext *save_context, - GError *error) -{ - GSimpleAsyncResult *simple; - - if (error == NULL) - return FALSE; - - simple = save_context->simple; - g_simple_async_result_take_error (simple, error); - g_simple_async_result_complete (simple); - - attachment_save_context_free (save_context); - - return TRUE; -} - -static GFile * -attachment_save_new_candidate (SaveContext *save_context) -{ - GFile *candidate; - GFileInfo *file_info; - EAttachment *attachment; - const gchar *display_name = NULL; - gchar *basename; - - attachment = save_context->attachment; - file_info = e_attachment_get_file_info (attachment); - - if (file_info != NULL) - display_name = g_file_info_get_display_name (file_info); - if (display_name == NULL) - /* 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); - } - - save_context->count++; - - candidate = g_file_get_child (save_context->directory, basename); - - g_free (basename); - - return candidate; -} - -static void -attachment_save_write_cb (GOutputStream *output_stream, - GAsyncResult *result, - SaveContext *save_context) -{ - EAttachment *attachment; - GCancellable *cancellable; - GInputStream *input_stream; - gssize bytes_written; - GError *error = NULL; - - bytes_written = g_output_stream_write_finish ( - output_stream, result, &error); - - if (attachment_save_check_for_error (save_context, error)) - return; - - attachment = save_context->attachment; - cancellable = attachment->priv->cancellable; - input_stream = save_context->input_stream; - - if (bytes_written < save_context->bytes_read) { - g_memmove ( - save_context->buffer, - save_context->buffer + bytes_written, - save_context->bytes_read - bytes_written); - save_context->bytes_read -= bytes_written; - - g_output_stream_write_async ( - output_stream, - save_context->buffer, - save_context->bytes_read, - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_save_write_cb, - save_context); - } else - 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); -} - -static void -attachment_save_read_cb (GInputStream *input_stream, - GAsyncResult *result, - SaveContext *save_context) -{ - EAttachment *attachment; - GCancellable *cancellable; - GOutputStream *output_stream; - gssize bytes_read; - GError *error = NULL; - - bytes_read = g_input_stream_read_finish ( - input_stream, result, &error); - - if (attachment_save_check_for_error (save_context, error)) - 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); - - return; - } - - attachment = save_context->attachment; - cancellable = attachment->priv->cancellable; - output_stream = save_context->output_stream; - save_context->bytes_read = bytes_read; - - attachment_progress_cb ( - g_seekable_tell (G_SEEKABLE (input_stream)), - save_context->total_num_bytes, attachment); - - g_output_stream_write_async ( - output_stream, - save_context->buffer, - save_context->bytes_read, - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) attachment_save_write_cb, - save_context); -} - -static void -attachment_save_got_output_stream (SaveContext *save_context) -{ - GCancellable *cancellable; - GInputStream *input_stream; - CamelDataWrapper *wrapper; - CamelMimePart *mime_part; - CamelStream *stream; - EAttachment *attachment; - GByteArray *buffer; - - attachment = save_context->attachment; - cancellable = attachment->priv->cancellable; - mime_part = e_attachment_get_mime_part (attachment); - - /* Decode the MIME part to an in-memory buffer. We have to do - * this because CamelStream is synchronous-only, and using threads - * is dangerous because CamelDataWrapper is not reentrant. */ - buffer = g_byte_array_new (); - stream = camel_stream_mem_new (); - camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (stream), buffer); - wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); - 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); - - 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); -} - -static void -attachment_save_create_cb (GFile *destination, - GAsyncResult *result, - SaveContext *save_context) -{ - EAttachment *attachment; - GCancellable *cancellable; - GFileOutputStream *output_stream; - GError *error = NULL; - - /* Output stream might be NULL, so don't use cast macro. */ - output_stream = g_file_create_finish (destination, result, &error); - save_context->output_stream = (GOutputStream *) output_stream; - - attachment = save_context->attachment; - cancellable = attachment->priv->cancellable; - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { - 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); - - g_object_unref (destination); - g_error_free (error); - return; - } - - if (attachment_save_check_for_error (save_context, error)) - return; - - save_context->destination = g_object_ref (destination); - attachment_save_got_output_stream (save_context); -} - -static void -attachment_save_replace_cb (GFile *destination, - GAsyncResult *result, - SaveContext *save_context) -{ - GFileOutputStream *output_stream; - GError *error = NULL; - - /* Output stream might be NULL, so don't use cast macro. */ - output_stream = g_file_replace_finish (destination, result, &error); - save_context->output_stream = (GOutputStream *) output_stream; - - if (attachment_save_check_for_error (save_context, error)) - return; - - save_context->destination = g_object_ref (destination); - attachment_save_got_output_stream (save_context); -} - -static void -attachment_save_query_info_cb (GFile *destination, - GAsyncResult *result, - SaveContext *save_context) -{ - EAttachment *attachment; - GCancellable *cancellable; - GFileInfo *file_info; - GFileType file_type; - GError *error = NULL; - - attachment = save_context->attachment; - cancellable = attachment->priv->cancellable; - - file_info = g_file_query_info_finish (destination, result, &error); - - /* G_IO_ERROR_NOT_FOUND just means we're creating a new file. */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { - g_error_free (error); - goto replace; - } - - if (attachment_save_check_for_error (save_context, error)) - return; - - file_type = g_file_info_get_file_type (file_info); - g_object_unref (file_info); - - 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); - - g_object_unref (destination); - - 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); -} - -void -e_attachment_save_async (EAttachment *attachment, - GFile *destination, - GAsyncReadyCallback callback, - gpointer user_data) -{ - SaveContext *save_context; - GCancellable *cancellable; - - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - g_return_if_fail (G_IS_FILE (destination)); - - if (e_attachment_get_loading (attachment)) { - g_simple_async_report_error_in_idle ( - G_OBJECT (attachment), callback, user_data, - G_IO_ERROR, G_IO_ERROR_BUSY, - _("A load operation is already in progress")); - return; - } - - if (e_attachment_get_saving (attachment)) { - g_simple_async_report_error_in_idle ( - G_OBJECT (attachment), callback, user_data, - G_IO_ERROR, G_IO_ERROR_BUSY, - _("A save operation is already in progress")); - return; - } - - if (e_attachment_get_mime_part (attachment) == NULL) { - g_simple_async_report_error_in_idle ( - G_OBJECT (attachment), callback, user_data, - G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Attachment contents not loaded")); - return; - } - - save_context = attachment_save_context_new ( - attachment, callback, user_data); - - cancellable = attachment->priv->cancellable; - g_cancellable_reset (cancellable); - - /* First we need to know if destination is a directory. */ - g_file_query_info_async ( - destination, G_FILE_ATTRIBUTE_STANDARD_TYPE, - G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, - cancellable, (GAsyncReadyCallback) - attachment_save_query_info_cb, save_context); -} - -GFile * -e_attachment_save_finish (EAttachment *attachment, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - GFile *destination; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - destination = g_simple_async_result_get_op_res_gpointer (simple); - if (destination != NULL) - g_object_ref (destination); - g_simple_async_result_propagate_error (simple, error); - - attachment_set_saving (attachment, FALSE); - - return destination; -} - -void -e_attachment_save_handle_error (EAttachment *attachment, - GAsyncResult *result, - GtkWindow *parent) -{ - GFile *file; - GFileInfo *file_info; - GtkWidget *dialog; - const gchar *display_name; - const gchar *primary_text; - GError *error = NULL; - - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - g_return_if_fail (G_IS_ASYNC_RESULT (result)); - g_return_if_fail (GTK_IS_WINDOW (parent)); - - file = e_attachment_save_finish (attachment, result, &error); - - if (file != NULL) { - g_object_unref (file); - return; - } - - /* Ignore cancellations. */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - file_info = e_attachment_get_file_info (attachment); - - if (file_info != NULL) - display_name = g_file_info_get_display_name (file_info); - else - display_name = NULL; - - if (display_name != NULL) - primary_text = g_strdup_printf ( - _("Could not save '%s'"), display_name); - else - primary_text = g_strdup_printf ( - _("Could not save the attachment")); - - dialog = gtk_message_dialog_new_with_markup ( - parent, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "%s", primary_text); - - gtk_message_dialog_format_secondary_text ( - GTK_MESSAGE_DIALOG (dialog), "%s", error->message); - - gtk_dialog_run (GTK_DIALOG (dialog)); - - gtk_widget_destroy (dialog); - g_error_free (error); -} - -gboolean -e_attachment_save (EAttachment *attachment, - GFile *in_destination, - GFile **out_destination, - GError **error) -{ - EAsyncClosure *closure; - GAsyncResult *result; - - g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); - g_return_val_if_fail (out_destination != NULL, FALSE); - - closure = e_async_closure_new (); - - e_attachment_save_async (attachment, in_destination, e_async_closure_callback, closure); - - result = e_async_closure_wait (closure); - - *out_destination = e_attachment_save_finish (attachment, result, error); - - e_async_closure_free (closure); - - return *out_destination != NULL; -} -- cgit v1.2.3