diff options
Diffstat (limited to 'widgets')
-rw-r--r-- | widgets/misc/ChangeLog | 14 | ||||
-rw-r--r-- | widgets/misc/e-attachment-bar.c | 31 | ||||
-rw-r--r-- | widgets/misc/e-attachment.c | 303 | ||||
-rw-r--r-- | widgets/misc/e-attachment.h | 5 | ||||
-rw-r--r-- | widgets/misc/e-image-chooser.c | 40 |
5 files changed, 235 insertions, 158 deletions
diff --git a/widgets/misc/ChangeLog b/widgets/misc/ChangeLog index dd708047a7..608a0db842 100644 --- a/widgets/misc/ChangeLog +++ b/widgets/misc/ChangeLog @@ -1,3 +1,17 @@ +2008-04-17 Milan Crha <mcrha@redhat.com> + + ** Part of fix for bug #526739 + + * e-attachment.h: (struct _EAttachment): + * e-attachment.c: (finalise), (init), (attachment_guess_mime_type), + (e_attachment_new), (struct DownloadInfo), (download_info_free), + (data_ready_cb), (download_to_local_path), + (e_attachment_new_remote_file): + Use gio instead of gnome-vfs to download remote files. + * e-image-chooser.c: (image_drag_data_received_cb): + Use new util function to read file. + * e-attachment-bar.c: (size_to_string): Stolen from gnome-vfs. + 2008-04-14 Matthew Barnes <mbarnes@redhat.com> * e-attachment-bar.c diff --git a/widgets/misc/e-attachment-bar.c b/widgets/misc/e-attachment-bar.c index ac25f628dd..0ef3ba21f7 100644 --- a/widgets/misc/e-attachment-bar.c +++ b/widgets/misc/e-attachment-bar.c @@ -33,7 +33,6 @@ #include <gconf/gconf.h> #include <gconf/gconf-client.h> #include <gdk/gdkkeysyms.h> -#include <libgnomevfs/gnome-vfs-mime-handlers.h> #include <glib/gi18n.h> #include <libgnome/libgnome.h> @@ -95,15 +94,31 @@ static void update (EAttachmentBar *bar); static char * size_to_string (gulong size) { - char *size_string; + /* code copied from gnome-vfs */ + #define KILOBYTE_FACTOR 1024.0 + #define MEGABYTE_FACTOR (1024.0 * 1024.0) + #define GIGABYTE_FACTOR (1024.0 * 1024.0 * 1024.0) - /* FIXME: The following should probably go into a separate module, as - we might have to do the same thing in other places as well. Also, - I am not sure this will be OK for all the languages. */ - - size_string = gnome_vfs_format_file_size_for_display (size); + if (size < (gulong) KILOBYTE_FACTOR) { + return g_strdup_printf (ngettext ("%u byte", "%u bytes",(guint) size), (guint) size); + } else { + gdouble displayed_size; + + if (size < (gulong) MEGABYTE_FACTOR) { + displayed_size = (gdouble) size / KILOBYTE_FACTOR; + return g_strdup_printf (_("%.1f KB"), displayed_size); + } else if (size < (gulong) GIGABYTE_FACTOR) { + displayed_size = (gdouble) size / MEGABYTE_FACTOR; + return g_strdup_printf (_("%.1f MB"), displayed_size); + } else { + displayed_size = (gdouble) size / GIGABYTE_FACTOR; + return g_strdup_printf (_("%.1f GB"), displayed_size); + } + } - return size_string; + #undef KILOBYTE_FACTOR + #undef MEGABYTE_FACTOR + #undef GIGABYTE_FACTOR } /* Attachment handling functions. */ 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; } diff --git a/widgets/misc/e-attachment.h b/widgets/misc/e-attachment.h index 3b03a0aa72..d2cf892c11 100644 --- a/widgets/misc/e-attachment.h +++ b/widgets/misc/e-attachment.h @@ -31,7 +31,7 @@ #include <camel/camel-mime-part.h> #include <camel/camel-exception.h> #include <camel/camel-cipher-context.h> -#include <libgnomevfs/gnome-vfs.h> +#include <gio/gio.h> #ifdef __cplusplus extern "C" { @@ -59,7 +59,8 @@ struct _EAttachment { GdkPixbuf *pixbuf_cache; - GnomeVFSAsyncHandle *handle; + GCancellable *cancellable; + gboolean is_available_local; int percentage; char *file_name; diff --git a/widgets/misc/e-image-chooser.c b/widgets/misc/e-image-chooser.c index 5dae27527f..f3fb4070ba 100644 --- a/widgets/misc/e-image-chooser.c +++ b/widgets/misc/e-image-chooser.c @@ -29,12 +29,12 @@ #include <gtk/gtkbutton.h> #include <gtk/gtkdnd.h> -#include <libgnomevfs/gnome-vfs-ops.h> #include <glib/gi18n.h> #include "e-image-chooser.h" #include "e-util/e-util-marshal.h" #include "e-util/e-icon-factory.h" +#include "e-util/e-util.h" struct _EImageChooserPrivate { @@ -409,46 +409,30 @@ image_drag_data_received_cb (GtkWidget *widget, target_type = gdk_atom_name (selection_data->target); if (!strcmp (target_type, URI_LIST_TYPE)) { - GnomeVFSResult result; - GnomeVFSHandle *handle; + GError *error = NULL; char *uri; char *nl = strstr ((char *)selection_data->data, "\r\n"); char *buf = NULL; - /* Why can't we change the info parameter to a GnomeVFSFileInfo and use that? */ - GnomeVFSFileInfo file_info; + gsize read = 0; if (nl) uri = g_strndup ((char *)selection_data->data, nl - (char*)selection_data->data); else uri = g_strdup ((char *)selection_data->data); - result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ); - if (result == GNOME_VFS_OK) { - result = gnome_vfs_get_file_info_from_handle (handle, &file_info, GNOME_VFS_FILE_INFO_DEFAULT); - if (result == GNOME_VFS_OK) { - GnomeVFSFileSize num_read; - - buf = g_malloc (file_info.size); - - if ((result = gnome_vfs_read (handle, buf, file_info.size, &num_read)) == GNOME_VFS_OK) { - if (set_image_from_data (chooser, buf, num_read)) { - handled = TRUE; - } else { - /* XXX we should pop up a warning dialog here */ - g_free (buf); - } - } else { - g_free (buf); - } + if (e_util_read_file (uri, TRUE, &buf, &read, &error) && read > 0 && buf) { + if (set_image_from_data (chooser, buf, read)) { + handled = TRUE; } - - gnome_vfs_close (handle); - } - else { - printf ("gnome_vfs_open failed (%s)\n", gnome_vfs_result_to_string (result)); } + g_free (buf); g_free (uri); + + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + } } gtk_drag_finish (context, handled, FALSE, time); |