aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
Diffstat (limited to 'mail')
-rw-r--r--mail/ChangeLog25
-rw-r--r--mail/mail-display.c91
-rw-r--r--mail/mail-format.c206
3 files changed, 197 insertions, 125 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index 61eb17ee1c..e5d63b69f7 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,28 @@
+2000-05-31 Dan Winship <danw@helixcode.com>
+
+ * mail-format.c (mail_format_mime_message): Initialize the "urls"
+ hash table stored on the message and store cid and other URLs
+ there rather than as object data on the message.
+ (get_cid): rewrite this a bunch
+ (handle_text_enriched): move the code from write_iframe_string()
+ into here, since it's the only place that actually needs it.
+ (handle_text_html): simplify this a lot. We can use a cid: URL
+ here rather than x-evolution-data.
+ (get_url_for_icon): New routine to return URLs for icons, and
+ cache the results, so we don't have to keep re-reading the icon
+ files (and so we can't be spoofed into reading non-icon files).
+ (handle_mystery, handle_audio): use get_url_for_icon.
+
+ * mail-display.c (save_data): move the CamelMimePart filename
+ extracting code from get_cid to here.
+ (on_link_clicked, on_object_requested): Update for cid: changes.
+ (on_url_requested): Kill off the kludgy, exploitable x-gnome-icon
+ URL schema, update cid and x-evolution-data to match
+ mail-format.c.
+
+ It should now be easier to implement RFC 2557 (Content-Location,
+ etc), but that RFC still pretty much sucks.
+
2000-05-30 Dan Winship <danw@helixcode.com>
* mail-format.c: Redo this back to the old way: a single GtkHTML
diff --git a/mail/mail-display.c b/mail/mail-display.c
index 4456ad7f81..4ab6dbed02 100644
--- a/mail/mail-display.c
+++ b/mail/mail-display.c
@@ -10,6 +10,7 @@
*/
#include <config.h>
#include <sys/stat.h>
+#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <gnome.h>
@@ -90,20 +91,39 @@ save_data_cb (GtkWidget *widget, gpointer user_data)
static void
save_data (const char *cid, CamelMimeMessage *message)
{
+ GHashTable *urls;
+ CamelMimePart *part;
CamelDataWrapper *data;
GtkFileSelection *file_select;
char *filename;
g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
- data = gtk_object_get_data (GTK_OBJECT (message), cid);
- g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data));
+ urls = gtk_object_get_data (GTK_OBJECT (message), "urls");
+ part = g_hash_table_lookup (urls, cid);
+ g_return_if_fail (CAMEL_IS_MIME_PART (part));
+ data = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+
+ filename = (char *)camel_mime_part_get_filename (part);
+ if (filename) {
+ char *p;
+
+ p = strrchr (filename, '/');
+ if (p)
+ filename = g_strdup_printf ("%s%s", evolution_dir, p);
+ else {
+ filename = g_strdup_printf ("%s/%s", evolution_dir,
+ filename);
+ }
- file_select = GTK_FILE_SELECTION (gtk_file_selection_new ("Save Attachment"));
- filename = gtk_object_get_data (GTK_OBJECT (data), "filename");
- if (filename)
- filename = g_strdup_printf ("%s/%s", evolution_dir, filename);
- else
+ for (p = strrchr (filename, '/') + 1; *p; p++) {
+ if (!isascii ((unsigned char)*p) ||
+ strchr (" /'\"`&();|<>${}!", *p))
+ *p = '_';
+ }
+ } else
filename = g_strdup_printf ("%s/attachment", evolution_dir);
+
+ file_select = GTK_FILE_SELECTION (gtk_file_selection_new ("Save Attachment"));
gtk_file_selection_set_filename (file_select, filename);
g_free (filename);
@@ -120,13 +140,17 @@ save_data (const char *cid, CamelMimeMessage *message)
static void
on_link_clicked (GtkHTML *html, const char *url, gpointer user_data)
{
+ CamelMimeMessage *message;
+
+ message = gtk_object_get_data (GTK_OBJECT (html), "message");
+
if (!strncasecmp (url, "news:", 5) ||
!strncasecmp (url, "nntp:", 5))
g_warning ("Can't handle news URLs yet.");
else if (!strncasecmp (url, "mailto:", 7))
send_to_url (url);
else if (!strncasecmp (url, "cid:", 4))
- save_data (url + 4, user_data);
+ save_data (url, message);
else
gnome_url_show (url);
}
@@ -163,6 +187,8 @@ static gboolean
on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data)
{
CamelMimeMessage *message;
+ GHashTable *urls;
+ CamelMedium *medium;
CamelDataWrapper *wrapper;
const char *goad_id;
GtkWidget *embedded;
@@ -176,8 +202,10 @@ on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data)
if (strncmp (eb->classid, "cid:", 4) != 0)
return FALSE;
message = gtk_object_get_data (GTK_OBJECT (html), "message");
- wrapper = gtk_object_get_data (GTK_OBJECT (message), eb->classid + 4);
- g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (wrapper), FALSE);
+ urls = gtk_object_get_data (GTK_OBJECT (message), "urls");
+ medium = g_hash_table_lookup (urls, eb->classid);
+ g_return_val_if_fail (CAMEL_IS_MEDIUM (medium), FALSE);
+ wrapper = camel_medium_get_content_object (medium);
goad_id = gnome_mime_get_value (eb->type, "bonobo-goad-id");
if (!goad_id) {
@@ -241,39 +269,22 @@ on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle,
gpointer user_data)
{
CamelMimeMessage *message;
+ GHashTable *urls;
message = gtk_object_get_data (GTK_OBJECT (html), "message");
+ urls = gtk_object_get_data (GTK_OBJECT (message), "urls");
- if (strncmp (url, "x-gnome-icon:", 13) == 0) {
- const char *name = url + 13;
- /* FIXME: gnome_pixmap_file will cheerily accept icon
- * names like "../../../dev/zero". Anyway, this whole
- * hack needs to be replaced with something more
- * efficient anyway.
- */
- char *path = gnome_pixmap_file (name), buf[1024];
- int fd, nread;
-
- 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) {
- const char *cid = url + 4;
+ user_data = g_hash_table_lookup (urls, url);
+ g_return_if_fail (user_data != NULL);
+
+ if (strncmp (url, "cid:", 4) == 0) {
+ CamelMedium *medium = user_data;
CamelDataWrapper *data;
CamelStream *stream_mem;
GByteArray *ba;
- data = gtk_object_get_data (GTK_OBJECT (message), cid);
- g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data));
+ g_return_if_fail (CAMEL_IS_MEDIUM (medium));
+ data = camel_medium_get_content_object (medium);
ba = g_byte_array_new ();
stream_mem = camel_stream_mem_new_with_byte_array (ba);
@@ -281,12 +292,10 @@ on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle,
gtk_html_write (html, handle, ba->data, ba->len);
gtk_object_unref (GTK_OBJECT (stream_mem));
} else if (strncmp (url, "x-evolution-data:", 17) == 0) {
- char *string;
-
- string = gtk_object_get_data (GTK_OBJECT (message), url);
- g_return_if_fail (string != NULL);
+ GByteArray *ba = user_data;
- gtk_html_write (html, handle, string, strlen (string));
+ g_return_if_fail (ba != NULL);
+ gtk_html_write (html, handle, ba->data, ba->len);
}
}
diff --git a/mail/mail-format.c b/mail/mail-format.c
index 45a84ff742..4a422617c7 100644
--- a/mail/mail-format.c
+++ b/mail/mail-format.c
@@ -36,6 +36,7 @@
struct mail_format_data {
CamelMimeMessage *root;
+ GHashTable *urls;
GtkHTML *html;
GtkHTMLStream *stream;
};
@@ -91,6 +92,8 @@ static void write_headers (struct mail_format_data *mfd);
static void call_handler_function (CamelMimePart *part,
struct mail_format_data *mfd);
+static void free_urls (gpointer data);
+
/**
* mail_format_mime_message:
@@ -113,70 +116,65 @@ mail_format_mime_message (CamelMimeMessage *mime_message,
mfd.html = html;
mfd.stream = stream;
mfd.root = root;
+ mfd.urls = gtk_object_get_data (GTK_OBJECT (root), "urls");
+ if (!mfd.urls) {
+ mfd.urls = g_hash_table_new (g_str_hash, g_str_equal);
+ gtk_object_set_data_full (GTK_OBJECT (root), "urls",
+ mfd.urls, free_urls);
+ }
write_headers (&mfd);
call_handler_function (CAMEL_MIME_PART (mime_message), &mfd);
}
-static char *
-get_cid (CamelMimePart *part, CamelMimeMessage *root)
+static void
+free_url (gpointer key, gpointer value, gpointer data)
{
- CamelDataWrapper *wrapper =
- camel_medium_get_content_object (CAMEL_MEDIUM (part));
- char *cid;
- const char *filename;
+ char *url = key;
- /* If we have a real Content-ID, use it. If we don't,
- * make a (syntactically invalid) fake one.
+ /* If it's an "x-evolution-data" URL, the value is a byte
+ * array. Otherwise it's a CamelMimePart which is part of the
+ * message and will be freed from elsewhere.
*/
- if (camel_mime_part_get_content_id (part))
- cid = g_strdup (camel_mime_part_get_content_id (part));
- else
- cid = g_strdup_printf ("@@@%p", wrapper);
+ if (!strncmp (url, "x-evolution-data:", 17))
+ g_byte_array_free (value, TRUE);
+ g_free (key);
+}
- gtk_object_set_data (GTK_OBJECT (root), cid, wrapper);
+static void
+free_urls (gpointer data)
+{
+ GHashTable *urls = data;
- /* Record the filename, in case the user wants to save this
- * data later.
- */
- filename = camel_mime_part_get_filename (part);
- if (filename) {
- char *safe, *p;
+ g_hash_table_foreach (urls, free_url, NULL);
+ g_hash_table_destroy (urls);
+}
- safe = strrchr (filename, '/');
- if (safe)
- safe = g_strdup (safe + 1);
- else
- safe = g_strdup (filename);
+static const char *
+get_cid (CamelMimePart *part, struct mail_format_data *mfd)
+{
+ char *cid;
+ const char *filename;
+ gpointer orig_name, value;
- for (p = safe; *p; p++) {
- if (!isascii ((unsigned char)*p) ||
- strchr (" /'\"`&();|<>${}!", *p))
- *p = '_';
- }
+ /* If we have a real Content-ID, use it. If we don't,
+ * make a (syntactically invalid) fake one.
+ */
+ if (camel_mime_part_get_content_id (part)) {
+ cid = g_strdup_printf ("cid:%s",
+ camel_mime_part_get_content_id (part));
+ } else
+ cid = g_strdup_printf ("cid:@@@%p", part);
- gtk_object_set_data (GTK_OBJECT (wrapper), "filename", safe);
- }
+ if (g_hash_table_lookup_extended (mfd->urls, cid, &orig_name, &value)) {
+ g_free (cid);
+ return orig_name;
+ } else
+ g_hash_table_insert (mfd->urls, cid, part);
return cid;
}
-static void
-write_iframe_string (CamelMimePart *part, struct mail_format_data *mfd,
- char *string)
-{
- char *cid, *xed;
-
- cid = get_cid (part, mfd->root);
- xed = g_strdup_printf ("x-evolution-data:%s", cid);
- g_free (cid);
- gtk_object_set_data_full (GTK_OBJECT (mfd->root), xed, string,
- g_free);
- mail_html_write (mfd->html, mfd->stream,
- "<iframe src=\"%s\" frameborder=0 scrolling=no>"
- "</iframe>", xed);
- g_free (xed);
-}
/* We're maintaining a hashtable of mimetypes -> functions;
@@ -562,7 +560,7 @@ handle_text_enriched (CamelMimePart *part, const char *mime_type,
GString *string;
CamelStream *memstream;
GByteArray *ba;
- char *p;
+ char *p, *xed;
int len, nofill = 0;
gboolean enriched;
@@ -609,6 +607,10 @@ handle_text_enriched (CamelMimePart *part, const char *mime_type,
"\n<!-- text/enriched -->\n");
}
+ /* This is not great code, but I don't feel like fixing it right
+ * now. I mean, it's just text/enriched...
+ */
+
ba = g_byte_array_new ();
memstream = camel_stream_mem_new_with_byte_array (ba);
camel_data_wrapper_write_to_stream (wrapper, memstream);
@@ -697,33 +699,34 @@ handle_text_enriched (CamelMimePart *part, const char *mime_type,
}
gtk_object_unref (GTK_OBJECT (memstream));
- write_iframe_string (part, mfd, string->str);
- g_string_free (string, FALSE);
+ ba = g_byte_array_new ();
+ g_byte_array_append (ba, (const guint8 *)string->str,
+ strlen (string->str));
+ g_string_free (string, TRUE);
+
+ xed = g_strdup_printf ("x-evolution-data:%p", part);
+ g_hash_table_insert (mfd->urls, xed, ba);
+ mail_html_write (mfd->html, mfd->stream,
+ "<iframe src=\"%s\" frameborder=0 scrolling=no>"
+ "</iframe>", xed);
}
static void
handle_text_html (CamelMimePart *part, const char *mime_type,
struct mail_format_data *mfd)
{
- CamelDataWrapper *wrapper =
- camel_medium_get_content_object (CAMEL_MEDIUM (part));
- char *text;
-
mail_html_write (mfd->html, mfd->stream, "\n<!-- text/html -->\n");
-
- text = get_data_wrapper_text (wrapper);
- write_iframe_string (part, mfd, text);
+ mail_html_write (mfd->html, mfd->stream,
+ "<iframe src=\"%s\" frameborder=0 scrolling=no>"
+ "</iframe>", get_cid (part, mfd));
}
static void
handle_image (CamelMimePart *part, const char *mime_type,
struct mail_format_data *mfd)
{
- char *cid;
-
- cid = get_cid (part, mfd->root);
- mail_html_write (mfd->html, mfd->stream, "<img src=\"cid:%s\">", cid);
- g_free (cid);
+ mail_html_write (mfd->html, mfd->stream, "<img src=\"%s\">",
+ get_cid (part, mfd));
}
static void
@@ -804,7 +807,7 @@ handle_multipart_related (CamelMimePart *part, const char *mime_type,
if (body_part == display_part)
continue;
- g_free (get_cid (body_part, mfd->root));
+ get_cid (body_part, mfd);
}
/* Now, display the displayed part. */
@@ -874,6 +877,52 @@ handle_multipart_appledouble (CamelMimePart *part, const char *mime_type,
call_handler_function (part, mfd);
}
+static const char *
+get_url_for_icon (const char *icon_name, struct mail_format_data *mfd)
+{
+ static GHashTable *icons;
+ char *icon_path = gnome_pixmap_file (icon_name), buf[1024], *url;
+ int fd, nread;
+ GByteArray *ba;
+
+ if (!icons)
+ icons = g_hash_table_new (g_str_hash, g_str_equal);
+
+ if (!icon_path)
+ return "file:///dev/null";
+
+ url = g_hash_table_lookup (icons, icon_path);
+ if (url) {
+ g_free (icon_path);
+ return url;
+ }
+
+ fd = open (icon_path, O_RDONLY);
+ if (fd == -1) {
+ g_free (icon_path);
+ return "file:///dev/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);
+
+ g_hash_table_insert (icons, icon_path, ba);
+ g_free (icon_path);
+
+ url = g_strdup_printf ("x-evolution-data:%p", ba);
+ g_hash_table_insert (mfd->urls, url, ba);
+
+ return url;
+}
+
+
static void
handle_mystery (CamelMimePart *part, struct mail_format_data *mfd,
const char *url, const char *icon_name, const char *id,
@@ -895,8 +944,9 @@ handle_mystery (CamelMimePart *part, struct mail_format_data *mfd,
mail_html_write (mfd->html, mfd->stream,
"<table border=2><tr><td>");
}
- mail_html_write (mfd->html, mfd->stream,
- "<img src=\"x-gnome-icon:%s\">", icon_name);
+ mail_html_write (mfd->html, mfd->stream, "<img src=\"%s\">",
+ get_url_for_icon (icon_name, mfd));
+
if (url)
mail_html_write (mfd->html, mfd->stream, "</a>");
else
@@ -937,7 +987,7 @@ static void
handle_audio (CamelMimePart *part, const char *mime_type,
struct mail_format_data *mfd)
{
- char *id, *cid, *cidstr;
+ char *id;
const char *desc;
desc = gnome_mime_get_value (mime_type, "description");
@@ -947,12 +997,8 @@ handle_audio (CamelMimePart *part, const char *mime_type,
id = g_strdup_printf ("Audio data in \"%s\" format.",
mime_type);
}
- cid = get_cid (part, mfd->root);
- cidstr = g_strdup_printf ("cid:%s", cid);
- g_free (cid);
- handle_mystery (part, mfd, cid, "gnome-audio2.png",
+ handle_mystery (part, mfd, get_cid (part, mfd), "gnome-audio2.png",
id, "play it");
- g_free (cidstr);
g_free (id);
}
@@ -1085,19 +1131,15 @@ handle_undisplayable (CamelMimePart *part, const char *mime_type,
struct mail_format_data *mfd)
{
const char *desc;
- char *id, *cid, *cidstr;
+ char *id;
desc = gnome_mime_get_value (mime_type, "description");
if (desc)
id = g_strdup (desc);
else
id = g_strdup_printf ("Data of type \"%s\".", mime_type);
- cid = get_cid (part, mfd->root);
- cidstr = g_strdup_printf ("cid:%s", cid);
- g_free (cid);
- handle_mystery (part, mfd, cid, "gnome-question.png", id,
- "save it to disk");
- g_free (cidstr);
+ handle_mystery (part, mfd, get_cid (part, mfd), "gnome-question.png",
+ id, "save it to disk");
g_free (id);
}
@@ -1132,13 +1174,9 @@ static void
handle_via_bonobo (CamelMimePart *part, const char *mime_type,
struct mail_format_data *mfd)
{
- char *cid;
-
- cid = get_cid (part, mfd->root);
mail_html_write (mfd->html, mfd->stream,
- "<object classid=\"cid:%s\" type=\"%s\">",
- cid, mime_type);
- g_free (cid);
+ "<object classid=\"%s\" type=\"%s\">",
+ get_cid (part, mfd), mime_type);
/* Call handle_undisplayable to output its HTML inside the
* <object> ... </object>. It will only be displayed if the