diff options
Diffstat (limited to 'mail')
-rw-r--r-- | mail/ChangeLog | 25 | ||||
-rw-r--r-- | mail/mail-display.c | 91 | ||||
-rw-r--r-- | mail/mail-format.c | 206 |
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 |