From b0ac33fbbe200997569e14574dd5aac746419bed Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sun, 21 Oct 2001 19:08:07 +0000 Subject: Make inline images used for replies not show up as attachments. Also, I think this should make replies to HTML messages containing inline images referenced via Content-Location work, but that's not tested. * e-msg-composer.c (various): Keep two hash tables of inline image data: one mapping from cid: URLs to CamelMimeParts for all attachments, the other mapping from file: and Content-Location urls to CamelMimeParts (for those inline images that came from a file or have a Content-Location). (add_inlined_images): Simplify. Most of this code is in e_msg_composer_add_inline_image_from_file() now. (e_msg_composer_add_message_attachments, handle_multipart): Change "attach_all" arg to "just_inlines". If it is set, call e_msg_composer_add_inline_image_from_mime_part on any attachment with a Content-Id or Content-Location. (e_msg_composer_add_inline_image_from_file): Create a mime part from a file and add it to the inline images hash. (e_msg_composer_add_inline_image_from_mime_part): Add a mime part directly to the inline images hash. * listener.c (resolve_image_url): If asked to resolve a file: URL that isn't in the inline images hash, call e_msg_composer_add_inline_image_from_file to get a cid for it. (impl_event): Look up the URL in the inline_images and inline_images_by_url hashes. * e-msg-composer-attachment-bar.c (e_msg_composer_attachment_bar_find_message): Gone. No longer used. svn path=/trunk/; revision=13852 --- composer/ChangeLog | 33 +++++++ composer/e-msg-composer-attachment-bar.c | 39 -------- composer/e-msg-composer-attachment-bar.h | 2 - composer/e-msg-composer.c | 158 ++++++++++++++++++++++--------- composer/e-msg-composer.h | 8 +- composer/listener.c | 68 ++++++------- 6 files changed, 183 insertions(+), 125 deletions(-) (limited to 'composer') diff --git a/composer/ChangeLog b/composer/ChangeLog index ddf610712b..612082dfe4 100644 --- a/composer/ChangeLog +++ b/composer/ChangeLog @@ -1,3 +1,36 @@ +2001-10-21 Dan Winship + + Make inline images used for replies not show up as + attachments. Also, I think this should make replies to HTML + messages containing inline images referenced via Content-Location + work, but that's not tested. + + * e-msg-composer.c (various): Keep two hash tables of inline image + data: one mapping from cid: URLs to CamelMimeParts for all + attachments, the other mapping from file: and Content-Location + urls to CamelMimeParts (for those inline images that came from a + file or have a Content-Location). + (add_inlined_images): Simplify. Most of this code is in + e_msg_composer_add_inline_image_from_file() now. + (e_msg_composer_add_message_attachments, handle_multipart): Change + "attach_all" arg to "just_inlines". If it is set, call + e_msg_composer_add_inline_image_from_mime_part on any attachment + with a Content-Id or Content-Location. + (e_msg_composer_add_inline_image_from_file): Create a mime part + from a file and add it to the inline images hash. + (e_msg_composer_add_inline_image_from_mime_part): Add a mime part + directly to the inline images hash. + + * listener.c (resolve_image_url): If asked to resolve a file: URL + that isn't in the inline images hash, call + e_msg_composer_add_inline_image_from_file to get a cid for it. + (impl_event): Look up the URL in the inline_images and + inline_images_by_url hashes. + + * e-msg-composer-attachment-bar.c + (e_msg_composer_attachment_bar_find_message): Gone. No longer + used. + 2001-10-19 Jeffrey Stedfast * e-msg-composer.c (handle_multipart): Now takes a 'attach_all' diff --git a/composer/e-msg-composer-attachment-bar.c b/composer/e-msg-composer-attachment-bar.c index 6619a59597..71562e9692 100644 --- a/composer/e-msg-composer-attachment-bar.c +++ b/composer/e-msg-composer-attachment-bar.c @@ -816,42 +816,3 @@ e_msg_composer_attachment_bar_attach_mime_part (EMsgComposerAttachmentBar *bar, add_from_mime_part (bar, part); } - -CamelMimePart * -e_msg_composer_attachment_bar_find_message (EMsgComposerAttachmentBar *bar, char *url) -{ - EMsgComposerAttachmentBarPrivate *priv; - GList *p; - char *content_id = NULL; - - g_return_val_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (bar), NULL); - g_return_val_if_fail (url != NULL, NULL); - - if (!strncmp ("cid:", url, 4)) - content_id = url + 4; - - priv = bar->priv; - - for (p = priv->attachments; p != NULL; p = p->next) { - CamelMimePart *part; - const char *part_id; - const char *part_location; - - part = E_MSG_COMPOSER_ATTACHMENT (p->data)->body; - - part_id = camel_mime_part_get_content_id (part); - g_warning ("content_id: %s, part_id: %s\n", content_id, part_id); - - if (content_id && part_id && !strcmp (part_id, content_id)) - return part; - - part_location = camel_mime_part_get_content_location (part); - g_warning ("url: %s, part_id: %s\n", url, part_id); - - if (part_location && !strcmp (part_location, url)) - return part; - - } - - return NULL; -} diff --git a/composer/e-msg-composer-attachment-bar.h b/composer/e-msg-composer-attachment-bar.h index 3dfe87ad80..15774bb2fe 100644 --- a/composer/e-msg-composer-attachment-bar.h +++ b/composer/e-msg-composer-attachment-bar.h @@ -68,8 +68,6 @@ 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 gchar *file_name); void e_msg_composer_attachment_bar_attach_mime_part (EMsgComposerAttachmentBar *bar, CamelMimePart *part); -CamelMimePart *e_msg_composer_attachment_bar_find_message (EMsgComposerAttachmentBar *bar, - char *url); #ifdef __cplusplus } diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index 1a8f525efa..aba81f2d6d 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -121,7 +121,7 @@ static GnomeAppClass *parent_class = NULL; /* local prototypes */ static GList *add_recipients (GList *list, const char *recips, gboolean decode); static void handle_multipart (EMsgComposer *composer, CamelMultipart *multipart, - gboolean attach_all, int depth); + gboolean just_inlines, int depth); static void message_rfc822_dnd (EMsgComposer *composer, CamelStream *stream); @@ -230,7 +230,15 @@ static gboolean clear_inline_images (gpointer key, gpointer value, gpointer user_data) { g_free (key); - g_free (value); + camel_object_unref (value); + + return TRUE; +} + +static gboolean +clear_url (gpointer key, gpointer value, gpointer user_data) +{ + g_free (key); return TRUE; } @@ -239,45 +247,13 @@ void e_msg_composer_clear_inlined_table (EMsgComposer *composer) { g_hash_table_foreach_remove (composer->inline_images, clear_inline_images, NULL); + g_hash_table_foreach_remove (composer->inline_images_by_url, clear_url, NULL); } static void -add_inlined_image (gpointer key, gpointer value, gpointer data) +add_inlined_image (gpointer key, gpointer part, gpointer multipart) { - gchar *file_name = (gchar *) key; - gchar *cid = (gchar *) value; - gchar *mime_type; - CamelMultipart *multipart = (CamelMultipart *) data; - CamelStream *stream; - CamelDataWrapper *wrapper; - CamelMimePart *part; - struct stat statbuf; - - /* check for regular file */ - if (stat (file_name, &statbuf) < 0 || !S_ISREG (statbuf.st_mode)) - return; - - if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) - return; - - wrapper = camel_data_wrapper_new (); - camel_data_wrapper_construct_from_stream (wrapper, stream); - camel_object_unref (CAMEL_OBJECT (stream)); - - mime_type = e_msg_composer_guess_mime_type (file_name); - camel_data_wrapper_set_mime_type (wrapper, mime_type ? mime_type : "application/octet-stream"); - g_free (mime_type); - - part = camel_mime_part_new (); - camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper); - camel_object_unref (CAMEL_OBJECT (wrapper)); - - camel_mime_part_set_content_id (part, cid); - camel_mime_part_set_filename (part, g_basename (file_name)); - camel_mime_part_set_encoding (part, CAMEL_MIME_PART_ENCODING_BASE64); - camel_multipart_add_part (multipart, part); - camel_object_unref (CAMEL_OBJECT (part)); } static void @@ -1961,6 +1937,7 @@ destroy (GtkObject *object) e_msg_composer_clear_inlined_table (composer); g_hash_table_destroy (composer->inline_images); + g_hash_table_destroy (composer->inline_images_by_url); g_free (composer->charset); @@ -2148,6 +2125,7 @@ init (EMsgComposer *composer) composer->editor_engine = CORBA_OBJECT_NIL; composer->inline_images = g_hash_table_new (g_str_hash, g_str_equal); + composer->inline_images_by_url = g_hash_table_new (g_str_hash, g_str_equal); composer->attachment_bar_visible = FALSE; composer->send_html = FALSE; @@ -2492,7 +2470,7 @@ handle_multipart_alternative (EMsgComposer *composer, CamelMultipart *multipart) } static void -handle_multipart (EMsgComposer *composer, CamelMultipart *multipart, gboolean attach_all, int depth) +handle_multipart (EMsgComposer *composer, CamelMultipart *multipart, gboolean just_inlines, int depth) { int i, nparts; @@ -2522,7 +2500,7 @@ handle_multipart (EMsgComposer *composer, CamelMultipart *multipart, gboolean at wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); mpart = CAMEL_MULTIPART (wrapper); - handle_multipart (composer, mpart, attach_all, depth + 1); + handle_multipart (composer, mpart, just_inlines, depth + 1); } else if (depth == 0 && i == 0) { /* Since the first part is not multipart/alternative, then this must be the body */ CamelDataWrapper *contents; @@ -2533,10 +2511,12 @@ handle_multipart (EMsgComposer *composer, CamelMultipart *multipart, gboolean at if (text) e_msg_composer_set_pending_body (composer, text); + } else if (just_inlines) { + if (camel_mime_part_get_content_id (mime_part) || + camel_mime_part_get_content_location (mime_part)) + e_msg_composer_add_inline_image_from_mime_part (composer, mime_part); } else { - /* this is a leaf of the tree, so attach it */ - if (attach_all || camel_mime_part_get_content_id (mime_part)) - e_msg_composer_attach (composer, mime_part); + e_msg_composer_attach (composer, mime_part); } } } @@ -2590,14 +2570,15 @@ is_special_header (const char *hdr_name) * @composer: the composer to add the attachments to. * @message: the source message to copy the attachments from. * @settext: set the text of the composer - * @attach_all: attach all attachments + * @just_inlines: whether to attach all attachments or just add + * inline images. * * Walk through all the mime parts in @message and add them to the composer * specified in @composer. */ void e_msg_composer_add_message_attachments (EMsgComposer *composer, CamelMimeMessage *message, - gboolean settext, gboolean attach_all) + gboolean settext, gboolean just_inlines) { CamelContentType *content_type; @@ -2619,7 +2600,7 @@ e_msg_composer_add_message_attachments (EMsgComposer *composer, CamelMimeMessage wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (CAMEL_MIME_PART (message))); multipart = CAMEL_MULTIPART (wrapper); - handle_multipart (composer, multipart, attach_all, 0); + handle_multipart (composer, multipart, just_inlines, 0); } else if (settext) { /* We either have a text/plain or a text/html part */ CamelDataWrapper *contents; @@ -3030,6 +3011,95 @@ e_msg_composer_attach (EMsgComposer *composer, CamelMimePart *attachment) } +/** + * e_msg_composer_add_inline_image_from_file: + * @composer: a composer object + * @file_name: the name of the file containing the image + * + * This reads in the image in @file_name and adds it to @composer + * as an inline image, to be wrapped in a multipart/related. + * + * Return value: the newly-created CamelMimePart (which must be reffed + * if the caller wants to keep its own reference), or %NULL on error. + **/ +CamelMimePart * +e_msg_composer_add_inline_image_from_file (EMsgComposer *composer, + const char *file_name) +{ + char *mime_type, *cid, *url; + CamelStream *stream; + CamelDataWrapper *wrapper; + CamelMimePart *part; + struct stat statbuf; + + /* check for regular file */ + if (stat (file_name, &statbuf) < 0 || !S_ISREG (statbuf.st_mode)) + return NULL; + + stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0); + if (!stream) + return NULL; + + wrapper = camel_data_wrapper_new (); + camel_data_wrapper_construct_from_stream (wrapper, stream); + camel_object_unref (CAMEL_OBJECT (stream)); + + mime_type = e_msg_composer_guess_mime_type (file_name); + camel_data_wrapper_set_mime_type (wrapper, mime_type ? mime_type : "application/octet-stream"); + g_free (mime_type); + + part = camel_mime_part_new (); + camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper); + camel_object_unref (CAMEL_OBJECT (wrapper)); + + cid = header_msgid_generate (); + camel_mime_part_set_content_id (part, cid); + camel_mime_part_set_filename (part, g_basename (file_name)); + camel_mime_part_set_encoding (part, CAMEL_MIME_PART_ENCODING_BASE64); + + url = g_strdup_printf ("file:%s", file_name); + g_hash_table_insert (composer->inline_images_by_url, url, part); + + url = g_strdup_printf ("cid:%s", cid); + g_hash_table_insert (composer->inline_images, url, part); + g_free (cid); + + return part; +} + +/** + * e_msg_composer_add_inline_image_from_mime_part: + * @composer: a composer object + * @part: a CamelMimePart containing image data + * + * This adds the mime part @part to @composer as an inline image, to + * be wrapped in a multipart/related. + **/ +void +e_msg_composer_add_inline_image_from_mime_part (EMsgComposer *composer, + CamelMimePart *part) +{ + char *cid, *url; + const char *location; + + cid = (char *)camel_mime_part_get_content_id (part); + if (!cid) { + cid = header_msgid_generate (); + camel_mime_part_set_content_id (part, cid); + g_free (cid); + } + + url = g_strdup_printf ("cid:%s", cid); + g_hash_table_insert (composer->inline_images, url, part); + camel_object_ref (CAMEL_OBJECT (part)); + + location = camel_mime_part_get_content_location (part); + if (location) { + g_hash_table_insert (composer->inline_images_by_url, + g_strdup (location), part); + } +} + /** * e_msg_composer_get_message: * @composer: A message composer widget diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h index 0153fe3ccf..72cb00a673 100644 --- a/composer/e-msg-composer.h +++ b/composer/e-msg-composer.h @@ -70,7 +70,7 @@ struct _EMsgComposer { Bonobo_PersistStream persist_stream_interface; GNOME_GtkHTML_Editor_Engine editor_engine; BonoboObject *editor_listener; - GHashTable *inline_images; + GHashTable *inline_images, *inline_images_by_url; Bonobo_ConfigDatabase config_db; @@ -122,6 +122,10 @@ void e_msg_composer_add_header (EMsgComposer *compose const char *value); void e_msg_composer_attach (EMsgComposer *composer, CamelMimePart *attachment); +CamelMimePart *e_msg_composer_add_inline_image_from_file (EMsgComposer *composer, + const char *filename); +void e_msg_composer_add_inline_image_from_mime_part (EMsgComposer *composer, + CamelMimePart *part); CamelMimeMessage *e_msg_composer_get_message (EMsgComposer *composer); CamelMimeMessage *e_msg_composer_get_message_draft (EMsgComposer *composer); void e_msg_composer_show_sig_file (EMsgComposer *composer); @@ -174,7 +178,7 @@ gchar * e_msg_composer_get_sig_file_content (const char *sigfi void e_msg_composer_add_message_attachments (EMsgComposer *composer, CamelMimeMessage *message, gboolean settext, - gboolean attach_all); + gboolean just_inlines); #ifdef __cplusplus } diff --git a/composer/listener.c b/composer/listener.c index 0b72407b88..228b1c2594 100644 --- a/composer/listener.c +++ b/composer/listener.c @@ -29,7 +29,6 @@ #include #include "listener.h" -#include "e-msg-composer-attachment-bar.h" static BonoboObjectClass *listener_parent_class; static POA_GNOME_GtkHTML_Editor_Listener__vepv listener_vepv; @@ -54,23 +53,22 @@ get_any_null () static gchar * resolve_image_url (EditorListener *l, gchar *url) { - gchar *cid = NULL; + CamelMimePart *part; + const char *cid; - printf ("resolve_image_url %s\n", url); - - if (!strncmp (url, "file:", 5)) { - gchar *id; - - id = (gchar *) g_hash_table_lookup (l->composer->inline_images, url + 5); - if (!id) { - id = header_msgid_generate (); - g_hash_table_insert (l->composer->inline_images, g_strdup (url + 5), id); - } - cid = g_strconcat ("cid:", id, NULL); - printf ("resolved to %s\n", cid); + part = g_hash_table_lookup (l->composer->inline_images_by_url, url); + if (!part && !strncmp (url, "file:", 5)) { + part = e_msg_composer_add_inline_image_from_file (l->composer, + url + 5); } + if (!part) + return NULL; + + cid = camel_mime_part_get_content_id (part); + if (!cid) + return NULL; - return cid; + return g_strconcat ("cid:", cid, NULL); } static void @@ -162,37 +160,31 @@ impl_event (PortableServer_Servant _servant, } } else if (!strcmp (name, "url_requested")) { GNOME_GtkHTML_Editor_URLRequestEvent *e; - CamelMimePart *part = NULL; + CamelMimePart *part; + GByteArray *ba; + CamelStream *cstream; + CamelDataWrapper *wrapper; e = (GNOME_GtkHTML_Editor_URLRequestEvent *)arg->_value; - g_warning ("url_requested = \"%s\"", e->url); - if (e->url) { - part = e_msg_composer_attachment_bar_find_message ( - E_MSG_COMPOSER_ATTACHMENT_BAR (l->composer->attachment_bar), e->url); - } + if (!e->url || e->stream == CORBA_OBJECT_NIL) + return get_any_null (); + part = g_hash_table_lookup (l->composer->inline_images_by_url, e->url); if (!part) - printf ("url_requested: no part found\n"); - else - printf ("url_requested: FOUND PART\n"); - - if (part && e->stream != CORBA_OBJECT_NIL) { - GByteArray *ba; - CamelStream *cstream; - CamelDataWrapper *wrapper; - - /* Write the data to a CamelStreamMem... */ - ba = g_byte_array_new (); - cstream = camel_stream_mem_new_with_byte_array (ba); - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part)); - camel_data_wrapper_write_to_stream (wrapper, cstream); + part = g_hash_table_lookup (l->composer->inline_images, e->url); + if (!part) + return get_any_null (); - bonobo_stream_client_write (e->stream, ba->data, ba->len, ev); + /* Write the data to a CamelStreamMem... */ + ba = g_byte_array_new (); + cstream = camel_stream_mem_new_with_byte_array (ba); + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part)); + camel_data_wrapper_write_to_stream (wrapper, cstream); - camel_object_unref (CAMEL_OBJECT (cstream)); - } + bonobo_stream_client_write (e->stream, ba->data, ba->len, ev); + camel_object_unref (CAMEL_OBJECT (cstream)); } return rv ? rv : get_any_null (); -- cgit v1.2.3