aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc/e-attachment.c
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/misc/e-attachment.c')
-rw-r--r--widgets/misc/e-attachment.c303
1 files changed, 183 insertions, 120 deletions
diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c
index 1383335499..27729b396f 100644
--- a/widgets/misc/e-attachment.c
+++ b/widgets/misc/e-attachment.c
@@ -29,7 +29,7 @@
#include <glib.h>
#ifdef G_OS_WIN32
-/* Include <windows.h> early (as the gnome-vfs stuff below will
+/* Include <windows.h> early (as the gio stuff below will
* include it anyway, sigh) to workaround the DATADIR problem.
* <windows.h> (and the headers it includes) stomps all over the
* namespace like a baboon on crack, and especially the DATADIR enum
@@ -50,12 +50,13 @@
#include <gtk/gtknotebook.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkdialog.h>
-#include <libgnomevfs/gnome-vfs-mime.h>
+#include <gio/gio.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <libebook/e-vcard.h>
+#include "e-util/e-util.h"
#include "e-util/e-error.h"
#include "e-util/e-mktemp.h"
#include "e-util/e-util-private.h"
@@ -97,8 +98,11 @@ finalise (GObject *object)
if (attachment->pixbuf_cache != NULL)
g_object_unref (attachment->pixbuf_cache);
} else {
- if (attachment->handle)
- gnome_vfs_async_cancel(attachment->handle);
+ if (attachment->cancellable) {
+ /* the operation is still running, so cancel it */
+ g_cancellable_cancel (attachment->cancellable);
+ attachment->cancellable = NULL;
+ }
g_free (attachment->description);
}
@@ -170,6 +174,7 @@ init (EAttachment *attachment)
attachment->sign = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
attachment->encrypt = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
attachment->store_uri = NULL;
+ attachment->cancellable = NULL;
}
GType
@@ -226,57 +231,31 @@ file_ext_is (const char *file_name, const char *ext)
static char *
attachment_guess_mime_type (const char *file_name)
{
- GnomeVFSFileInfo *info;
- GnomeVFSResult result;
- char *type = NULL;
-
- info = gnome_vfs_file_info_new ();
- result = gnome_vfs_get_file_info (file_name, info,
- GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
- GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE |
- GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
-
- if (result != GNOME_VFS_OK) {
- CamelURL *url;
- char *uri;
-
- url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, file_name);
- uri = camel_url_to_string (url, 0);
- camel_url_free (url);
-
- result = gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE | GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
-
- g_free (uri);
- }
-
- if (result == GNOME_VFS_OK) {
- gchar *content = NULL;
+ char *type;
+ gchar *content = NULL;
- type = g_strdup (gnome_vfs_file_info_get_mime_type (info));
+ type = e_util_guess_mime_type (file_name);
- if (type && strcmp (type, "text/directory") == 0 &&
- file_ext_is (file_name, ".vcf") &&
- g_file_get_contents (file_name, &content, NULL, NULL) &&
- content) {
- EVCard *vc = e_vcard_new_from_string (content);
- if (vc) {
- g_free (type);
- g_object_unref (G_OBJECT (vc));
+ if (type && strcmp (type, "text/directory") == 0 &&
+ file_ext_is (file_name, ".vcf") &&
+ g_file_get_contents (file_name, &content, NULL, NULL) &&
+ content) {
+ EVCard *vc = e_vcard_new_from_string (content);
- type = g_strdup ("text/x-vcard");
- }
+ if (vc) {
+ g_free (type);
+ g_object_unref (G_OBJECT (vc));
+ type = g_strdup ("text/x-vcard");
}
- g_free (content);
}
- gnome_vfs_file_info_unref (info);
+ g_free (content);
if (type) {
- /* gnome_vfs can sometimes return invalid type, so check for it */
+ /* Check if returned mime_type is valid */
CamelContentType *ctype = camel_content_type_decode (type);
if (!ctype) {
@@ -376,7 +355,7 @@ e_attachment_new (const char *file_name, const char *disposition, CamelException
new->body = part;
new->size = statbuf.st_size;
new->guessed_type = TRUE;
- new->handle = NULL;
+ new->cancellable = NULL;
new->is_available_local = TRUE;
new->file_name = filename;
@@ -389,93 +368,173 @@ e_attachment_new (const char *file_name, const char *disposition, CamelException
}
-typedef struct DownloadInfo {
+typedef struct {
EAttachment *attachment;
char *file_name;
char *uri;
GtkWindow *parent; /* for error dialog */
+
+ guint64 file_size; /* zero indicates unknown size */
+ GInputStream *istream; /* read from here ... */
+ GOutputStream *ostream; /* ...and write into this. */
+ gboolean was_error;
+ GCancellable *cancellable;
+
+ void *buffer; /* read into this, not more than buffer_size bytes */
+ gsize buffer_size;
} DownloadInfo;
-static int
-async_progress_update_cb (GnomeVFSAsyncHandle *handle,
- GnomeVFSXferProgressInfo *info,
- DownloadInfo *download_info)
+static void
+download_info_free (DownloadInfo *download_info)
{
- switch (info->status) {
- case GNOME_VFS_XFER_PROGRESS_STATUS_OK:
- if (info->file_size) {
- download_info->attachment->percentage = info->bytes_copied*100/info->file_size;
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+ /* if there was an error, then free attachment too */
+ if (download_info->was_error)
+ g_object_unref (download_info->attachment);
+
+ if (download_info->ostream)
+ g_object_unref (download_info->ostream);
+
+ if (download_info->istream)
+ g_object_unref (download_info->istream);
+
+ if (download_info->cancellable)
+ g_object_unref (download_info->cancellable);
+
+ g_free (download_info->file_name);
+ g_free (download_info->uri);
+ g_free (download_info->buffer);
+ g_free (download_info);
+}
+
+static void
+data_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ DownloadInfo *download_info = (DownloadInfo *)user_data;
+ GError *error = NULL;
+ gssize read;
+
+ g_return_if_fail (download_info != NULL);
+
+ if (g_cancellable_is_cancelled (download_info->cancellable)) {
+ /* finish the operation and close both streams */
+ g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, NULL);
+
+ g_output_stream_close (download_info->ostream, NULL, NULL);
+ g_input_stream_close (download_info->istream, NULL, NULL);
+
+ /* The only way how to get this canceled is in EAttachment's finalize method,
+ and because the download_info_free free's the attachment on error,
+ then do not consider cancellation as an error. */
+ download_info_free (download_info);
+ return;
+ }
+
+ read = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
+
+ if (!error)
+ g_output_stream_write_all (download_info->ostream, download_info->buffer, read, NULL, download_info->cancellable, &error);
+
+ if (error) {
+ download_info->was_error = error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED;
+ if (download_info->was_error)
+ e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, error->message, NULL);
+
+ g_error_free (error);
+
+ download_info->attachment->cancellable = NULL;
+ download_info_free (download_info);
+ return;
+ }
+
+ if (read == 0) {
+ CamelException ex;
+
+ /* done with reading */
+ g_output_stream_close (download_info->ostream, NULL, NULL);
+ g_input_stream_close (download_info->istream, NULL, NULL);
+
+ download_info->attachment->cancellable = NULL;
+
+ camel_exception_init (&ex);
+ e_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex);
+
+ if (camel_exception_is_set (&ex)) {
+ download_info->was_error = TRUE;
+ e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, camel_exception_get_description (&ex), NULL);
+ camel_exception_clear (&ex);
+ }
+
+ download_info->attachment->percentage = -1;
+ download_info->attachment->is_available_local = TRUE;
+ g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+
+ download_info_free (download_info);
+ return;
+ } else if (download_info->file_size) {
+ download_info->attachment->percentage = read * 100 / download_info->file_size;
+ download_info->file_size -= MIN (download_info->file_size, read);
+ g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+ } else {
+ download_info->attachment->percentage = 0;
+ g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+ }
+
+ /* read next chunk */
+ g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+}
+
+static gboolean
+download_to_local_path (DownloadInfo *download_info, CamelException *ex)
+{
+ GError *error = NULL;
+ GFile *src = g_file_new_for_uri (download_info->uri);
+ GFile *des = g_file_new_for_path (download_info->file_name);
+ gboolean res = FALSE;
+
+ g_return_val_if_fail (src != NULL && des != NULL, FALSE);
+
+ download_info->ostream = G_OUTPUT_STREAM (g_file_replace (des, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));
+
+ if (download_info->ostream && !error) {
+ GFileInfo *fi;
+
+ fi = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+
+ if (fi) {
+ download_info->file_size = g_file_info_get_attribute_uint64 (fi, G_FILE_ATTRIBUTE_STANDARD_SIZE);
+ g_object_unref (fi);
} else {
- download_info->attachment->percentage = 0;
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+ download_info->file_size = 0;
}
- if (info->phase == GNOME_VFS_XFER_PHASE_COMPLETED) {
- CamelException ex;
-
- if (!info->file_size) {
- if (info->vfs_status == GNOME_VFS_OK)
- info->vfs_status = GNOME_VFS_ERROR_EOF;
- goto error_msg;
- }
-
- download_info->attachment->handle = NULL;
- camel_exception_init (&ex);
- e_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex);
- if (camel_exception_is_set (&ex)) {
- e_error_run (download_info->parent, "mail-composer:no-attach",
- download_info->uri, camel_exception_get_description (&ex), NULL);
- camel_exception_clear (&ex);
- goto error;
- }
- download_info->attachment->percentage = -1;
- download_info->attachment->is_available_local = TRUE;
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
- g_free (download_info->file_name);
- g_free (download_info->uri);
- g_free (download_info);
+ download_info->istream = G_INPUT_STREAM (g_file_read (src, NULL, &error));
+
+ if (download_info->istream && !error) {
+ download_info->cancellable = g_cancellable_new ();
+ download_info->attachment->cancellable = download_info->cancellable;
+ download_info->buffer_size = 10240; /* max 10KB chunk */
+ download_info->buffer = g_malloc (sizeof (char) * download_info->buffer_size);
+
+ g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+
+ res = TRUE;
}
- return TRUE;
- case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR:
- error_msg:
- e_error_run (download_info->parent, "mail-composer:no-attach",
- download_info->uri, gnome_vfs_result_to_string (info->vfs_status), NULL);
- error:
- g_object_unref (download_info->attachment);
- g_free (download_info->file_name);
- g_free (download_info->uri);
- g_free (download_info);
- return FALSE;
- default:
- break;
}
- return TRUE;
-}
+ if (error) {
+ /* propagate error */
+ if (ex)
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, error->message);
-static void
-download_to_local_path (GnomeVFSURI *source_uri, GnomeVFSURI *target_uri, DownloadInfo *download_info)
+ g_error_free (error);
+ download_info->was_error = TRUE;
+ download_info_free (download_info);
+ }
-{
- GList *source_uri_list;
- GList *target_uri_list;
-
- source_uri_list = g_list_append (NULL, source_uri);
- target_uri_list = g_list_append (NULL, target_uri);
-
- /* Callback info */
- gnome_vfs_async_xfer (&download_info->attachment->handle, /* handle_return */
- source_uri_list, /* source_uri_list */
- target_uri_list, /* target_uri_list */
- GNOME_VFS_XFER_DEFAULT, /* xfer_options */
- GNOME_VFS_XFER_ERROR_MODE_ABORT, /* error_mode */
- GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, /* overwrite_mode */
- GNOME_VFS_PRIORITY_DEFAULT, /* priority */
- (GnomeVFSAsyncXferProgressCallback) async_progress_update_cb,
- download_info, /* update_callback_data */
- NULL, /* progress_sync_callback */
- NULL); /* sync_callback_data */
+ g_object_unref (src);
+ g_object_unref (des);
+
+ return res;
}
EAttachment *
@@ -497,19 +556,23 @@ e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, cons
new->body = NULL;
new->size = 0;
new->guessed_type = FALSE;
- new->handle = NULL;
+ new->cancellable = NULL;
new->is_available_local = FALSE;
new->percentage = 0;
new->file_name = g_build_filename (path, base, NULL);
g_free (base);
- download_info = g_new (DownloadInfo, 1);
+ download_info = g_new0 (DownloadInfo, 1);
download_info->attachment = new;
download_info->file_name = g_strdup (new->file_name);
download_info->uri = g_strdup (uri);
download_info->parent = error_dlg_parent;
- download_to_local_path (gnome_vfs_uri_new (uri), gnome_vfs_uri_new (new->file_name), download_info);
+ download_info->was_error = FALSE;
+
+ /* it frees all on the error, so do not free it twice */
+ if (!download_to_local_path (download_info, ex))
+ return NULL;
return new;
}