aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/ChangeLog20
-rw-r--r--mail/Makefile.am2
-rw-r--r--mail/mail-display.c55
-rw-r--r--mail/mail-format.c204
-rw-r--r--mail/mail-identify.c82
-rw-r--r--mail/mail-identify.h1
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);