diff options
-rw-r--r-- | mail/ChangeLog | 20 | ||||
-rw-r--r-- | mail/Makefile.am | 2 | ||||
-rw-r--r-- | mail/mail-display.c | 55 | ||||
-rw-r--r-- | mail/mail-format.c | 204 | ||||
-rw-r--r-- | mail/mail-identify.c | 82 | ||||
-rw-r--r-- | mail/mail-identify.h | 1 |
6 files changed, 231 insertions, 133 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index baac4be710..50b7d6c11a 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,23 @@ +2000-04-29 Dan Winship <danw@helixcode.com> + + * mail-format.c (lookup_handler, etc): Improve the builtin vs + bonobo selection code. + (handle_mystery): Include name and Content-Description in the + "mystery data" info, when available + (handle_unknown_type): Call mail_identify_mime_part before + giving up. + (handle_undisplayable): Split out of handle_unknown_type now + that handle_unknown_type can try alternate viewers. + (handle_via_bonobo): Fall back to handle_undisplayable if the + bonobo control fails. + + * mail-identify.c (mail_identify_mime_part): New function to + attempt to identify a MIME part that we can't identify based on + Content-Type alone. + + * mail-display.c (on_url_requested): redo the mystery data icon + display stuff less kludgily. + 2000-04-28 Dan Winship <danw@helixcode.com> * mail-format.c (write_recipients_to_stream, write_headers, diff --git a/mail/Makefile.am b/mail/Makefile.am index b87445b32a..4757995bf1 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -34,6 +34,8 @@ evolution_mail_SOURCES = \ mail-display.h \ mail-format.c \ mail-format.h \ + mail-identify.c \ + mail-identify.h \ mail-ops.c \ mail-ops.h \ main.c \ diff --git a/mail/mail-display.c b/mail/mail-display.c index 036ebad60b..448426d70c 100644 --- a/mail/mail-display.c +++ b/mail/mail-display.c @@ -24,17 +24,6 @@ static GtkObjectClass *mail_display_parent_class; * Callbacks *----------------------------------------------------------------------*/ -static CamelStream * -cid_stream (const char *cid, CamelMimeMessage *message) -{ - CamelDataWrapper *data; - - data = gtk_object_get_data (GTK_OBJECT (message), cid); - g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data), NULL); - - return camel_data_wrapper_get_output_stream (data); -} - static void on_link_clicked (GtkHTML *html, const char *url, gpointer user_data) { @@ -53,24 +42,44 @@ on_url_requested (GtkHTML *html, const char *url, GtkHTMLStreamHandle handle, { char buf[1024]; int nread; - CamelStream *output; CamelMimeMessage *message = CAMEL_MIME_MESSAGE (user_data); - if (strncmp (url, "camel:", 6) == 0) { - output = GUINT_TO_POINTER (strtoul (url + 6, NULL, 0)); - g_return_if_fail (CAMEL_IS_STREAM (output)); + if (strncmp (url, "x-gnome-icon:", 13) == 0) { + const char *name = url + 13; + char *path = gnome_pixmap_file (name); + int fd; + + g_return_if_fail (path != NULL); + fd = open (path, O_RDONLY); + g_free (path); + g_return_if_fail (fd != -1); + + while (1) { + nread = read (fd, buf, sizeof (buf)); + if (nread < 1) + break; + gtk_html_write (html, handle, buf, nread); + } + close (fd); } else if (strncmp (url, "cid:", 4) == 0) { - output = cid_stream (url + 4, message); + const char *cid = url + 4; + CamelDataWrapper *data; + CamelStream *output; + + data = gtk_object_get_data (GTK_OBJECT (message), cid); + g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data)); + + output = camel_data_wrapper_get_output_stream (data); g_return_if_fail (CAMEL_IS_STREAM (output)); + + camel_stream_reset (output); + do { + nread = camel_stream_read (output, buf, sizeof (buf)); + if (nread > 0) + gtk_html_write (html, handle, buf, nread); + } while (!camel_stream_eos (output)); } else return; - - camel_stream_reset (output); - do { - nread = camel_stream_read (output, buf, sizeof (buf)); - if (nread > 0) - gtk_html_write (html, handle, buf, nread); - } while (!camel_stream_eos (output)); } /* HTML part code */ diff --git a/mail/mail-format.c b/mail/mail-format.c index b9689394d0..d10b74612b 100644 --- a/mail/mail-format.c +++ b/mail/mail-format.c @@ -1,8 +1,9 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Author : + * Authors: * Matt Loper <matt@helixcode.com> + * Dan Winship <danw@helixcode.com> * * Copyright 2000, Helix Code, Inc. (http://www.helixcode.com) * @@ -25,6 +26,7 @@ #include <config.h> #include "mail-format.h" #include "mail-display.h" +#include "mail-identify.h" #include "camel/hash-table-utils.h" #include "e-util/e-html-utils.h" @@ -133,7 +135,6 @@ get_cid (CamelMimePart *part, CamelMimeMessage *root) typedef void (*mime_handler_fn) (CamelMimePart *part, CamelMimeMessage *root, GtkBox *box); static GHashTable *mime_function_table, *mime_fallback_table; -static GHashTable *mime_icon_table; static void setup_function_table (void) @@ -178,79 +179,19 @@ setup_function_table (void) handle_multipart_mixed); } -static CamelStream * -icon_stream (char *path) -{ - GByteArray *ba; - char buf[8192]; - int fd, nread; - - fd = open (path, O_RDONLY); - if (fd == -1) - return NULL; - - ba = g_byte_array_new (); - while (1) { - nread = read (fd, buf, sizeof (buf)); - if (nread < 1) - break; - g_byte_array_append (ba, buf, nread); - } - close (fd); - return camel_stream_mem_new_with_byte_array (ba); -} - -static void -setup_icon_table (void) -{ - char *path; - - mime_icon_table = g_hash_table_new (g_strcase_hash, - g_strcase_equal); - - path = gnome_pixmap_file ("gnome-audio2.png"); - if (path) { - g_hash_table_insert (mime_icon_table, "audio", - icon_stream (path)); - g_free (path); - } - path = gnome_pixmap_file ("gnome-graphics.png"); - if (path) { - g_hash_table_insert (mime_icon_table, "image", - icon_stream (path)); - g_free (path); - } - path = gnome_pixmap_file ("gnome-qeye.png"); - if (path) { - g_hash_table_insert (mime_icon_table, "video", - icon_stream (path)); - g_free (path); - } - path = gnome_pixmap_file ("gnome-question.png"); - if (path) { - g_hash_table_insert (mime_icon_table, "unknown", - icon_stream (path)); - g_free (path); - } -} - static mime_handler_fn -lookup_handler (CamelMimePart *part, gboolean *generic) +lookup_handler (const char *mime_type, gboolean *generic) { - CamelDataWrapper *wrapper; mime_handler_fn handler_function; const char *whole_goad_id, *generic_goad_id; - char *mimetype_whole = NULL; - char *mimetype_main = NULL; - - g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL); + char *mime_type_main; - if (mime_function_table == NULL) { + if (mime_function_table == NULL) setup_function_table (); - setup_icon_table (); - } - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part)); + mime_type_main = g_strdup_printf ("%.*s/*", + (int)strcspn (mime_type, "/"), + mime_type); /* OK. There are 6 possibilities, which we try in this order: * 1) full match in the main table @@ -265,60 +206,53 @@ lookup_handler (CamelMimePart *part, gboolean *generic) */ /* Check for full match in mime_function_table. */ - mimetype_whole = camel_data_wrapper_get_mime_type (wrapper); - g_strdown (mimetype_whole); - mimetype_main = g_strdup_printf ("%s/*", wrapper->mime_type->type); - g_strdown (mimetype_main); - handler_function = g_hash_table_lookup (mime_function_table, - mimetype_whole); + mime_type); if (!handler_function) { handler_function = g_hash_table_lookup (mime_function_table, - mimetype_main); + mime_type_main); if (handler_function) { /* Optimize this for the next time through. */ g_hash_table_insert (mime_function_table, - g_strdup (mimetype_whole), + g_strdup (mime_type), handler_function); } } if (handler_function) { - g_free (mimetype_whole); - g_free (mimetype_main); + g_free (mime_type_main); *generic = FALSE; return handler_function; } - whole_goad_id = gnome_mime_get_value (mimetype_whole, - "bonobo-goad-id"); - generic_goad_id = gnome_mime_get_value (mimetype_main, + whole_goad_id = gnome_mime_get_value (mime_type, "bonobo-goad-id"); + generic_goad_id = gnome_mime_get_value (mime_type_main, "bonobo-goad-id"); if (whole_goad_id && (!generic_goad_id || strcmp (whole_goad_id, generic_goad_id) != 0)) { /* Optimize this for the next time through. */ g_hash_table_insert (mime_function_table, - mimetype_whole, + g_strdup (mime_type), handle_via_bonobo); - g_free (mimetype_main); + g_free (mime_type_main); *generic = FALSE; return handle_via_bonobo; } handler_function = g_hash_table_lookup (mime_fallback_table, - mimetype_whole); - g_free (mimetype_whole); + mime_type); if (handler_function) *generic = FALSE; else { handler_function = g_hash_table_lookup (mime_fallback_table, - mimetype_main); + mime_type_main); if (!handler_function && generic_goad_id) handler_function = handle_via_bonobo; *generic = TRUE; } - g_free (mimetype_main); + + g_free (mime_type_main); return handler_function; } @@ -329,10 +263,13 @@ call_handler_function (CamelMimePart *part, CamelMimeMessage *root, CamelDataWrapper *wrapper; mime_handler_fn handler_function = NULL; gboolean generic; + char *mime_type; wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part)); - - handler_function = lookup_handler (part, &generic); + mime_type = camel_data_wrapper_get_mime_type (wrapper); + g_strdown (mime_type); + handler_function = lookup_handler (mime_type, &generic); + g_free (mime_type); if (handler_function) (*handler_function) (part, root, box); @@ -912,31 +849,52 @@ handle_multipart_appledouble (CamelMimePart *part, CamelMimeMessage *root, static void handle_mystery (CamelMimePart *part, CamelMimeMessage *root, GtkBox *box, - char *icon_cid, char *id, char *action) + char *icon_name, char *id, char *action) { GtkHTML *html; GtkHTMLStreamHandle *stream; - char *cid; + const char *info; + char *htmlinfo; + GMimeContentField *content_type; - cid = get_cid (part, root); mail_html_new (&html, &stream, root, TRUE); - mail_html_write (html, stream, "<table><tr><td><a href=\"camel:%p\">" - "<img src=\"camel:%p\"></a></td>" - "<td>%s<br><br>Click on the icon to %s." - "</td></tr></table>", get_cid (part, root), - icon_cid, id, action); + mail_html_write (html, stream, "<table><tr><td><a href=\"cid:%p\">" + "<img src=\"x-gnome-icon:%s\"></a></td>" + "<td>%s<br>", get_cid (part, root), icon_name, id); + + info = camel_mime_part_get_description (part); + if (info) { + htmlinfo = e_text_to_html (info, E_TEXT_TO_HTML_CONVERT_URLS); + mail_html_write (html, stream, "Description: %s<br>", + htmlinfo); + g_free (htmlinfo); + } + + content_type = camel_mime_part_get_content_type (part); + info = gmime_content_field_get_parameter (content_type, "name"); + if (!info) + info = camel_mime_part_get_filename (part); + if (info) { + htmlinfo = e_text_to_html (info, 0); + mail_html_write (html, stream, "Name: %s<br>", + htmlinfo); + g_free (htmlinfo); + } + + mail_html_write (html, stream, + "<br>Click on the icon to %s.</td></tr></table>", + action); mail_html_end (html, stream, TRUE, box); } static void handle_audio (CamelMimePart *part, CamelMimeMessage *root, GtkBox *box) { - char *cid, *id; + char *id; - cid = g_hash_table_lookup (mime_icon_table, "audio"); id = g_strdup_printf ("Audio data in \"%s\" format.", camel_mime_part_get_content_type (part)->subtype); - handle_mystery (part, root, box, cid, id, "play it"); + handle_mystery (part, root, box, "gnome-audio2.png", id, "play it"); g_free (id); } @@ -963,18 +921,42 @@ handle_message_rfc822 (CamelMimePart *part, CamelMimeMessage *root, } static void -handle_unknown_type (CamelMimePart *part, CamelMimeMessage *root, GtkBox *box) +handle_undisplayable (CamelMimePart *part, CamelMimeMessage *root, GtkBox *box) { - char *cid, *id; + char *id; - cid = g_hash_table_lookup (mime_icon_table, "unknown"); id = g_strdup_printf ("Unknown data of type \"%s/%s\".", camel_mime_part_get_content_type (part)->type, camel_mime_part_get_content_type (part)->subtype); - handle_mystery (part, root, box, cid, id, "save it to disk"); + handle_mystery (part, root, box, "gnome-question.png", id, + "save it to disk"); g_free (id); } +static void +handle_unknown_type (CamelMimePart *part, CamelMimeMessage *root, GtkBox *box) +{ + char *type; + + /* Don't give up quite yet. */ + type = mail_identify_mime_part (part); + if (type) { + mime_handler_fn handler_function; + gboolean generic; + + handler_function = lookup_handler (type, &generic); + g_free (type); + if (handler_function && + handler_function != handle_unknown_type) { + (*handler_function) (part, root, box); + return; + } + } + + /* OK. Give up. */ + handle_undisplayable (part, root, box); +} + static void embeddable_destroy_cb (GtkObject *obj, gpointer user_data) { @@ -1028,22 +1010,23 @@ handle_via_bonobo (CamelMimePart *part, CamelMimeMessage *root, GtkBox *box) if (!goad_id) goad_id = gnome_mime_get_value (type->type, "bonobo-goad-id"); - if (!goad_id) + if (!goad_id) { + handle_undisplayable (part, root, box); return; + } embedded = bonobo_widget_new_subdoc (goad_id, NULL); - if (!embedded) - return; - server = bonobo_widget_get_server (BONOBO_WIDGET (embedded)); - if (!server) { - bonobo_object_destroy (BONOBO_OBJECT (embedded)); + if (!embedded) { + handle_undisplayable (part, root, box); return; } + server = bonobo_widget_get_server (BONOBO_WIDGET (embedded)); persist = (Bonobo_PersistStream) bonobo_object_client_query_interface ( server, "IDL:Bonobo/PersistStream:1.0", NULL); if (persist == CORBA_OBJECT_NIL) { bonobo_object_destroy (BONOBO_OBJECT (embedded)); + handle_undisplayable (part, root, box); return; } @@ -1069,6 +1052,7 @@ handle_via_bonobo (CamelMimePart *part, CamelMimeMessage *root, GtkBox *box) if (ev._major != CORBA_NO_EXCEPTION) { bonobo_object_unref (BONOBO_OBJECT (embedded)); CORBA_exception_free (&ev); + handle_undisplayable (part, root, box); return; } CORBA_exception_free (&ev); diff --git a/mail/mail-identify.c b/mail/mail-identify.c new file mode 100644 index 0000000000..244bd7d013 --- /dev/null +++ b/mail/mail-identify.c @@ -0,0 +1,82 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Dan Winship <danw@helixcode.com> + * + * Copyright 2000, Helix Code, Inc. (http://www.helixcode.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <libgnome/libgnome.h> +#include "camel/camel.h" +#include "mail-identify.h" + +/** + * mail_identify_mime_part: + * @part: a CamelMimePart + * + * Try to identify the MIME type of the data in @part (which presumably + * doesn't have a useful Content-Type). + **/ +char * +mail_identify_mime_part (CamelMimePart *part) +{ + GMimeContentField *content_type; + const char *filename, *type; + CamelMimePartEncodingType encoding; + + content_type = camel_mime_part_get_content_type (part); + + + /* Try identifying based on name in Content-Type or + * filename in Content-Disposition. + */ + filename = gmime_content_field_get_parameter (content_type, "name"); + if (filename) { + type = gnome_mime_type_or_default (filename, NULL); + if (type) + return g_strdup (type); + } + + filename = camel_mime_part_get_filename (part); + if (filename) { + type = gnome_mime_type_or_default (filename, NULL); + if (type) + return g_strdup (type); + } + + + /* Try file magic. */ + /* FIXME */ + + + /* Another possibility to try is the x-mac-type / x-mac-creator + * parameter to Content-Type used by some Mac email clients. That + * would require a Mac type to mime type conversion table. + */ + + + /* We give up. */ + return NULL; +} diff --git a/mail/mail-identify.h b/mail/mail-identify.h new file mode 100644 index 0000000000..30bc9f1c78 --- /dev/null +++ b/mail/mail-identify.h @@ -0,0 +1 @@ +char *mail_identify_mime_part (CamelMimePart *part); |