aboutsummaryrefslogtreecommitdiffstats
path: root/mail/mail-display.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/mail-display.c')
-rw-r--r--mail/mail-display.c315
1 files changed, 225 insertions, 90 deletions
diff --git a/mail/mail-display.c b/mail/mail-display.c
index 960c97d18f..521d15a3dd 100644
--- a/mail/mail-display.c
+++ b/mail/mail-display.c
@@ -16,6 +16,7 @@
#include <gnome.h>
#include "e-util/e-util.h"
#include "e-util/e-html-utils.h"
+#include "e-util/e-popup-menu.h"
#include "mail-display.h"
#include "mail.h"
@@ -29,7 +30,7 @@
static GtkObjectClass *mail_display_parent_class;
-static void redisplay (MailDisplay *md);
+static void redisplay (MailDisplay *md, gboolean unscroll);
/*----------------------------------------------------------------------*
* Callbacks
@@ -116,22 +117,92 @@ make_safe_filename (const char *prefix, CamelMimePart *part)
return safe;
}
-static CamelMimePart *
-part_for_url (const char *url, MailDisplay *md)
+static void
+save_data_cb (GtkWidget *widget, gpointer user_data)
{
- GHashTable *urls;
+ GtkFileSelection *file_select = (GtkFileSelection *)
+ gtk_widget_get_ancestor (widget, GTK_TYPE_FILE_SELECTION);
- urls = g_datalist_get_data (md->data, "urls");
- g_return_val_if_fail (urls != NULL, NULL);
- return g_hash_table_lookup (urls, url);
+ write_data_to_file (user_data,
+ gtk_file_selection_get_filename (file_select),
+ FALSE);
+ gtk_widget_destroy (GTK_WIDGET (file_select));
+}
+
+static gboolean
+idle_redisplay (gpointer data)
+{
+ MailDisplay *md = data;
+
+ md->idle_id = 0;
+ redisplay (md, FALSE);
+ return FALSE;
+}
+
+static void
+queue_redisplay (MailDisplay *md)
+{
+ if (!md->idle_id) {
+ md->idle_id = g_idle_add_full (G_PRIORITY_LOW, idle_redisplay,
+ md, NULL);
+ }
+}
+
+static void
+on_link_clicked (GtkHTML *html, const char *url, gpointer user_data)
+{
+ MailDisplay *md = user_data;
+
+ if (!g_strncasecmp (url, "news:", 5) ||
+ !g_strncasecmp (url, "nntp:", 5))
+ g_warning ("Can't handle news URLs yet.");
+ else if (!g_strncasecmp (url, "mailto:", 7))
+ send_to_url (url);
+ else if (!strcmp (url, "x-evolution-decode-pgp:")) {
+ g_datalist_set_data (md->data, "show_pgp",
+ GINT_TO_POINTER (1));
+ queue_redisplay (md);
+ } else
+ gnome_url_show (url);
}
static void
-launch_external (const char *url, MailDisplay *md)
+save_cb (GtkWidget *widget, gpointer user_data)
{
- const char *command = url + 21;
- char *tmpl, *tmpdir, *filename, *argv[2];
- CamelMimePart *part = part_for_url (url, md);
+ CamelMimePart *part = gtk_object_get_data (user_data, "CamelMimePart");
+ GtkFileSelection *file_select;
+ char *filename;
+
+ filename = make_safe_filename (g_get_home_dir (), part);
+ file_select = GTK_FILE_SELECTION (
+ gtk_file_selection_new ("Save Attachment"));
+ gtk_file_selection_set_filename (file_select, filename);
+ g_free (filename);
+
+ gtk_signal_connect (GTK_OBJECT (file_select->ok_button), "clicked",
+ GTK_SIGNAL_FUNC (save_data_cb), part);
+ gtk_signal_connect_object (GTK_OBJECT (file_select->cancel_button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ GTK_OBJECT (file_select));
+
+ gtk_widget_show (GTK_WIDGET (file_select));
+}
+
+static void
+launch_cb (GtkWidget *widget, gpointer user_data)
+{
+ CamelMimePart *part = gtk_object_get_data (user_data, "CamelMimePart");
+ GnomeVFSMimeApplication *app;
+ GMimeContentField *content_type;
+ char *mime_type, *tmpl, *tmpdir, *filename, *argv[2];
+
+ content_type = camel_mime_part_get_content_type (part);
+ mime_type = gmime_content_field_get_mime_type (content_type);
+ app = gnome_vfs_mime_get_default_application (mime_type);
+ g_free (mime_type);
+
+ g_return_if_fail (app != NULL);
tmpl = g_strdup ("/tmp/evolution.XXXXXX");
#ifdef HAVE_MKDTEMP
@@ -160,7 +231,7 @@ launch_external (const char *url, MailDisplay *md)
return;
}
- argv[0] = (char *)command;
+ argv[0] = app->command;
argv[1] = filename;
gnome_execute_async (tmpdir, 2, argv);
@@ -169,82 +240,86 @@ launch_external (const char *url, MailDisplay *md)
}
static void
-save_data_cb (GtkWidget *widget, gpointer user_data)
-{
- GtkFileSelection *file_select = (GtkFileSelection *)
- gtk_widget_get_ancestor (widget, GTK_TYPE_FILE_SELECTION);
-
- write_data_to_file (user_data,
- gtk_file_selection_get_filename (file_select),
- FALSE);
- gtk_widget_destroy (GTK_WIDGET (file_select));
-}
-
-static void
-save_data (const char *cid, MailDisplay *md)
+inline_cb (GtkWidget *widget, gpointer user_data)
{
- GtkFileSelection *file_select;
- char *filename;
- CamelMimePart *part;
-
- part = part_for_url (cid, md);
- g_return_if_fail (part != NULL);
- filename = make_safe_filename (g_get_home_dir (), part);
+ MailDisplay *md = gtk_object_get_data (user_data, "MailDisplay");
+ CamelMimePart *part = gtk_object_get_data (user_data, "CamelMimePart");
- file_select = GTK_FILE_SELECTION (gtk_file_selection_new ("Save Attachment"));
- gtk_file_selection_set_filename (file_select, filename);
- g_free (filename);
-
- gtk_signal_connect (GTK_OBJECT (file_select->ok_button), "clicked",
- GTK_SIGNAL_FUNC (save_data_cb), part);
- gtk_signal_connect_object (GTK_OBJECT (file_select->cancel_button),
- "clicked",
- GTK_SIGNAL_FUNC (gtk_widget_destroy),
- GTK_OBJECT (file_select));
+ if (mail_part_is_inline (part))
+ camel_mime_part_set_disposition (part, "attachment");
+ else
+ camel_mime_part_set_disposition (part, "inline");
- gtk_widget_show (GTK_WIDGET (file_select));
+ queue_redisplay (md);
}
static gboolean
-idle_redisplay (gpointer data)
+pixmap_press (GtkWidget *ebox, GdkEventButton *event, gpointer user_data)
{
- MailDisplay *md = data;
+ EPopupMenu menu[] = {
+ { N_("Save to Disk..."), NULL,
+ GTK_SIGNAL_FUNC (save_cb), 0 },
+ { N_("Open in %s..."), NULL,
+ GTK_SIGNAL_FUNC (launch_cb), 1 },
+ { N_("View Inline"), NULL,
+ GTK_SIGNAL_FUNC (inline_cb), 2 },
+ { NULL, NULL, NULL, 0 }
+ };
+ CamelMimePart *part;
+ MailMimeHandler *handler;
+ int mask;
- md->idle_id = 0;
- redisplay (md);
- return FALSE;
-}
+ if (event->button != 3)
+ return FALSE;
-static void
-queue_redisplay (MailDisplay *md)
-{
- if (!md->idle_id) {
- md->idle_id = g_idle_add_full (G_PRIORITY_LOW, idle_redisplay,
- md, NULL);
+ part = gtk_object_get_data (user_data, "CamelMimePart");
+ handler = mail_lookup_handler (gtk_object_get_data (user_data,
+ "mime_type"));
+
+ /* External view item */
+ if (handler && handler->application) {
+ menu[1].name = g_strdup_printf (menu[1].name,
+ handler->application->name);
+ } else {
+ menu[1].name = g_strdup_printf (menu[1].name,
+ N_("External Viewer"));
+ mask |= 1;
}
-}
-static void
-on_link_clicked (GtkHTML *html, const char *url, gpointer user_data)
-{
- MailDisplay *md = user_data;
+ /* Inline view item */
+ if (handler && handler->builtin) {
+ if (!mail_part_is_inline (part)) {
+ if (handler->component) {
+ OAF_Property *prop;
+ char *name;
+
+ prop = oaf_server_info_prop_find (
+ handler->component, "name");
+ if (!prop) {
+ prop = oaf_server_info_prop_find (
+ handler->component,
+ "description");
+ }
+ if (prop && prop->v._d == OAF_P_STRING)
+ name = prop->v._u.value_string;
+ else
+ name = "bonobo";
+ menu[2].name = g_strdup_printf (
+ N_("View Inline (via %s)"), name);
+ } else
+ menu[2].name = g_strdup (menu[2].name);
+ } else
+ menu[2].name = g_strdup (N_("Hide"));
+ } else {
+ menu[2].name = g_strdup (menu[2].name);
+ mask |= 2;
+ }
- if (!g_strncasecmp (url, "news:", 5) ||
- !g_strncasecmp (url, "nntp:", 5))
- g_warning ("Can't handle news URLs yet.");
- else if (!g_strncasecmp (url, "mailto:", 7))
- send_to_url (url);
- else if (!strncmp (url, "cid:", 4))
- save_data (url, md);
- else if (!strncmp (url, "x-evolution-external:", 21))
- launch_external (url, md);
- else if (!strcmp (url, "x-evolution-decode-pgp:")) {
- g_datalist_set_data (md->data, "show_pgp",
- GINT_TO_POINTER (1));
- queue_redisplay (md);
- } else
- gnome_url_show (url);
-}
+ e_popup_menu_run (menu, event, mask, 0, user_data);
+ g_free (menu[1].name);
+ g_free (menu[2].name);
+ return TRUE;
+}
static gboolean
on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data)
@@ -261,28 +336,77 @@ on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data)
GByteArray *ba;
CamelStream *cstream;
BonoboStream *bstream;
+ char *cid;
- if (strncmp (eb->classid, "cid:", 4) != 0)
+ cid = eb->classid;
+ if (!strncmp (cid, "popup:", 6))
+ cid += 6;
+ if (strncmp (cid, "cid:", 4) != 0)
return FALSE;
+
urls = g_datalist_get_data (md->data, "urls");
g_return_val_if_fail (urls != NULL, FALSE);
- medium = g_hash_table_lookup (urls, eb->classid);
+ medium = g_hash_table_lookup (urls, cid);
g_return_val_if_fail (CAMEL_IS_MEDIUM (medium), FALSE);
- wrapper = camel_medium_get_content_object (medium);
+
+ if (cid != eb->classid) {
+ /* This is a part wrapper */
+ const char *icon;
+ GtkWidget *pixmap, *ebox;
+
+ icon = gnome_vfs_mime_get_value (eb->type, "icon-filename");
+ if (icon) {
+ pixmap = gnome_pixmap_new_from_file_at_size (icon,
+ 24, 24);
+ } else {
+ char *filename;
+
+ filename = gnome_pixmap_file ("gnome-unknown.png");
+ pixmap = gnome_pixmap_new_from_file_at_size (filename,
+ 24, 24);
+ g_free (filename);
+ }
+
+ ebox = gtk_event_box_new ();
+ gtk_widget_set_sensitive (GTK_WIDGET (ebox), TRUE);
+ gtk_widget_add_events (GTK_WIDGET (ebox),
+ GDK_BUTTON_PRESS_MASK);
+ gtk_signal_connect (GTK_OBJECT (ebox), "button_press_event",
+ GTK_SIGNAL_FUNC (pixmap_press), ebox);
+ gtk_object_set_data (GTK_OBJECT (ebox), "MailDisplay", md);
+ gtk_object_set_data (GTK_OBJECT (ebox), "CamelMimePart",
+ medium);
+ gtk_object_set_data_full (GTK_OBJECT (ebox), "mime_type",
+ g_strdup (eb->type),
+ (GDestroyNotify)g_free);
+
+ gtk_container_add (GTK_CONTAINER (ebox), pixmap);
+ gtk_widget_show_all (ebox);
+ gtk_container_add (GTK_CONTAINER (eb), ebox);
+ return TRUE;
+ }
component = gnome_vfs_mime_get_default_component (eb->type);
if (!component)
return FALSE;
embedded = bonobo_widget_new_subdoc (component->iid, NULL);
- if (!embedded)
+ if (embedded) {
+ /* FIXME: as of bonobo 0.18, there's an extra
+ * client_site dereference in the BonoboWidget
+ * destruction path that we have to balance out to
+ * prevent problems.
+ */
+ bonobo_object_ref (bonobo_widget_get_client_site (
+ BONOBO_WIDGET (embedded)));
+ } else
embedded = bonobo_widget_new_control (component->iid, NULL);
CORBA_free (component);
if (!embedded)
return FALSE;
- server = bonobo_widget_get_server (BONOBO_WIDGET (embedded));
+ 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) {
@@ -293,6 +417,7 @@ on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data)
/* 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 (medium);
camel_data_wrapper_write_to_stream (wrapper, cstream);
/* ...convert the CamelStreamMem to a BonoboStreamMem... */
@@ -422,9 +547,15 @@ clear_data (CamelObject *object, gpointer event_data, gpointer user_data)
}
static void
-redisplay (MailDisplay *md)
+redisplay (MailDisplay *md, gboolean unscroll)
{
GtkAdjustment *adj;
+ gfloat oldv;
+
+ if (!unscroll) {
+ adj = e_scroll_frame_get_vadjustment (md->scroll);
+ oldv = adj->value;
+ }
md->stream = gtk_html_begin (md->html);
mail_html_write (md->html, md->stream, "%s%s", HTML_HEADER,
@@ -439,13 +570,17 @@ redisplay (MailDisplay *md)
gtk_html_end (md->html, md->stream, GTK_HTML_STREAM_OK);
md->stream = NULL;
- adj = e_scroll_frame_get_vadjustment (md->scroll);
- gtk_adjustment_set_value (adj, 0);
- e_scroll_frame_set_vadjustment (md->scroll, adj);
-
- adj = e_scroll_frame_get_hadjustment (md->scroll);
- gtk_adjustment_set_value (adj, 0);
- e_scroll_frame_set_hadjustment (md->scroll, adj);
+ if (unscroll) {
+ adj = e_scroll_frame_get_hadjustment (md->scroll);
+ gtk_adjustment_set_value (adj, 0);
+ e_scroll_frame_set_hadjustment (md->scroll, adj);
+ } else {
+ adj = e_scroll_frame_get_vadjustment (md->scroll);
+ if (oldv < adj->upper) {
+ gtk_adjustment_set_value (adj, oldv);
+ e_scroll_frame_set_vadjustment (md->scroll, adj);
+ }
+ }
}
/**
@@ -472,7 +607,7 @@ mail_display_set_message (MailDisplay *md, CamelMedium *medium)
md->current_message = (CamelMimeMessage*)medium;
g_datalist_init (md->data);
- redisplay (md);
+ redisplay (md, TRUE);
if (medium) {
camel_object_hook_event (CAMEL_OBJECT (medium), "finalize",
clear_data, *(md->data));