From b25b709bf7fa81751810567af26ba4e8fe416b3a Mon Sep 17 00:00:00 2001 From: Srininvasa Ragavan Date: Mon, 23 May 2005 07:10:03 +0000 Subject: Added attachment of remote URL. The dnd of url, downloads the files and 2005-05-23 Srininvasa Ragavan * e-msg-composer-attachment-bar.c, e-msg-composer-attachment-bar.h, e-msg-composer-attachment.c, e-msg-composer-attachment.h, e-msg-composer.c, e-msg-composer.h, mail-composer.error.xml : Added attachment of remote URL. The dnd of url, downloads the files and attaches to the mail. svn path=/trunk/; revision=29399 --- composer/ChangeLog | 8 ++ composer/e-msg-composer-attachment-bar.c | 183 ++++++++++++++++++++++++- composer/e-msg-composer-attachment-bar.h | 3 + composer/e-msg-composer-attachment.c | 228 ++++++++++++++++++++++++++----- composer/e-msg-composer-attachment.h | 16 +++ composer/e-msg-composer.c | 26 +++- composer/e-msg-composer.h | 2 + composer/mail-composer.error.xml | 7 + 8 files changed, 433 insertions(+), 40 deletions(-) (limited to 'composer') diff --git a/composer/ChangeLog b/composer/ChangeLog index f635ebce9e..e31e66e2ad 100644 --- a/composer/ChangeLog +++ b/composer/ChangeLog @@ -1,3 +1,11 @@ +2005-05-23 Srininvasa Ragavan + + * e-msg-composer-attachment-bar.c, e-msg-composer-attachment-bar.h, + e-msg-composer-attachment.c, e-msg-composer-attachment.h, e-msg-composer.c, + e-msg-composer.h, mail-composer.error.xml : Added attachment of remote URL. + The dnd of url, downloads the files and attaches to the mail. + + 2005-05-16 Srinivasa Ragavan * e-msg-composer.c (set_editor_text) (menu_edit_delete_all_cb) diff --git a/composer/e-msg-composer-attachment-bar.c b/composer/e-msg-composer-attachment-bar.c index dde51106ec..7f15137e6a 100644 --- a/composer/e-msg-composer-attachment-bar.c +++ b/composer/e-msg-composer-attachment-bar.c @@ -52,6 +52,7 @@ #include "e-util/e-gui-utils.h" #include "e-util/e-icon-factory.h" #include "e-util/e-error.h" +#include "e-util/e-mktemp.h" #include "mail/em-popup.h" #define ICON_WIDTH 64 @@ -70,6 +71,7 @@ struct _EMsgComposerAttachmentBarPrivate { GList *attachments; guint num_attachments; + gchar *path; }; @@ -223,10 +225,20 @@ update (EMsgComposerAttachmentBar *bar) EMsgComposerAttachment *attachment; CamelContentType *content_type; char *size_string, *label; - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf=NULL; const char *desc; attachment = p->data; + + if (!attachment->is_available_local) { + /* stock_attach would be better, but its fugly scaled up */ + pixbuf = e_icon_factory_get_icon("stock_unknown", E_ICON_SIZE_DIALOG); + if (pixbuf) { + attachment->index = gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, ""); + g_object_unref(pixbuf); + } + continue; + } content_type = camel_mime_part_get_content_type (attachment->body); /* Get the image out of the attachment and create a thumbnail for it */ @@ -325,6 +337,27 @@ update (EMsgComposerAttachmentBar *bar) gnome_icon_list_thaw (icon_list); } +static void +update_remote_file (EMsgComposerAttachmentBar *bar, EMsgComposerAttachment *attachment, char *msg) +{ + EMsgComposerAttachmentBarPrivate *priv; + GnomeIconList *icon_list; + GnomeIconTextItem *item; + + priv = bar->priv; + icon_list = GNOME_ICON_LIST (bar); + + gnome_icon_list_freeze (icon_list); + + item = gnome_icon_list_get_icon_text_item (icon_list, attachment->index); + if (!item->is_text_allocated) + g_free (item->text); + + gnome_icon_text_item_configure (item, item->x, item->y, item->width, item->fontname, msg, item->is_editable, TRUE); + + gnome_icon_list_thaw (icon_list); +} + static void remove_selected (EMsgComposerAttachmentBar *bar) { @@ -540,6 +573,9 @@ destroy (GtkObject *object) if (bar->priv->attach) gtk_widget_destroy(bar->priv->attach); + if (bar->priv->path) + g_free (bar->priv->path); + g_free (bar->priv); bar->priv = NULL; } @@ -637,6 +673,7 @@ init (EMsgComposerAttachmentBar *bar) priv->attach = NULL; priv->attachments = NULL; priv->num_attachments = 0; + priv->path = NULL; bar->priv = priv; } @@ -815,7 +852,8 @@ e_msg_composer_attachment_bar_to_multipart (EMsgComposerAttachmentBar *bar, EMsgComposerAttachment *attachment; attachment = E_MSG_COMPOSER_ATTACHMENT (p->data); - attach_to_multipart (multipart, attachment, default_charset); + if (attachment->is_available_local) + attach_to_multipart (multipart, attachment, default_charset); } } @@ -842,6 +880,147 @@ e_msg_composer_attachment_bar_attach (EMsgComposerAttachmentBar *bar, add_from_file (bar, file_name, "attachment"); } +typedef struct DownloadInfo { + EMsgComposerAttachment *attachment; + EMsgComposerAttachmentBar *bar; + gchar *file_name; +}DownloadInfo; + +static int +async_progress_update_cb (GnomeVFSAsyncHandle *handle, + GnomeVFSXferProgressInfo *info, + DownloadInfo *download_info) +{ + int percent=0; + switch (info->status) { + case GNOME_VFS_XFER_PROGRESS_STATUS_OK: + { + gchar *base_path = g_path_get_basename(download_info->attachment->file_name); + if (info->file_size) { + percent = info->bytes_copied*100/info->file_size; + update_remote_file (download_info->bar, + download_info->attachment, + g_strdup_printf("%s (%d\%)", base_path, percent)); + } else { + update_remote_file (download_info->bar, + download_info->attachment, + g_strdup_printf("%s (%d\%)", base_path, percent)); + } + g_free (base_path); + + if (info->phase == GNOME_VFS_XFER_PHASE_COMPLETED) { + CamelException ex; + + download_info->attachment->is_available_local = TRUE; + download_info->attachment->handle = NULL; + camel_exception_init (&ex); + e_msg_composer_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex); + update(download_info->bar); + g_free (download_info->file_name); + g_free (download_info); + } + return TRUE; + break; + } + case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR: + gnome_vfs_async_cancel (handle); + g_free (download_info->file_name); + g_free (download_info); + return FALSE; + break; + + default: + break; + } + + return TRUE; +} + +static void +download_to_local_path (GnomeVFSURI *source_uri, GnomeVFSURI *target_uri, DownloadInfo *download_info) + +{ + GnomeVFSResult result; + GList *source_uri_list = NULL; + GList *target_uri_list = NULL; + + source_uri_list = g_list_prepend (source_uri_list, source_uri); + target_uri_list = g_list_prepend (target_uri_list, target_uri); + + /* Callback info */ + result = 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 */ + async_progress_update_cb, /* progress_update_callback */ + download_info, /* update_callback_data */ + NULL, /* progress_sync_callback */ + NULL); /* sync_callback_data */ +} + + +int +e_msg_composer_attachment_bar_get_download_count (EMsgComposerAttachmentBar *bar) +{ + EMsgComposerAttachmentBarPrivate *priv; + GList *p; + int count=0; + + priv = bar->priv; + + for (p = priv->attachments; p != NULL; p = p->next) { + EMsgComposerAttachment *attachment; + + attachment = p->data; + if (!attachment->is_available_local) + count++; + } + + return count; +} + +void +e_msg_composer_attachment_bar_attach_remote_file (EMsgComposerAttachmentBar *bar, + const gchar *url) +{ + EMsgComposerAttachment *attachment; + CamelException ex; + gchar *tmpfile; + gchar *base; + + if (!bar->priv->path) + bar->priv->path = e_mkdtemp("attach-XXXXXX"); + base = g_path_get_basename (url); + + g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (bar)); + tmpfile = g_build_filename (bar->priv->path, base, NULL); + + g_free (base); + + camel_exception_init (&ex); + attachment = e_msg_composer_attachment_new_remote_file (tmpfile, "attachment", &ex); + if (attachment) { + DownloadInfo *download_info; + download_info = g_new (DownloadInfo, 1); + download_info->attachment = attachment; + download_info->bar =bar; + download_info->file_name = g_strdup (tmpfile); + add_common (bar, attachment); + download_to_local_path (gnome_vfs_uri_new(url), gnome_vfs_uri_new(tmpfile), download_info); + + } else { + e_error_run((GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)bar), "mail-composer:no-attach", + attachment->file_name, camel_exception_get_description(&ex), NULL); + camel_exception_clear (&ex); + } + + g_free (tmpfile); + +} + void e_msg_composer_attachment_bar_attach_mime_part (EMsgComposerAttachmentBar *bar, CamelMimePart *part) diff --git a/composer/e-msg-composer-attachment-bar.h b/composer/e-msg-composer-attachment-bar.h index a43b466633..f87390db87 100644 --- a/composer/e-msg-composer-attachment-bar.h +++ b/composer/e-msg-composer-attachment-bar.h @@ -69,6 +69,9 @@ void e_msg_composer_attachment_bar_to_multipart (EMsgComposerAttachmentBar *bar, guint e_msg_composer_attachment_bar_get_num_attachments (EMsgComposerAttachmentBar *bar); void e_msg_composer_attachment_bar_attach (EMsgComposerAttachmentBar *bar, const char *file_name); void e_msg_composer_attachment_bar_attach_mime_part (EMsgComposerAttachmentBar *bar, CamelMimePart *part); +int e_msg_composer_attachment_bar_get_download_count (EMsgComposerAttachmentBar *bar); +void e_msg_composer_attachment_bar_attach_remote_file (EMsgComposerAttachmentBar *bar,const gchar *url); + #ifdef __cplusplus } diff --git a/composer/e-msg-composer-attachment.c b/composer/e-msg-composer-attachment.c index f4f173cee2..1c88e7a68f 100644 --- a/composer/e-msg-composer-attachment.c +++ b/composer/e-msg-composer-attachment.c @@ -73,12 +73,21 @@ finalise(GObject *object) EMsgComposerAttachment *attachment; attachment = E_MSG_COMPOSER_ATTACHMENT (object); - - camel_object_unref (attachment->body); - if (attachment->pixbuf_cache != NULL) - g_object_unref (attachment->pixbuf_cache); - - G_OBJECT_CLASS (parent_class)->finalize (object); + + if (attachment->is_available_local) { + camel_object_unref (attachment->body); + if (attachment->pixbuf_cache != NULL) + g_object_unref (attachment->pixbuf_cache); + + G_OBJECT_CLASS (parent_class)->finalize (object); + } else { + if (attachment->handle) + gnome_vfs_async_cancel(attachment->handle); + if (attachment->file_name) + g_free (attachment->file_name); + if (attachment->description) + g_free (attachment->description); + } } @@ -119,6 +128,10 @@ init (EMsgComposerAttachment *msg_composer_attachment) msg_composer_attachment->body = NULL; msg_composer_attachment->size = 0; msg_composer_attachment->pixbuf_cache = NULL; + msg_composer_attachment->index = -1; + msg_composer_attachment->file_name = NULL; + msg_composer_attachment->description = NULL; + msg_composer_attachment->disposition = FALSE; } GType @@ -236,10 +249,123 @@ e_msg_composer_attachment_new (const char *file_name, new->body = part; new->size = statbuf.st_size; new->guessed_type = TRUE; + new->handle = NULL; + new->is_available_local = TRUE; + + return new; +} + + +EMsgComposerAttachment * +e_msg_composer_attachment_new_remote_file (const char *file_name, + const char *disposition, + CamelException *ex) +{ + EMsgComposerAttachment *new; + + g_return_val_if_fail (file_name != NULL, NULL); + + new = g_object_new (E_TYPE_MSG_COMPOSER_ATTACHMENT, NULL); + new->editor_gui = NULL; + new->body = NULL; + new->size = 0; + new->guessed_type = FALSE; + new->handle = NULL; + new->is_available_local = FALSE; + new->file_name = g_path_get_basename(file_name); return new; } +void +e_msg_composer_attachment_build_remote_file (const char *file_name, + EMsgComposerAttachment *attachment, + const char *disposition, + CamelException *ex) +{ + CamelMimePart *part; + CamelDataWrapper *wrapper; + CamelStream *stream; + struct stat statbuf; + char *mime_type; + char *filename; + + g_return_if_fail (file_name != NULL); + + if (stat (file_name, &statbuf) < 0) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot attach file %s: %s"), + file_name, g_strerror (errno)); + return; + } + + /* return if it's not a regular file */ + if (!S_ISREG (statbuf.st_mode)) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot attach file %s: not a regular file"), + file_name); + return; + } + + stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0); + if (!stream) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot attach file %s: %s"), + file_name, g_strerror (errno)); + return; + } + + mime_type = e_msg_composer_guess_mime_type (file_name); + if (mime_type) { + if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) { + wrapper = (CamelDataWrapper *) camel_mime_message_new (); + } else { + wrapper = camel_data_wrapper_new (); + } + + camel_data_wrapper_construct_from_stream (wrapper, stream); + camel_data_wrapper_set_mime_type (wrapper, mime_type); + g_free (mime_type); + } else { + wrapper = camel_data_wrapper_new (); + camel_data_wrapper_construct_from_stream (wrapper, stream); + camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream"); + } + + camel_object_unref (stream); + + part = camel_mime_part_new (); + camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper); + camel_object_unref (wrapper); + + if (attachment->disposition) + camel_mime_part_set_disposition (part, "inline"); + else + camel_mime_part_set_disposition (part, "attachment"); + + if (!attachment->file_name) + filename = g_path_get_basename (file_name); + else + filename = g_path_get_basename (attachment->file_name); + + camel_mime_part_set_filename (part, filename); + g_free (filename); + + if (attachment->description) { + camel_mime_part_set_description (part, attachment->description); + g_free (attachment->description); + attachment->description = NULL; + } + + attachment->editor_gui = NULL; + attachment->body = part; + attachment->size = statbuf.st_size; + attachment->guessed_type = TRUE; + if (attachment->file_name) { + g_free (attachment->file_name); + attachment->file_name = NULL; + } +} /** * e_msg_composer_attachment_new_from_mime_part: @@ -357,26 +483,43 @@ ok_cb (GtkWidget *widget, gpointer data) attachment = dialog_data->attachment; str = gtk_entry_get_text (dialog_data->file_name_entry); - camel_mime_part_set_filename (attachment->body, str); + if (attachment->is_available_local) { + camel_mime_part_set_filename (attachment->body, str); + } else { + if (attachment->file_name) + g_free (attachment->file_name); + attachment->file_name = g_strdup (str); + } str = gtk_entry_get_text (dialog_data->description_entry); - camel_mime_part_set_description (attachment->body, str); + if (attachment->is_available_local) { + camel_mime_part_set_description (attachment->body, str); + } else { + if (attachment->description) + g_free (attachment->description); + attachment->description = g_strdup (str); + } str = gtk_entry_get_text (dialog_data->mime_type_entry); - camel_mime_part_set_content_type (attachment->body, str); - - camel_data_wrapper_set_mime_type(camel_medium_get_content_object(CAMEL_MEDIUM (attachment->body)), str); - - switch (gtk_toggle_button_get_active (dialog_data->disposition_checkbox)) { - case 0: - camel_mime_part_set_disposition (attachment->body, "attachment"); - break; - case 1: - camel_mime_part_set_disposition (attachment->body, "inline"); - break; - default: - /* Hmmmm? */ - break; + if (attachment->is_available_local) { + camel_mime_part_set_content_type (attachment->body, str); + camel_data_wrapper_set_mime_type(camel_medium_get_content_object(CAMEL_MEDIUM (attachment->body)), str); + } + + if (attachment->is_available_local) { + switch (gtk_toggle_button_get_active (dialog_data->disposition_checkbox)) { + case 0: + camel_mime_part_set_disposition (attachment->body, "attachment"); + break; + case 1: + camel_mime_part_set_disposition (attachment->body, "inline"); + break; + default: + /* Hmmmm? */ + break; + } + } else { + attachment->disposition = gtk_toggle_button_get_active (dialog_data->disposition_checkbox); } changed (attachment); @@ -438,19 +581,36 @@ e_msg_composer_attachment_edit (EMsgComposerAttachment *attachment, GtkWidget *p glade_xml_get_widget (editor_gui, "mime_type_entry")); dialog_data->disposition_checkbox = GTK_TOGGLE_BUTTON ( glade_xml_get_widget (editor_gui, "disposition_checkbox")); + + if (attachment->is_available_local) { + set_entry (editor_gui, "file_name_entry", + camel_mime_part_get_filename (attachment->body)); + set_entry (editor_gui, "description_entry", + camel_mime_part_get_description (attachment->body)); + content_type = camel_mime_part_get_content_type (attachment->body); + type = camel_content_type_simple (content_type); + set_entry (editor_gui, "mime_type_entry", type); + g_free (type); + + disposition = camel_mime_part_get_disposition (attachment->body); + gtk_toggle_button_set_active (dialog_data->disposition_checkbox, + disposition && !g_ascii_strcasecmp (disposition, "inline")); + } else { + set_entry (editor_gui, "file_name_entry", + attachment->file_name); + set_entry (editor_gui, "description_entry", + attachment->description); + type = e_msg_composer_guess_mime_type (attachment->file_name); + if (type) { + set_entry (editor_gui, "mime_type_entry", type); + g_free (type); + } else { + set_entry (editor_gui, "mime_type_entry", ""); + } - set_entry (editor_gui, "file_name_entry", - camel_mime_part_get_filename (attachment->body)); - set_entry (editor_gui, "description_entry", - camel_mime_part_get_description (attachment->body)); - content_type = camel_mime_part_get_content_type (attachment->body); - type = camel_content_type_simple (content_type); - set_entry (editor_gui, "mime_type_entry", type); - g_free (type); - - disposition = camel_mime_part_get_disposition (attachment->body); - gtk_toggle_button_set_active (dialog_data->disposition_checkbox, - disposition && !g_ascii_strcasecmp (disposition, "inline")); + gtk_toggle_button_set_active (dialog_data->disposition_checkbox, attachment->disposition); + + } connect_widget (editor_gui, "dialog", "response", (GCallback)response_cb, dialog_data); #warning "signal connect while alive" diff --git a/composer/e-msg-composer-attachment.h b/composer/e-msg-composer-attachment.h index caef6ebc58..d287a00dbf 100644 --- a/composer/e-msg-composer-attachment.h +++ b/composer/e-msg-composer-attachment.h @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -53,6 +54,13 @@ struct _EMsgComposerAttachment { gulong size; GdkPixbuf *pixbuf_cache; + + GnomeVFSAsyncHandle *handle; + gboolean is_available_local; + char *file_name; + char *description; + gboolean disposition; + int index; }; struct _EMsgComposerAttachmentClass { @@ -66,9 +74,17 @@ GType e_msg_composer_attachment_get_type (void); EMsgComposerAttachment *e_msg_composer_attachment_new (const char *file_name, const char *disposition, CamelException *ex); +EMsgComposerAttachment * e_msg_composer_attachment_new_remote_file (const char *file_name, + const char *disposition, + CamelException *ex); +void e_msg_composer_attachment_build_remote_file (const char *filename, + EMsgComposerAttachment *attachment, + const char *disposition, + CamelException *ex); EMsgComposerAttachment *e_msg_composer_attachment_new_from_mime_part (CamelMimePart *part); void e_msg_composer_attachment_edit (EMsgComposerAttachment *attachment, GtkWidget *parent); + #ifdef __cplusplus } diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index 350b31c784..1240490b38 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -2679,6 +2679,13 @@ struct _drop_data { unsigned int aborted:1; }; +int +e_msg_composer_get_remote_download_count (EMsgComposer *composer) +{ + return e_msg_composer_attachment_bar_get_download_count + (E_MSG_COMPOSER_ATTACHMENT_BAR (composer->attachment_bar)); +} + static void drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, GtkSelectionData *selection, guint info, guint time) { @@ -2727,16 +2734,22 @@ drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, Gtk g_free (str); } else { url = camel_url_new (str, NULL); - g_free (str); - if (url == NULL) + if (url == NULL) { + g_free (str); continue; + } if (!g_ascii_strcasecmp (url->protocol, "file")) e_msg_composer_attachment_bar_attach (E_MSG_COMPOSER_ATTACHMENT_BAR (composer->attachment_bar), url->path); - + else { + e_msg_composer_attachment_bar_attach_remote_file + (E_MSG_COMPOSER_ATTACHMENT_BAR (composer->attachment_bar), + str); + } + g_free (str); camel_url_free (url); } } @@ -4687,6 +4700,11 @@ CamelMimeMessage * e_msg_composer_get_message (EMsgComposer *composer, gboolean save_html_object_data) { g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); + if ( e_msg_composer_get_remote_download_count (composer) != 0) { + if (!em_utils_prompt_user((GtkWindow *)composer, NULL, "mail-composer:ask-send-message-pending-download", NULL)) { + return NULL; + } + } return build_message (composer, save_html_object_data); } @@ -4713,7 +4731,7 @@ e_msg_composer_get_message_draft (EMsgComposer *composer) old_flags[3] = composer->smime_encrypt; composer->smime_encrypt = FALSE; - msg = e_msg_composer_get_message (composer, TRUE); + msg = build_message (composer, TRUE); composer->send_html = old_send_html; composer->pgp_sign = old_flags[0]; diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h index 76d70e8a3b..279bd150f3 100644 --- a/composer/e-msg-composer.h +++ b/composer/e-msg-composer.h @@ -241,6 +241,8 @@ void e_msg_composer_drop_editor_undo (EMsgCo gboolean e_msg_composer_request_close_all (void); void e_msg_composer_check_autosave (GtkWindow *parent); +int e_msg_composer_get_remote_download_count (EMsgComposer *composer); + #ifdef __cplusplus } diff --git a/composer/mail-composer.error.xml b/composer/mail-composer.error.xml index aa00c122e7..58e56991e8 100644 --- a/composer/mail-composer.error.xml +++ b/composer/mail-composer.error.xml @@ -32,6 +32,13 @@ <_primary>Could not save to autosave file "{0}". <_secondary>Error saving to autosave because "{1}". + + + <_primary>Download in progress. Do you want to send the mail? + <_secondary xml:space="preserve"> There are few attachments getting downloaded. Sending the mail will cause the mail to be sent without those pending attachments +