diff options
-rw-r--r-- | mail/Makefile.am | 2 | ||||
-rw-r--r-- | mail/e-mail-browser.c | 29 | ||||
-rw-r--r-- | mail/e-mail-display.c | 627 | ||||
-rw-r--r-- | mail/e-mail-display.h | 83 | ||||
-rw-r--r-- | mail/e-mail-reader.c | 45 | ||||
-rw-r--r-- | mail/e-mail-shell-view-private.c | 23 | ||||
-rw-r--r-- | mail/em-folder-view.c | 59 | ||||
-rw-r--r-- | mail/em-format-html-display.c | 1313 | ||||
-rw-r--r-- | mail/em-format-html-display.h | 30 | ||||
-rw-r--r-- | mail/em-format-html.c | 749 | ||||
-rw-r--r-- | mail/em-format-html.h | 5 | ||||
-rw-r--r-- | mail/em-html-stream.c | 147 | ||||
-rw-r--r-- | mail/em-html-stream.h | 55 |
13 files changed, 1755 insertions, 1412 deletions
diff --git a/mail/Makefile.am b/mail/Makefile.am index b7b2a1d48a..cf7f71acea 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -37,6 +37,8 @@ module_LTLIBRARIES = \ libevolution_module_mail_la_SOURCES = \ e-mail-browser.c \ e-mail-browser.h \ + e-mail-display.c \ + e-mail-display.h \ e-mail-label-dialog.c \ e-mail-label-dialog.h \ e-mail-label-list-store.c \ diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c index 0e4239d4a7..8d685537bf 100644 --- a/mail/e-mail-browser.c +++ b/mail/e-mail-browser.c @@ -218,6 +218,23 @@ mail_browser_message_selected_cb (EMailBrowser *browser, } static void +mail_browser_status_message_cb (EMailBrowser *browser, + const gchar *status_message) +{ + GtkStatusbar *statusbar; + guint context_id; + + statusbar = GTK_STATUSBAR (browser->priv->statusbar); + context_id = gtk_statusbar_get_context_id (statusbar, G_STRFUNC); + + /* Always pop first. This prevents messages from piling up. */ + gtk_statusbar_pop (statusbar, context_id); + + if (status_message != NULL && *status_message != '\0') + gtk_statusbar_push (statusbar, context_id, status_message); +} + +static void mail_browser_set_shell_module (EMailBrowser *browser, EShellModule *shell_module) { @@ -320,6 +337,7 @@ mail_browser_dispose (GObject *object) static void mail_browser_constructed (GObject *object) { + EMFormatHTMLDisplay *html_display; EMailBrowserPrivate *priv; EMailReader *reader; EShellModule *shell_module; @@ -329,6 +347,7 @@ mail_browser_constructed (GObject *object) GtkUIManager *ui_manager; GtkWidget *container; GtkWidget *widget; + GtkHTML *html; const gchar *domain; guint merge_id; @@ -338,10 +357,14 @@ mail_browser_constructed (GObject *object) ui_manager = priv->ui_manager; domain = GETTEXT_PACKAGE; + html_display = e_mail_reader_get_html_display (reader); shell_module = e_mail_reader_get_shell_module (reader); + shell = e_shell_module_get_shell (shell_module); e_shell_watch_window (shell, GTK_WINDOW (object)); + html = EM_FORMAT_HTML (html_display)->html; + /* The message list is a widget, but it is not shown in the browser. * Unfortunately, the widget is inseparable from its model, and the * model is all we need. */ @@ -352,6 +375,10 @@ mail_browser_constructed (GObject *object) priv->message_list, "message-selected", G_CALLBACK (mail_browser_message_selected_cb), object); + g_signal_connect_swapped ( + html, "status-message", + G_CALLBACK (mail_browser_status_message_cb), object); + e_mail_reader_init (reader); action_group = priv->action_group; @@ -409,7 +436,7 @@ mail_browser_constructed (GObject *object) container = widget; - widget = GTK_WIDGET (((EMFormatHTML *) priv->html_display)->html); + widget = GTK_WIDGET (EM_FORMAT_HTML (html_display)->html); gtk_container_add (GTK_CONTAINER (container), widget); gtk_widget_show (widget); } diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c new file mode 100644 index 0000000000..8ad72ebf86 --- /dev/null +++ b/mail/e-mail-display.c @@ -0,0 +1,627 @@ +/* + * e-mail-display.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-mail-display.h" + +#include <string.h> +#include <glib/gi18n.h> + +#include "e-util/e-util.h" + +#define E_MAIL_DISPLAY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate)) + +struct _EMailDisplayPrivate { + EMFormatHTML *formatter; +}; + +enum { + PROP_0, + PROP_ANIMATE, + PROP_CARET_MODE, + PROP_FORMATTER +}; + +enum { + POPUP_EVENT, + STATUS_MESSAGE, + LAST_SIGNAL +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static gboolean +mail_display_emit_popup_event (EMailDisplay *display, + GdkEventButton *event, + const gchar *uri, + EMFormatPURI *puri) +{ + CamelMimePart *mime_part; + gboolean stop_handlers = FALSE; + + mime_part = (puri != NULL) ? puri->part : NULL; + + g_signal_emit ( + display, signals[POPUP_EVENT], 0, + event, uri, mime_part, &stop_handlers); + + return stop_handlers; +} + +static void +mail_display_emit_status_message (EMailDisplay *display, + const gchar *status_message) +{ + g_signal_emit (display, signals[STATUS_MESSAGE], 0, status_message); +} + +static void +mail_display_get_uri_puri (EMailDisplay *display, + GdkEventButton *event, + gchar **uri, + EMFormatPURI **puri) +{ + EMFormat *formatter; + GtkHTML *html; + gchar *text_uri; + gchar *image_uri; + gboolean is_cid; + + html = GTK_HTML (display); + formatter = EM_FORMAT (display->priv->formatter); + + if (event != NULL) { + text_uri = gtk_html_get_url_at (html, event->x, event->y); + image_uri = gtk_html_get_image_src_at (html, event->x, event->y); + } else { + text_uri = gtk_html_get_cursor_url (html); + image_uri = gtk_html_get_cursor_image_src (html); + } + + is_cid = (image_uri != NULL) && + (g_ascii_strncasecmp (image_uri, "cid:", 4) == 0); + + if (image_uri != NULL) { + if (strstr (image_uri, "://") == NULL && !is_cid) { + gchar *temp; + + temp = g_strconcat ("file://", image_uri, NULL); + g_free (image_uri); + temp = image_uri; + } + } + + if (puri != NULL) { + if (text_uri != NULL) + *puri = em_format_find_puri (formatter, text_uri); + + if (*puri == NULL && image_uri != NULL) + *puri = em_format_find_puri (formatter, image_uri); + } + + if (uri != NULL) { + *uri = NULL; + if (is_cid) { + if (text_uri != NULL) + *uri = g_strdup_printf ( + "%s\n%s", text_uri, image_uri); + else { + *uri = image_uri; + image_uri = NULL; + } + } else { + *uri = text_uri; + text_uri = NULL; + } + } + + g_free (text_uri); + g_free (image_uri); +} + +static void +mail_display_update_formatter_colors (EMailDisplay *display) +{ + EMFormatHTMLColorType type; + EMFormatHTML *formatter; + GdkColor *color; + GtkStyle *style; + gint state; + + state = GTK_WIDGET_STATE (display); + formatter = display->priv->formatter; + + style = gtk_widget_get_style (GTK_WIDGET (display)); + if (style == NULL) + return; + + g_object_freeze_notify (G_OBJECT (formatter)); + + color = &style->bg[state]; + type = EM_FORMAT_HTML_COLOR_BODY; + em_format_html_set_color (formatter, type, color); + + color = &style->base[GTK_STATE_NORMAL]; + type = EM_FORMAT_HTML_COLOR_CONTENT; + em_format_html_set_color (formatter, type, color); + + color = &style->dark[state]; + type = EM_FORMAT_HTML_COLOR_FRAME; + em_format_html_set_color (formatter, type, color); + + color = &style->fg[state]; + type = EM_FORMAT_HTML_COLOR_HEADER; + em_format_html_set_color (formatter, type, color); + + color = &style->text[state]; + type = EM_FORMAT_HTML_COLOR_TEXT; + em_format_html_set_color (formatter, type, color); + + g_object_thaw_notify (G_OBJECT (formatter)); +} + +static void +mail_display_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ANIMATE: + e_mail_display_set_animate ( + E_MAIL_DISPLAY (object), + g_value_get_boolean (value)); + return; + + case PROP_CARET_MODE: + e_mail_display_set_caret_mode ( + E_MAIL_DISPLAY (object), + g_value_get_boolean (value)); + return; + + case PROP_FORMATTER: + e_mail_display_set_formatter ( + E_MAIL_DISPLAY (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_display_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ANIMATE: + g_value_set_boolean ( + value, e_mail_display_get_animate ( + E_MAIL_DISPLAY (object))); + return; + + case PROP_CARET_MODE: + g_value_set_boolean ( + value, e_mail_display_get_caret_mode ( + E_MAIL_DISPLAY (object))); + return; + + case PROP_FORMATTER: + g_value_set_object ( + value, e_mail_display_get_formatter ( + E_MAIL_DISPLAY (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_display_dispose (GObject *object) +{ + EMailDisplayPrivate *priv; + + priv = E_MAIL_DISPLAY_GET_PRIVATE (object); + + if (priv->formatter) { + g_object_unref (priv->formatter); + priv->formatter = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +mail_display_realize (GtkWidget *widget) +{ + /* Chain up to parent's realize() method. */ + GTK_WIDGET_CLASS (parent_class)->realize (widget); + + mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget)); +} + +static void +mail_display_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + EMailDisplayPrivate *priv; + + priv = E_MAIL_DISPLAY_GET_PRIVATE (widget); + + /* Chain up to parent's style_set() method. */ + GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style); + + mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget)); + em_format_redraw (EM_FORMAT (priv->formatter)); +} + +static gboolean +mail_display_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + if (event->button == 3) { + EMailDisplay *display; + EMFormatPURI *puri = NULL; + gboolean stop_handlers = TRUE; + gchar *uri = NULL; + + display = E_MAIL_DISPLAY (widget); + mail_display_get_uri_puri (display, event, &uri, &puri); + + if (uri == NULL || !g_str_has_prefix (uri, "##")) + stop_handlers = mail_display_emit_popup_event ( + display, event, uri, puri); + + g_free (uri); + + if (stop_handlers) + return TRUE; + } + + /* Chain up to parent's button_press_event() method. */ + return GTK_WIDGET_CLASS (parent_class)-> + button_press_event (widget, event); +} + +static gboolean +mail_display_scroll_event (GtkWidget *widget, + GdkEventScroll *event) +{ + if (event->state & GDK_CONTROL_MASK) { + switch (event->direction) { + case GDK_SCROLL_UP: + gtk_html_zoom_in (GTK_HTML (widget)); + return TRUE; + case GDK_SCROLL_DOWN: + gtk_html_zoom_out (GTK_HTML (widget)); + return TRUE; + default: + break; + } + } + + return FALSE; +} + +static void +mail_display_link_clicked (GtkHTML *html, + const gchar *uri) +{ + EMailDisplayPrivate *priv; + + priv = E_MAIL_DISPLAY_GET_PRIVATE (html); + g_return_if_fail (priv->formatter != NULL); + + if (g_str_has_prefix (uri, "##")) { + guint32 flags; + + flags = priv->formatter->header_wrap_flags; + + if (strcmp (uri, "##TO##") == 0) { + if (!(flags & EM_FORMAT_HTML_HEADER_TO)) + flags |= EM_FORMAT_HTML_HEADER_TO; + else + flags &= ~EM_FORMAT_HTML_HEADER_TO; + } else if (strcmp (uri, "##CC##") == 0) { + if (!(flags & EM_FORMAT_HTML_HEADER_CC)) + flags |= EM_FORMAT_HTML_HEADER_CC; + else + flags |= EM_FORMAT_HTML_HEADER_CC; + } else if (strcmp (uri, "##BCC##") == 0) { + if (!(flags & EM_FORMAT_HTML_HEADER_BCC)) + flags |= EM_FORMAT_HTML_HEADER_BCC; + else + flags |= EM_FORMAT_HTML_HEADER_BCC; + } + + priv->formatter->header_wrap_flags = flags; + em_format_redraw (EM_FORMAT (priv->formatter)); + + } else if (*uri == '#') + gtk_html_jump_to_anchor (html, uri + 1); + + else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0) + /* ignore */ ; + + else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0) + /* ignore */ ; + + else { + gpointer parent; + + parent = gtk_widget_get_toplevel (GTK_WIDGET (html)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + e_show_uri (parent, uri); + } +} + +static void +mail_display_on_url (GtkHTML *html, + const gchar *uri) +{ + EMailDisplay *display; + CamelInternetAddress *address; + CamelURL *curl; + const gchar *format = NULL; + gchar *message = NULL; + gchar *who; + + display = E_MAIL_DISPLAY (html); + + if (uri == NULL || *uri == '\0') + goto exit; + + if (g_str_has_prefix (uri, "mailto:")) + format = _("Click to mail %s"); + else if (g_str_has_prefix (uri, "callto:")) + format = _("Click to call %s"); + else if (g_str_has_prefix (uri, "h323:")) + format = _("Click to call %s"); + else if (g_str_has_prefix (uri, "sip:")) + format = _("Click to call %s"); + else if (g_str_has_prefix (uri, "##")) + message = g_strdup (_("Click to hide/unhide addresses")); + else + message = g_strdup_printf (_("Click to open %s"), uri); + + if (format == NULL) + goto exit; + + curl = camel_url_new (uri, NULL); + address = camel_internet_address_new (); + camel_address_decode (CAMEL_ADDRESS (address), curl->path); + who = camel_address_format (CAMEL_ADDRESS (address)); + camel_object_unref (address); + camel_url_free (curl); + + if (who == NULL) + who = g_strdup (strchr (uri, ':') + 1); + + message = g_strdup_printf (format, who); + + g_free (who); + +exit: + mail_display_emit_status_message (display, message); + + g_free (message); +} + +static void +mail_display_iframe_created (GtkHTML *html, + GtkHTML *iframe) +{ + g_signal_connect_swapped ( + iframe, "button-press-event", + G_CALLBACK (mail_display_button_press_event), html); +} + +static void +mail_display_class_init (EMailDisplayClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkHTMLClass *html_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EMailDisplayPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_display_set_property; + object_class->get_property = mail_display_get_property; + object_class->dispose = mail_display_dispose; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->realize = mail_display_realize; + widget_class->style_set = mail_display_style_set; + widget_class->button_press_event = mail_display_button_press_event; + widget_class->scroll_event = mail_display_scroll_event; + + html_class = GTK_HTML_CLASS (class); + html_class->link_clicked = mail_display_link_clicked; + html_class->on_url = mail_display_on_url; + html_class->iframe_created = mail_display_iframe_created; + + g_object_class_install_property ( + object_class, + PROP_ANIMATE, + g_param_spec_boolean ( + "animate", + "Animate Images", + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_CARET_MODE, + g_param_spec_boolean ( + "caret-mode", + "Caret Mode", + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_FORMATTER, + g_param_spec_object ( + "formatter", + "HTML Formatter", + NULL, + EM_TYPE_FORMAT_HTML, + G_PARAM_READWRITE)); + + signals[POPUP_EVENT] = g_signal_new ( + "popup-event", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailDisplayClass, popup_event), + g_signal_accumulator_true_handled, NULL, + e_marshal_BOOLEAN__BOXED_POINTER_POINTER, + G_TYPE_BOOLEAN, 3, + GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE, + G_TYPE_POINTER, + G_TYPE_POINTER); + + signals[STATUS_MESSAGE] = g_signal_new ( + "status-message", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EMailDisplayClass, status_message), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); +} + +static void +mail_display_init (EMailDisplay *display) +{ + display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display); +} + +GType +e_mail_display_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EMailDisplayClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) mail_display_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMailDisplay), + 0, /* n_preallocs */ + (GInstanceInitFunc) mail_display_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_HTML, "EMailDisplay", &type_info, 0); + } + + return type; +} + +gboolean +e_mail_display_get_animate (EMailDisplay *display) +{ + /* XXX This is just here to maintain symmetry + * with e_mail_display_set_animate(). */ + + g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE); + + return gtk_html_get_animate (GTK_HTML (display)); +} + +void +e_mail_display_set_animate (EMailDisplay *display, + gboolean animate) +{ + /* XXX GtkHTML does not utilize GObject properties as well + * as it could. This just wraps gtk_html_set_animate() + * so we can get a "notify::animate" signal. */ + + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); + + gtk_html_set_animate (GTK_HTML (display), animate); + + g_object_notify (G_OBJECT (display), "animate"); +} + +gboolean +e_mail_display_get_caret_mode (EMailDisplay *display) +{ + /* XXX This is just here to maintain symmetry + * with e_mail_display_get_caret_mode(). */ + + g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE); + + return gtk_html_get_caret_mode (GTK_HTML (display)); +} + +void +e_mail_display_set_caret_mode (EMailDisplay *display, + gboolean caret_mode) +{ + /* XXX GtkHTML does not utilize GObject properties as well + * as it could. This just wraps gtk_html_set_caret_mode() + * so we can get a "notify::caret-mode" signal. */ + + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); + + gtk_html_set_caret_mode (GTK_HTML (display), caret_mode); + + g_object_notify (G_OBJECT (display), "caret-mode"); +} + +EMFormatHTML * +e_mail_display_get_formatter (EMailDisplay *display) +{ + g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); + + return display->priv->formatter; +} + +void +e_mail_display_set_formatter (EMailDisplay *display, + EMFormatHTML *formatter) +{ + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); + g_return_if_fail (EM_IS_FORMAT_HTML (formatter)); + + if (display->priv->formatter != NULL) + g_object_unref (display->priv->formatter); + + display->priv->formatter = g_object_ref (formatter); + + g_object_notify (G_OBJECT (display), "formatter"); +} diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h new file mode 100644 index 0000000000..f1d5fc583f --- /dev/null +++ b/mail/e-mail-display.h @@ -0,0 +1,83 @@ +/* + * e-mail-display.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_DISPLAY_H +#define E_MAIL_DISPLAY_H + +#include <gtkhtml/gtkhtml.h> +#include <mail/em-format-html.h> + +/* Standard GObject macros */ +#define E_TYPE_MAIL_DISPLAY \ + (e_mail_display_get_type ()) +#define E_MAIL_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplay)) +#define E_MAIL_DISPLAY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_DISPLAY, EMailDisplayClass)) +#define E_IS_MAIL_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_DISPLAY)) +#define E_IS_MAIL_DISPLAY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_DISPLAY)) +#define E_MAIL_DISPLAY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayClass)) + +G_BEGIN_DECLS + +typedef struct _EMailDisplay EMailDisplay; +typedef struct _EMailDisplayClass EMailDisplayClass; +typedef struct _EMailDisplayPrivate EMailDisplayPrivate; + +struct _EMailDisplay { + GtkHTML parent; + EMailDisplayPrivate *priv; +}; + +struct _EMailDisplayClass { + GtkHTMLClass parent_class; + + /* Signals */ + gboolean (*popup_event) (EMailDisplay *display, + GdkEventButton *event, + const gchar *uri, + EMFormatPURI *puri); + void (*status_message) (EMailDisplay *display, + const gchar *status_message); +}; + +GType e_mail_display_get_type (void); +gboolean e_mail_display_get_animate (EMailDisplay *display); +void e_mail_display_set_animate (EMailDisplay *display, + gboolean animate); +gboolean e_mail_display_get_caret_mode (EMailDisplay *display); +void e_mail_display_set_caret_mode (EMailDisplay *display, + gboolean caret_mode); +EMFormatHTML * e_mail_display_get_formatter (EMailDisplay *display); +void e_mail_display_set_formatter (EMailDisplay *display, + EMFormatHTML *formatter); + +G_END_DECLS + +#endif /* E_MAIL_DISPLAY_H */ diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c index ab7c86c160..b058fda07e 100644 --- a/mail/e-mail-reader.c +++ b/mail/e-mail-reader.c @@ -1620,40 +1620,6 @@ static GtkToggleActionEntry mail_reader_toggle_entries[] = { FALSE } }; -static void -mail_reader_link_clicked_cb (EMailReader *reader, - const gchar *uri, - EMFormatHTMLDisplay *html_display) -{ - GtkHTML *html; - GtkWindow *window; - MessageList *message_list; - const gchar *folder_uri; - - html = EM_FORMAT_HTML (html_display)->html; - message_list = e_mail_reader_get_message_list (reader); - window = e_mail_reader_get_window (reader); - folder_uri = message_list->folder_uri; - - if (g_str_has_prefix (uri, "##")) - return; - - if (g_ascii_strncasecmp (uri, "mailto:", 7) == 0) - em_utils_compose_new_message_with_mailto (uri, folder_uri); - - else if (*uri == '#') - gtk_html_jump_to_anchor (html, uri + 1); - - else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0) - /* ignore */ ; - - else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0) - /* ignore */ ; - - else - e_show_uri (window, uri); -} - static gboolean mail_reader_html_button_release_event_cb (EMailReader *reader, GdkEventButton *button, @@ -2057,6 +2023,7 @@ e_mail_reader_init (EMailReader *reader) MessageList *message_list; GConfBridge *bridge; GtkAction *action; + GtkHTML *html; const gchar *action_name; const gchar *key; @@ -2070,6 +2037,8 @@ e_mail_reader_init (EMailReader *reader) shell = e_shell_module_get_shell (shell_module); shell_settings = e_shell_get_shell_settings (shell); + html = EM_FORMAT_HTML (html_display)->html; + gtk_action_group_add_actions ( action_group, mail_reader_entries, G_N_ELEMENTS (mail_reader_entries), reader); @@ -2136,7 +2105,7 @@ e_mail_reader_init (EMailReader *reader) e_binding_new ( G_OBJECT (shell_settings), "mail-show-animated-images", - G_OBJECT (html_display), "animate"); + G_OBJECT (html), "animate"); e_binding_new ( G_OBJECT (shell_settings), "mail-show-sender-photo", @@ -2147,15 +2116,11 @@ e_mail_reader_init (EMailReader *reader) e_mutual_binding_new ( G_OBJECT (action), "active", - G_OBJECT (html_display), "caret-mode"); + G_OBJECT (html), "caret-mode"); /* Connect signals. */ g_signal_connect_swapped ( - html_display, "link-clicked", - G_CALLBACK (mail_reader_link_clicked_cb), reader); - - g_signal_connect_swapped ( EM_FORMAT_HTML (html_display)->html, "button-release-event", G_CALLBACK (mail_reader_html_button_release_event_cb), reader); diff --git a/mail/e-mail-shell-view-private.c b/mail/e-mail-shell-view-private.c index 994f250565..460856ba5e 100644 --- a/mail/e-mail-shell-view-private.c +++ b/mail/e-mail-shell-view-private.c @@ -89,6 +89,19 @@ mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view) } static void +mail_shell_view_reader_status_message_cb (EMailShellView *mail_shell_view, + const gchar *status_message) +{ + EShellView *shell_view; + EShellTaskbar *shell_taskbar; + + shell_view = E_SHELL_VIEW (mail_shell_view); + shell_taskbar = e_shell_view_get_shell_taskbar (shell_view); + + e_shell_taskbar_set_message (shell_taskbar, status_message); +} + +static void mail_shell_view_load_view_collection (EShellViewClass *shell_view_class) { GalViewCollection *collection; @@ -160,6 +173,7 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) EShellSettings *shell_settings; EShellSidebar *shell_sidebar; EShellWindow *shell_window; + EMFormatHTMLDisplay *html_display; EMFolderTreeModel *folder_tree_model; EMFolderTree *folder_tree; RuleContext *context; @@ -168,6 +182,7 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) GtkUIManager *ui_manager; MessageList *message_list; EMailReader *reader; + GtkHTML *html; const gchar *source; guint merge_id; gchar *uri; @@ -197,11 +212,14 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) priv->mail_shell_sidebar = g_object_ref (shell_sidebar); reader = E_MAIL_READER (shell_content); + html_display = e_mail_reader_get_html_display (reader); message_list = e_mail_reader_get_message_list (reader); mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar); folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar); + html = EM_FORMAT_HTML (html_display)->html; + g_signal_connect_swapped ( folder_tree, "folder-selected", G_CALLBACK (mail_shell_view_folder_tree_selected_cb), @@ -243,6 +261,11 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) G_CALLBACK (e_mail_shell_view_update_search_filter), mail_shell_view); + g_signal_connect_swapped ( + html, "status-message", + G_CALLBACK (mail_shell_view_reader_status_message_cb), + mail_shell_view); + e_mail_shell_view_actions_init (mail_shell_view); e_mail_shell_view_update_search_filter (mail_shell_view); e_mail_reader_init (reader); diff --git a/mail/em-folder-view.c b/mail/em-folder-view.c index 9783a7157c..fb449e558c 100644 --- a/mail/em-folder-view.c +++ b/mail/em-folder-view.c @@ -238,7 +238,7 @@ emfv_init(GObject *o) // em_format_set_session ((EMFormat *) emfv->preview, session); // g_signal_connect(emfv->preview, "link_clicked", G_CALLBACK(emfv_format_link_clicked), emfv); g_signal_connect(emfv->preview, "popup_event", G_CALLBACK(emfv_format_popup_event), emfv); - g_signal_connect (emfv->preview, "on_url", G_CALLBACK (emfv_on_url_cb), emfv); +// g_signal_connect (emfv->preview, "on_url", G_CALLBACK (emfv_on_url_cb), emfv); // g_signal_connect (((EMFormatHTML *)emfv->preview)->html, "button-release-event", G_CALLBACK (emfv_on_html_button_released_cb), emfv); //#ifdef ENABLE_PROFILING // g_signal_connect(emfv->preview, "complete", G_CALLBACK (emfv_format_complete), emfv); @@ -268,7 +268,7 @@ emfv_class_init(GObjectClass *klass) ((EMFolderViewClass *)klass)->set_message = emfv_set_message; ((EMFolderViewClass *)klass)->activate = emfv_activate; - ((EMFolderViewClass *)klass)->on_url = emfv_on_url; +// ((EMFolderViewClass *)klass)->on_url = emfv_on_url; signals[EMFV_ON_URL] = g_signal_new ("on-url", G_OBJECT_CLASS_TYPE (klass), @@ -1077,58 +1077,3 @@ emfv_setting_notify(GConfClient *gconf, guint cnxn_id, GConfEntry *entry, EMFold break; } } } - -static void -emfv_on_url (EMFolderView *emfv, const char *uri, const char *nice_uri) -{ - if (emfv->statusbar_active) { - if (emfv->uic) { - bonobo_ui_component_set_status (emfv->uic, nice_uri, NULL); - /* Make sure the node keeps existing if nice_url == NULL */ - if (!nice_uri) - bonobo_ui_component_set_translate ( - emfv->uic, "/", "<status><item name=\"main\"/></status>", NULL); - } - } -} - -static void -emfv_on_url_cb (GObject *emitter, const char *url, EMFolderView *emfv) -{ - char *nice_url = NULL; - - if (url) { - if (strncmp (url, "mailto:", 7) == 0) { - CamelInternetAddress *cia = camel_internet_address_new(); - CamelURL *curl; - char *addr; - - curl = camel_url_new(url, NULL); - camel_address_decode((CamelAddress *)cia, curl->path); - addr = camel_address_format((CamelAddress *)cia); - nice_url = g_strdup_printf (_("Click to mail %s"), addr&&addr[0]?addr:(url + 7)); - g_free(addr); - camel_url_free(curl); - camel_object_unref(cia); - } else if (strncmp (url, "callto:", 7) == 0 || strncmp (url, "h323:", 5) == 0 || strncmp (url, "sip:", 4) == 0) { - CamelInternetAddress *cia = camel_internet_address_new(); - CamelURL *curl; - char *addr; - - curl = camel_url_new(url, NULL); - camel_address_decode((CamelAddress *)cia, curl->path); - addr = camel_address_format((CamelAddress *)cia); - nice_url = g_strdup_printf (_("Click to call %s"), addr&&addr[0]?addr:(url + 7)); - g_free(addr); - camel_url_free(curl); - camel_object_unref(cia); - } else if (!strncmp (url, "##", 2)) { - nice_url = g_strdup (_("Click to hide/unhide addresses")); - } else - nice_url = g_strdup_printf (_("Click to open %s"), url); - } - - g_signal_emit (emfv, signals[EMFV_ON_URL], 0, url, nice_url); - - g_free (nice_url); -} diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index 70b92c39ff..72cec78559 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -75,6 +75,7 @@ #include "mail-config.h" +#include "e-mail-display.h" #include "em-format-html-display.h" #include "e-searching-tokenizer.h" #include "em-icon-stream.h" @@ -126,20 +127,47 @@ struct _EMFormatHTMLDisplayPrivate { gboolean updated; }; -enum { - PROP_0, - PROP_ANIMATE, - PROP_CARET_MODE +struct _smime_pobject { + EMFormatHTMLPObject object; + + int signature; + CamelCipherValidity *valid; + GtkWidget *widget; }; -static int efhd_html_button_press_event (GtkWidget *widget, GdkEventButton *event, EMFormatHTMLDisplay *efh); -static void efhd_html_link_clicked (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd); -static void efhd_html_on_url (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd); +/* TODO: move the dialogue elsehwere */ +/* FIXME: also in em-format-html.c */ +static const struct { + const char *icon, *shortdesc, *description; +} smime_sign_table[5] = { + { "stock_signature-bad", N_("Unsigned"), N_("This message is not signed. There is no guarantee that this message is authentic.") }, + { "stock_signature-ok", N_("Valid signature"), N_("This message is signed and is valid meaning that it is very likely that this message is authentic.") }, + { "stock_signature-bad", N_("Invalid signature"), N_("The signature of this message cannot be verified, it may have been altered in transit.") }, + { "stock_signature", N_("Valid signature, but cannot verify sender"), N_("This message is signed with a valid signature, but the sender of the message cannot be verified.") }, + { "stock_signature-bad", N_("Signature exists, but need public key"), N_("This message is signed with a signature, but there is no corresponding public key.") }, + +}; + +static const struct { + const char *icon, *shortdesc, *description; +} smime_encrypt_table[4] = { + { "stock_lock-broken", N_("Unencrypted"), N_("This message is not encrypted. Its content may be viewed in transit across the Internet.") }, + { "stock_lock-ok", N_("Encrypted, weak"), N_("This message is encrypted, but with a weak encryption algorithm. It would be difficult, but not impossible for an outsider to view the content of this message in a practical amount of time.") }, + { "stock_lock-ok", N_("Encrypted"), N_("This message is encrypted. It would be difficult for an outsider to view the content of this message.") }, + { "stock_lock-ok", N_("Encrypted, strong"), N_("This message is encrypted, with a strong encryption algorithm. It would be very difficult for an outsider to view the content of this message in a practical amount of time.") }, +}; + +static const char *smime_sign_colour[5] = { + "", " bgcolor=\"#88bb88\"", " bgcolor=\"#bb8888\"", " bgcolor=\"#e8d122\"","" +}; static void efhd_attachment_frame(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri); static gboolean efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject); static void efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info); static void efhd_message_update_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info); +static void efhd_attachment_button_show (GtkWidget *w, void *data); +static gboolean efhd_attachment_button (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject); +static gboolean efhd_attachment_optional (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *object); static void efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd); struct _attach_puri { @@ -177,151 +205,250 @@ struct _attach_puri { }; -static void efhd_iframe_created(GtkHTML *html, GtkHTML *iframe, EMFormatHTMLDisplay *efh); -/*static void efhd_url_requested(GtkHTML *html, const char *url, GtkHTMLStream *handle, EMFormatHTMLDisplay *efh); - static gboolean efhd_object_requested(GtkHTML *html, GtkHTMLEmbedded *eb, EMFormatHTMLDisplay *efh);*/ - static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info); -static const EMFormatHandler *efhd_find_handler(EMFormat *emf, const char *mime_type); -static void efhd_format_clone(EMFormat *, CamelFolder *folder, const char *, CamelMimeMessage *msg, EMFormat *); -static void efhd_format_error(EMFormat *emf, CamelStream *stream, const char *txt); -static void efhd_format_source(EMFormat *, CamelStream *, CamelMimePart *); -static void efhd_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *); -static void efhd_format_optional(EMFormat *, CamelStream *, CamelMimePart *, CamelStream *); -static void efhd_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid); static void efhd_complete(EMFormat *); gboolean efhd_mnemonic_show_bar (GtkWidget *widget, gboolean focus, GtkWidget *efhd); static void efhd_builtin_init(EMFormatHTMLDisplayClass *efhc); -enum { - EFHD_LINK_CLICKED, - EFHD_POPUP_EVENT, - EFHD_ON_URL, - EFHD_LAST_SIGNAL, -}; - -static guint efhd_signals[EFHD_LAST_SIGNAL] = { 0 }; - -static EMFormatHTMLClass *efhd_parent; -static EMFormatClass *efhd_format_class; +static EMFormatHTMLClass *parent_class; static void -efhd_gtkhtml_realize(GtkHTML *html, EMFormatHTMLDisplay *efhd) +efhd_xpkcs7mime_free (EMFormatHTMLPObject *o) { - EMFormatHTMLColorType type; - EMFormatHTML *efh; - GdkColor *color; - GtkStyle *style; - gint state; + struct _smime_pobject *po = (struct _smime_pobject *)o; - efh = EM_FORMAT_HTML (efhd); - state = GTK_WIDGET_STATE (html); + if (po->widget) + gtk_widget_destroy(po->widget); + camel_cipher_validity_free(po->valid); +} - style = gtk_widget_get_style (GTK_WIDGET (html)); - if (style == NULL) - return; +static void +efhd_xpkcs7mime_info_response (GtkWidget *widget, + guint button, + struct _smime_pobject *po) +{ + gtk_widget_destroy (widget); + po->widget = NULL; +} - g_object_freeze_notify (G_OBJECT (efh)); +#ifdef HAVE_NSS +static void +efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button, + struct _smime_pobject *po) +{ + CamelCipherCertInfo *info = g_object_get_data((GObject *)button, "e-cert-info"); + ECertDB *db = e_cert_db_peek(); + ECert *ec = NULL; - color = &style->bg[state]; - type = EM_FORMAT_HTML_COLOR_BODY; - em_format_html_set_color (efh, type, color); + if (info->email) + ec = e_cert_db_find_cert_by_email_address(db, info->email, NULL); - color = &style->base[GTK_STATE_NORMAL]; - type = EM_FORMAT_HTML_COLOR_CONTENT; - em_format_html_set_color (efh, type, color); + if (ec == NULL && info->name) + ec = e_cert_db_find_cert_by_nickname(db, info->name, NULL); - color = &style->dark[state]; - type = EM_FORMAT_HTML_COLOR_FRAME; - em_format_html_set_color (efh, type, color); + if (ec != NULL) { + GtkWidget *w = certificate_viewer_show(ec); - color = &style->fg[state]; - type = EM_FORMAT_HTML_COLOR_HEADER; - em_format_html_set_color (efh, type, color); + /* oddly enough certificate_viewer_show doesn't ... */ + gtk_widget_show(w); + g_signal_connect(w, "response", G_CALLBACK(gtk_widget_destroy), NULL); - color = &style->text[state]; - type = EM_FORMAT_HTML_COLOR_TEXT; - em_format_html_set_color (efh, type, color); + if (w && po->widget) + gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)po->widget); - g_object_thaw_notify (G_OBJECT (efh)); + g_object_unref(ec); + } else { + g_warning("can't find certificate for %s <%s>", info->name?info->name:"", info->email?info->email:""); + } } +#endif static void -efhd_gtkhtml_style_set(GtkHTML *html, GtkStyle *old, EMFormatHTMLDisplay *efhd) +efhd_xpkcs7mime_add_cert_table (GtkWidget *vbox, + CamelDList *certlist, + struct _smime_pobject *po) { - efhd_gtkhtml_realize(html, efhd); - em_format_redraw((EMFormat *)efhd); + CamelCipherCertInfo *info = (CamelCipherCertInfo *)certlist->head; + GtkTable *table = (GtkTable *)gtk_table_new(camel_dlist_length(certlist), 2, FALSE); + int n = 0; + + while (info->next) { + char *la = NULL; + const char *l = NULL; + + if (info->name) { + if (info->email && strcmp(info->name, info->email) != 0) + l = la = g_strdup_printf("%s <%s>", info->name, info->email); + else + l = info->name; + } else { + if (info->email) + l = info->email; + } + + if (l) { + GtkWidget *w; +#if defined(HAVE_NSS) + ECertDB *db = e_cert_db_peek(); + ECert *ec = NULL; +#endif + w = gtk_label_new(l); + gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5); + g_free(la); + gtk_table_attach(table, w, 0, 1, n, n+1, GTK_FILL, GTK_FILL, 3, 3); +#if defined(HAVE_NSS) + w = gtk_button_new_with_mnemonic(_("_View Certificate")); + gtk_table_attach(table, w, 1, 2, n, n+1, 0, 0, 3, 3); + g_object_set_data((GObject *)w, "e-cert-info", info); + g_signal_connect(w, "clicked", G_CALLBACK(efhd_xpkcs7mime_viewcert_clicked), po); + + if (info->email) + ec = e_cert_db_find_cert_by_email_address(db, info->email, NULL); + if (ec == NULL && info->name) + ec = e_cert_db_find_cert_by_nickname(db, info->name, NULL); + + if (ec == NULL) + gtk_widget_set_sensitive(w, FALSE); + else + g_object_unref(ec); +#else + w = gtk_label_new (_("This certificate is not viewable")); + gtk_table_attach(table, w, 1, 2, n, n+1, 0, 0, 3, 3); +#endif + n++; + } + + info = info->next; + } + + gtk_box_pack_start((GtkBox *)vbox, (GtkWidget *)table, TRUE, TRUE, 6); } static void -efhd_init(GObject *o) +efhd_xpkcs7mime_validity_clicked (GtkWidget *button, + EMFormatHTMLPObject *pobject) { - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)o; -#define efh ((EMFormatHTML *)efhd) + struct _smime_pobject *po = (struct _smime_pobject *)pobject; + GladeXML *xml; + GtkWidget *vbox, *w; + char *gladefile; - efhd->priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE(efhd); + if (po->widget) + /* FIXME: window raise? */ + return; - efhd->search_tok = (ESearchingTokenizer *)e_searching_tokenizer_new(); - gtk_html_set_tokenizer (efh->html, (HTMLTokenizer *)efhd->search_tok); + gladefile = g_build_filename ( + EVOLUTION_GLADEDIR, "mail-dialogs.glade", NULL); + xml = glade_xml_new (gladefile, "message_security_dialog", NULL); + g_free (gladefile); - g_signal_connect(efh->html, "realize", G_CALLBACK(efhd_gtkhtml_realize), o); - g_signal_connect(efh->html, "style-set", G_CALLBACK(efhd_gtkhtml_style_set), o); - /* we want to convert url's etc */ - efh->text_html_flags |= CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES; -#undef efh + po->widget = glade_xml_get_widget(xml, "message_security_dialog"); - efhd->nobar = getenv("EVOLUTION_NO_BAR") != NULL; + vbox = glade_xml_get_widget(xml, "signature_vbox"); + w = gtk_label_new (_(smime_sign_table[po->valid->sign.status].description)); + gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5); + gtk_label_set_line_wrap((GtkLabel *)w, TRUE); + gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6); + if (po->valid->sign.description) { + GtkTextBuffer *buffer; - efhd->priv->show_bar = FALSE; - efhd->priv->files = NULL; -} + buffer = gtk_text_buffer_new(NULL); + gtk_text_buffer_set_text(buffer, po->valid->sign.description, strlen(po->valid->sign.description)); + w = g_object_new(gtk_scrolled_window_get_type(), + "hscrollbar_policy", GTK_POLICY_AUTOMATIC, + "vscrollbar_policy", GTK_POLICY_AUTOMATIC, + "shadow_type", GTK_SHADOW_IN, + "child", g_object_new(gtk_text_view_get_type(), + "buffer", buffer, + "cursor_visible", FALSE, + "editable", FALSE, + "width_request", 500, + "height_request", 160, + NULL), + NULL); + g_object_unref(buffer); -static void -efhd_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ANIMATE: - em_format_html_display_set_animate ( - EM_FORMAT_HTML_DISPLAY (object), - g_value_get_boolean (value)); - return; + gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6); + } - case PROP_CARET_MODE: - em_format_html_display_set_caret_mode ( - EM_FORMAT_HTML_DISPLAY (object), - g_value_get_boolean (value)); - return; + if (!camel_dlist_empty(&po->valid->sign.signers)) + efhd_xpkcs7mime_add_cert_table(vbox, &po->valid->sign.signers, po); + + gtk_widget_show_all(vbox); + + vbox = glade_xml_get_widget(xml, "encryption_vbox"); + w = gtk_label_new(_(smime_encrypt_table[po->valid->encrypt.status].description)); + gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5); + gtk_label_set_line_wrap((GtkLabel *)w, TRUE); + gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6); + if (po->valid->encrypt.description) { + GtkTextBuffer *buffer; + + buffer = gtk_text_buffer_new(NULL); + gtk_text_buffer_set_text(buffer, po->valid->encrypt.description, strlen(po->valid->encrypt.description)); + w = g_object_new(gtk_scrolled_window_get_type(), + "hscrollbar_policy", GTK_POLICY_AUTOMATIC, + "vscrollbar_policy", GTK_POLICY_AUTOMATIC, + "shadow_type", GTK_SHADOW_IN, + "child", g_object_new(gtk_text_view_get_type(), + "buffer", buffer, + "cursor_visible", FALSE, + "editable", FALSE, + "width_request", 500, + "height_request", 160, + NULL), + NULL); + g_object_unref(buffer); + + gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6); } - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + if (!camel_dlist_empty(&po->valid->encrypt.encrypters)) + efhd_xpkcs7mime_add_cert_table(vbox, &po->valid->encrypt.encrypters, po); + + gtk_widget_show_all(vbox); + + g_object_unref(xml); + + g_signal_connect(po->widget, "response", G_CALLBACK(efhd_xpkcs7mime_info_response), po); + gtk_widget_show(po->widget); } -static void -efhd_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ANIMATE: - g_value_set_boolean ( - value, em_format_html_display_get_animate ( - EM_FORMAT_HTML_DISPLAY (object))); - return; +static gboolean +efhd_xpkcs7mime_button (EMFormatHTML *efh, + GtkHTMLEmbedded *eb, + EMFormatHTMLPObject *pobject) +{ + GtkWidget *container; + GtkWidget *widget; + struct _smime_pobject *po = (struct _smime_pobject *)pobject; + const char *icon_name; - case PROP_CARET_MODE: - g_value_set_boolean ( - value, em_format_html_display_get_caret_mode ( - EM_FORMAT_HTML_DISPLAY (object))); - return; - } + /* FIXME: need to have it based on encryption and signing too */ + if (po->valid->sign.status != 0) + icon_name = smime_sign_table[po->valid->sign.status].icon; + else + icon_name = smime_encrypt_table[po->valid->encrypt.status].icon; + + container = GTK_WIDGET (eb); + + widget = gtk_button_new (); + g_signal_connect ( + widget, "clicked", + G_CALLBACK (efhd_xpkcs7mime_validity_clicked), pobject); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + container = widget; + + widget = gtk_image_new_from_icon_name ( + icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + return TRUE; } static void @@ -337,206 +464,294 @@ efhd_finalize (GObject *object) g_free (priv->search_text); /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (efhd_parent)->finalize (object); + G_OBJECT_CLASS (parent_class)->finalize (object); } -static gboolean -efhd_bool_accumulator(GSignalInvocationHint *ihint, GValue *out, const GValue *in, void *data) +static void +efhd_format_clone (EMFormat *emf, + CamelFolder *folder, + const gchar *uid, + CamelMimeMessage *msg, + EMFormat *src) { - gboolean val = g_value_get_boolean(in); + EMFormatHTMLDisplayPrivate *priv; + + priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (emf); + + if (emf != src) { + priv->show_bar = (src != NULL) ? + EM_FORMAT_HTML_DISPLAY (src)->priv->show_bar : FALSE; - g_value_set_boolean(out, val); + EM_FORMAT_HTML (emf)->header_wrap_flags = 0; + } - return !val; + /* Chain up to parent's format_clone() method. */ + EM_FORMAT_CLASS (parent_class)-> + format_clone (emf, folder, uid, msg, src); } static void -efhd_class_init (GObjectClass *class) +efhd_format_attachment (EMFormat *emf, + CamelStream *stream, + CamelMimePart *part, + const gchar *mime_type, + const EMFormatHandler *handle) { - GObjectClass *object_class; - EMFormatClass *format_class; + char *classid, *text, *html; + struct _attach_puri *info; - g_type_class_add_private (class, sizeof (EMFormatHTMLDisplayPrivate)); + classid = g_strdup_printf ("attachment%s", emf->part_id->str); + info = (struct _attach_puri *) em_format_add_puri ( + emf, sizeof (*info), classid, part, efhd_attachment_frame); + em_format_html_add_pobject ( + EM_FORMAT_HTML (emf), sizeof (EMFormatHTMLPObject), + classid, part, efhd_attachment_button); + info->handle = handle; + info->shown = em_format_is_inline ( + emf, info->puri.part_id, info->puri.part, handle); + info->snoop_mime_type = emf->snoop_mime_type; + info->attachment = e_attachment_new_from_mime_part (info->puri.part); + e_attachment_bar_create_attachment_cache (info->attachment); - object_class = G_OBJECT_CLASS (class); - object_class->set_property = efhd_set_property; - object_class->get_property = efhd_get_property; - object_class->finalize = efhd_finalize; + if (emf->valid) { + info->sign = emf->valid->sign.status; + info->encrypt = emf->valid->encrypt.status; + } - format_class = EM_FORMAT_CLASS (class); - format_class->find_handler = efhd_find_handler; - format_class->format_clone = efhd_format_clone; - format_class->format_error = efhd_format_error; - format_class->format_source = efhd_format_source; - format_class->format_attachment = efhd_format_attachment; - format_class->format_optional = efhd_format_optional; - format_class->format_secure = efhd_format_secure; - format_class->complete = efhd_complete; + camel_stream_write_string( + stream, EM_FORMAT_HTML_VPAD + "<table cellspacing=0 cellpadding=0><tr><td>" + "<table width=10 cellspacing=0 cellpadding=0>" + "<tr><td></td></tr></table></td>"); - g_object_class_install_property ( - object_class, - PROP_ANIMATE, - g_param_spec_boolean ( - "animate", - "Animate Images", - NULL, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_CARET_MODE, - g_param_spec_boolean ( - "caret-mode", - "Caret Mode", - NULL, - FALSE, - G_PARAM_READWRITE)); - - efhd_signals[EFHD_LINK_CLICKED] = - g_signal_new("link_clicked", - G_TYPE_FROM_CLASS(class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(EMFormatHTMLDisplayClass, link_clicked), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - efhd_signals[EFHD_POPUP_EVENT] = - g_signal_new("popup_event", - G_TYPE_FROM_CLASS(class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(EMFormatHTMLDisplayClass, popup_event), - efhd_bool_accumulator, NULL, - e_marshal_BOOLEAN__BOXED_POINTER_POINTER, - G_TYPE_BOOLEAN, 3, - GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE, - G_TYPE_POINTER, G_TYPE_POINTER); - - efhd_signals[EFHD_ON_URL] = - g_signal_new("on_url", - G_TYPE_FROM_CLASS(class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(EMFormatHTMLDisplayClass, on_url), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - - efhd_builtin_init((EMFormatHTMLDisplayClass *)class); -} + camel_stream_printf ( + stream, "<td><object classid=\"%s\"></object></td>", classid); -GType -em_format_html_display_get_type (void) -{ - static GType type = 0; + camel_stream_write_string ( + stream, "<td><table width=3 cellspacing=0 cellpadding=0>" + "<tr><td></td></tr></table></td><td><font size=-1>"); - if (type == 0) { - static const GTypeInfo info = { - sizeof(EMFormatHTMLDisplayClass), - NULL, NULL, - (GClassInitFunc)efhd_class_init, - NULL, NULL, - sizeof(EMFormatHTMLDisplay), 0, - (GInstanceInitFunc)efhd_init - }; - efhd_parent = g_type_class_ref(em_format_html_get_type()); - efhd_format_class = g_type_class_ref(em_format_get_type()); - type = g_type_register_static(em_format_html_get_type(), "EMFormatHTMLDisplay", &info, 0); - } + /* output some info about it */ + /* FIXME: should we look up mime_type from object again? */ + text = em_format_describe_part (part, mime_type); + html = camel_text_to_html ( + text, EM_FORMAT_HTML (emf)->text_html_flags & + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); + camel_stream_write_string (stream, html); + g_free (html); + g_free (text); + + camel_stream_write_string ( + stream, "</font></td></tr><tr></table>\n" + EM_FORMAT_HTML_VPAD); - return type; + if (handle && info->shown) + handle->handler (emf, stream, part, handle); + + g_free (classid); } -static gboolean -efhd_scroll_event(GtkWidget *w, GdkEventScroll *event, EMFormatHTMLDisplay *efhd) +static void +efhd_format_optional (EMFormat *emf, + CamelStream *fstream, + CamelMimePart *part, + CamelStream *mstream) { - if(event->state & GDK_CONTROL_MASK) - { - if(event->direction == GDK_SCROLL_UP) - { - gtk_html_zoom_in (efhd->parent.html); - } - else if(event->direction == GDK_SCROLL_DOWN) - { - gtk_html_zoom_out (efhd->parent.html); - } - return TRUE; + char *classid, *html; + struct _attach_puri *info; + CamelStream *stream; + + if (CAMEL_IS_STREAM_FILTER (fstream) && ((CamelStreamFilter *) fstream)->source) + stream = ((CamelStreamFilter *) fstream)->source; + else + stream = fstream; + + classid = g_strdup_printf ("optional%s", emf->part_id->str); + info = (struct _attach_puri *) em_format_add_puri ( + emf, sizeof (*info), classid, part, efhd_attachment_frame); + em_format_html_add_pobject ( + EM_FORMAT_HTML (emf), sizeof (EMFormatHTMLPObject), + classid, part, efhd_attachment_optional); + info->handle = em_format_find_handler (emf, "text/plain"); + info->shown = FALSE; + info->snoop_mime_type = "text/plain"; + info->attachment = e_attachment_new_from_mime_part (info->puri.part); + info->mstream = (CamelStreamMem *) mstream; + if (emf->valid) { + info->sign = emf->valid->sign.status; + info->encrypt = emf->valid->encrypt.status; } - return FALSE; -} -EMFormatHTMLDisplay *em_format_html_display_new(void) -{ - EMFormatHTMLDisplay *efhd; + camel_stream_write_string ( + stream, EM_FORMAT_HTML_VPAD + "<table cellspacing=0 cellpadding=0><tr><td>" + "<h3><font size=-1 color=red>"); + + html = camel_text_to_html ( + _("Evolution cannot render this email as it is too " + "large to process. You can view it unformatted or " + "with an external text editor."), + EM_FORMAT_HTML (emf)->text_html_flags & + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); + camel_stream_write_string (stream, html); + camel_stream_write_string ( + stream, "</font></h3></td></tr></table>\n"); + camel_stream_write_string ( + stream, "<table cellspacing=0 cellpadding=0><tr>"); + camel_stream_printf ( + stream, "<td><object classid=\"%s\"></object>" + "</td></tr></table>", classid); - efhd = g_object_new(em_format_html_display_get_type(), 0); + g_free(html); - g_signal_connect(efhd->parent.html, "iframe_created", G_CALLBACK(efhd_iframe_created), efhd); - g_signal_connect(efhd->parent.html, "link_clicked", G_CALLBACK(efhd_html_link_clicked), efhd); - g_signal_connect(efhd->parent.html, "on_url", G_CALLBACK(efhd_html_on_url), efhd); - g_signal_connect(efhd->parent.html, "button_press_event", G_CALLBACK(efhd_html_button_press_event), efhd); - g_signal_connect(efhd->parent.html,"scroll_event", G_CALLBACK(efhd_scroll_event), efhd); + camel_stream_write_string ( + stream, EM_FORMAT_HTML_VPAD); - return efhd; + g_free (classid); } -gboolean -em_format_html_display_get_animate (EMFormatHTMLDisplay *efhd) +static void +efhd_format_secure (EMFormat *emf, + CamelStream *stream, + CamelMimePart *part, + CamelCipherValidity *valid) { - GtkHTML *html; + EM_FORMAT_CLASS (parent_class)-> + format_secure (emf, stream, part, valid); + + if (emf->valid == valid + && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE + || valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) { + char *classid; + struct _smime_pobject *pobj; + + camel_stream_printf ( + stream, "<table border=0 width=\"100%%\" " + "cellpadding=3 cellspacing=0%s><tr>", + smime_sign_colour[valid->sign.status]); + + classid = g_strdup_printf ( + "smime:///em-format-html/%s/icon/signed", + emf->part_id->str); + pobj = (struct _smime_pobject *) em_format_html_add_pobject ( + EM_FORMAT_HTML (emf), sizeof (*pobj), + classid, part, efhd_xpkcs7mime_button); + pobj->valid = camel_cipher_validity_clone(valid); + pobj->object.free = efhd_xpkcs7mime_free; + camel_stream_printf ( + stream, "<td valign=center><object classid=\"%s\">" + "</object></td><td width=100%% valign=center>", + classid); + g_free (classid); + + if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) { + const gchar *desc; + gint status; - g_return_val_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd), FALSE); + status = valid->sign.status; + desc = smime_sign_table[status].shortdesc; + camel_stream_printf (stream, "%s", gettext (desc)); + } - html = ((EMFormatHTML *) efhd)->html; + if (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) { + const gchar *desc; + gint status; - return gtk_html_get_animate (html); + if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) { + camel_stream_printf (stream, "<br>"); + } + + status = valid->encrypt.status; + desc = smime_encrypt_table[status].shortdesc; + camel_stream_printf (stream, "%s", gettext (desc)); + } + + camel_stream_printf(stream, "</td></tr></table>"); + } } -void -em_format_html_display_set_animate (EMFormatHTMLDisplay *efhd, - gboolean animate) +static void +efhd_class_init (EMFormatHTMLDisplayClass *class) { - GtkHTML *html; + GObjectClass *object_class; + EMFormatClass *format_class; + EMFormatHTMLClass *format_html_class; - /* XXX Note this is imperfect. If animate is set by - * some other means we won't emit a notification. */ + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EMFormatHTMLDisplayPrivate)); - g_return_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd)); + object_class = G_OBJECT_CLASS (class); + object_class->finalize = efhd_finalize; - html = ((EMFormatHTML *) efhd)->html; - gtk_html_set_animate (html, animate); + format_class = EM_FORMAT_CLASS (class); + format_class->format_clone = efhd_format_clone; + format_class->format_attachment = efhd_format_attachment; + format_class->format_optional = efhd_format_optional; + format_class->format_secure = efhd_format_secure; + format_class->complete = efhd_complete; + + format_html_class = EM_FORMAT_HTML_CLASS (class); + format_html_class->html_widget_type = E_TYPE_MAIL_DISPLAY; - g_object_notify (G_OBJECT (efhd), "animate"); + efhd_builtin_init (class); } -gboolean -em_format_html_display_get_caret_mode (EMFormatHTMLDisplay *efhd) +static void +efhd_init (EMFormatHTMLDisplay *efhd) { GtkHTML *html; - g_return_val_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd), FALSE); + html = EM_FORMAT_HTML (efhd)->html; + + efhd->priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (efhd); - html = ((EMFormatHTML *) efhd)->html; + e_mail_display_set_formatter ( + E_MAIL_DISPLAY (html), EM_FORMAT_HTML (efhd)); - return gtk_html_get_caret_mode (html); + efhd->search_tok = + (ESearchingTokenizer *) e_searching_tokenizer_new (); + gtk_html_set_tokenizer (html, (HTMLTokenizer *) efhd->search_tok); + + /* we want to convert url's etc */ + EM_FORMAT_HTML (efhd)->text_html_flags |= + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | + CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES; + + efhd->priv->show_bar = FALSE; + efhd->priv->files = NULL; } -void -em_format_html_display_set_caret_mode (EMFormatHTMLDisplay *efhd, - gboolean caret_mode) +GType +em_format_html_display_get_type (void) { - GtkHTML *html; + static GType type = 0; - /* XXX Note this is imperfect. If caret mode is set by - * some other means we won't emit a notification. */ + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EMFormatHTMLDisplayClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) efhd_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMFormatHTMLDisplay), + 0, /* n_preallocs */ + (GInstanceInitFunc) efhd_init, + NULL /* value_table */ + }; - g_return_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd)); + type = g_type_register_static ( + EM_TYPE_FORMAT_HTML, "EMFormatHTMLDisplay", + &type_info, 0); + } - html = ((EMFormatHTML *) efhd)->html; - gtk_html_set_caret_mode (html, caret_mode); + return type; +} - g_object_notify (G_OBJECT (efhd), "caret-mode"); +EMFormatHTMLDisplay * +em_format_html_display_new (void) +{ + return g_object_new (EM_TYPE_FORMAT_HTML_DISPLAY, NULL); } EAttachmentBar * @@ -896,147 +1111,6 @@ em_format_html_display_zoom_reset (EMFormatHTMLDisplay *efhd) /* ********************************************************************** */ static void -efhd_iframe_created(GtkHTML *html, GtkHTML *iframe, EMFormatHTMLDisplay *efh) -{ - d(printf("Iframe created %p ... \n", iframe)); - - g_signal_connect(iframe, "button_press_event", G_CALLBACK (efhd_html_button_press_event), efh); - - return; -} - -static void -efhd_get_uri_puri (GtkWidget *html, GdkEventButton *event, EMFormatHTMLDisplay *efhd, char **uri, EMFormatPURI **puri) -{ - char *url, *img_url; - - g_return_if_fail (html != NULL); - g_return_if_fail (GTK_IS_HTML (html)); - g_return_if_fail (efhd != NULL); - - if (event) { - url = gtk_html_get_url_at (GTK_HTML (html), event->x, event->y); - img_url = gtk_html_get_image_src_at (GTK_HTML (html), event->x, event->y); - } else { - url = gtk_html_get_cursor_url (GTK_HTML (html)); - img_url = gtk_html_get_cursor_image_src (GTK_HTML (html)); - } - - if (img_url) { - if (!(strstr (img_url, "://") || g_ascii_strncasecmp (img_url, "cid:", 4) == 0)) { - char *u = g_strconcat ("file://", img_url, NULL); - g_free (img_url); - img_url = u; - } - } - - if (puri) { - if (url) - *puri = em_format_find_puri ((EMFormat *)efhd, url); - - if (!*puri && img_url) - *puri = em_format_find_puri ((EMFormat *)efhd, img_url); - } - - if (uri) { - *uri = NULL; - if (img_url && g_ascii_strncasecmp (img_url, "cid:", 4) != 0) { - if (url) - *uri = g_strdup_printf ("%s\n%s", url, img_url); - else { - *uri = img_url; - img_url = NULL; - } - } else { - *uri = url; - url = NULL; - } - } - - g_free (url); - g_free (img_url); -} - -static int -efhd_html_button_press_event (GtkWidget *widget, GdkEventButton *event, EMFormatHTMLDisplay *efhd) -{ - char *uri = NULL; - EMFormatPURI *puri = NULL; - gboolean res = FALSE; - - if (event->button != 3) - return FALSE; - - d(printf("popup button pressed\n")); - - efhd_get_uri_puri (widget, event, efhd, &uri, &puri); - - if (uri && !strncmp (uri, "##", 2)) { - g_free (uri); - return TRUE; - } - - g_signal_emit((GtkObject *)efhd, efhd_signals[EFHD_POPUP_EVENT], 0, event, uri, puri?puri->part:NULL, &res); - - g_free (uri); - - return res; -} - -gboolean -em_format_html_display_popup_menu (EMFormatHTMLDisplay *efhd) -{ - GtkHTML *html; - char *uri = NULL; - EMFormatPURI *puri = NULL; - gboolean res = FALSE; - - html = efhd->parent.html; - - efhd_get_uri_puri (GTK_WIDGET (html), NULL, efhd, &uri, &puri); - - g_signal_emit ((GtkObject *)efhd, efhd_signals[EFHD_POPUP_EVENT], 0, NULL, uri, puri?puri->part:NULL, &res); - - g_free (uri); - - return res; -} - -static void -efhd_html_link_clicked (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd) -{ - d(printf("link clicked event '%s'\n", url)); - if (url && !strncmp(url, "##", 2)) { - if (!strcmp (url, "##TO##")) - if (!(((EMFormatHTML *) efhd)->header_wrap_flags & EM_FORMAT_HTML_HEADER_TO)) - ((EMFormatHTML *) efhd)->header_wrap_flags |= EM_FORMAT_HTML_HEADER_TO; - else - ((EMFormatHTML *) efhd)->header_wrap_flags &= ~EM_FORMAT_HTML_HEADER_TO; - else if (!strcmp (url, "##CC##")) - if (!(((EMFormatHTML *) efhd)->header_wrap_flags & EM_FORMAT_HTML_HEADER_CC)) - ((EMFormatHTML *) efhd)->header_wrap_flags |= EM_FORMAT_HTML_HEADER_CC; - else - ((EMFormatHTML *) efhd)->header_wrap_flags &= ~EM_FORMAT_HTML_HEADER_CC; - else if (!strcmp (url, "##BCC##")) { - if (!(((EMFormatHTML *) efhd)->header_wrap_flags & EM_FORMAT_HTML_HEADER_BCC)) - ((EMFormatHTML *) efhd)->header_wrap_flags |= EM_FORMAT_HTML_HEADER_BCC; - else - ((EMFormatHTML *) efhd)->header_wrap_flags &= ~EM_FORMAT_HTML_HEADER_BCC; - } - em_format_redraw((EMFormat *)efhd); - } else - g_signal_emit((GObject *)efhd, efhd_signals[EFHD_LINK_CLICKED], 0, url); -} - -static void -efhd_html_on_url (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd) -{ - d(printf("on_url event '%s'\n", url)); - - g_signal_emit((GObject *)efhd, efhd_signals[EFHD_ON_URL], 0, url); -} - -static void efhd_complete(EMFormat *emf) { EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)emf; @@ -1052,306 +1126,6 @@ efhd_complete(EMFormat *emf) /* ********************************************************************** */ -/* TODO: move the dialogue elsehwere */ -/* FIXME: also in em-format-html.c */ -static const struct { - const char *icon, *shortdesc, *description; -} smime_sign_table[5] = { - { "stock_signature-bad", N_("Unsigned"), N_("This message is not signed. There is no guarantee that this message is authentic.") }, - { "stock_signature-ok", N_("Valid signature"), N_("This message is signed and is valid meaning that it is very likely that this message is authentic.") }, - { "stock_signature-bad", N_("Invalid signature"), N_("The signature of this message cannot be verified, it may have been altered in transit.") }, - { "stock_signature", N_("Valid signature, but cannot verify sender"), N_("This message is signed with a valid signature, but the sender of the message cannot be verified.") }, - { "stock_signature-bad", N_("Signature exists, but need public key"), N_("This message is signed with a signature, but there is no corresponding public key.") }, - -}; - -static const struct { - const char *icon, *shortdesc, *description; -} smime_encrypt_table[4] = { - { "stock_lock-broken", N_("Unencrypted"), N_("This message is not encrypted. Its content may be viewed in transit across the Internet.") }, - { "stock_lock-ok", N_("Encrypted, weak"), N_("This message is encrypted, but with a weak encryption algorithm. It would be difficult, but not impossible for an outsider to view the content of this message in a practical amount of time.") }, - { "stock_lock-ok", N_("Encrypted"), N_("This message is encrypted. It would be difficult for an outsider to view the content of this message.") }, - { "stock_lock-ok", N_("Encrypted, strong"), N_("This message is encrypted, with a strong encryption algorithm. It would be very difficult for an outsider to view the content of this message in a practical amount of time.") }, -}; - -static const char *smime_sign_colour[5] = { - "", " bgcolor=\"#88bb88\"", " bgcolor=\"#bb8888\"", " bgcolor=\"#e8d122\"","" -}; - -struct _smime_pobject { - EMFormatHTMLPObject object; - - int signature; - CamelCipherValidity *valid; - GtkWidget *widget; -}; - -static void -efhd_xpkcs7mime_free(EMFormatHTMLPObject *o) -{ - struct _smime_pobject *po = (struct _smime_pobject *)o; - - if (po->widget) - gtk_widget_destroy(po->widget); - camel_cipher_validity_free(po->valid); -} - -static void -efhd_xpkcs7mime_info_response(GtkWidget *w, guint button, struct _smime_pobject *po) -{ - gtk_widget_destroy(w); - po->widget = NULL; -} - -#ifdef HAVE_NSS -static void -efhd_xpkcs7mime_viewcert_foad(GtkWidget *w, guint button, struct _smime_pobject *po) -{ - gtk_widget_destroy(w); -} - -static void -efhd_xpkcs7mime_viewcert_clicked(GtkWidget *button, struct _smime_pobject *po) -{ - CamelCipherCertInfo *info = g_object_get_data((GObject *)button, "e-cert-info"); - ECertDB *db = e_cert_db_peek(); - ECert *ec = NULL; - - if (info->email) - ec = e_cert_db_find_cert_by_email_address(db, info->email, NULL); - - if (ec == NULL && info->name) - ec = e_cert_db_find_cert_by_nickname(db, info->name, NULL); - - if (ec != NULL) { - GtkWidget *w = certificate_viewer_show(ec); - - /* oddly enough certificate_viewer_show doesn't ... */ - gtk_widget_show(w); - g_signal_connect(w, "response", G_CALLBACK(efhd_xpkcs7mime_viewcert_foad), po); - - if (w && po->widget) - gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)po->widget); - - g_object_unref(ec); - } else { - g_warning("can't find certificate for %s <%s>", info->name?info->name:"", info->email?info->email:""); - } -} -#endif - -static void -efhd_xpkcs7mime_add_cert_table(GtkWidget *vbox, CamelDList *certlist, struct _smime_pobject *po) -{ - CamelCipherCertInfo *info = (CamelCipherCertInfo *)certlist->head; - GtkTable *table = (GtkTable *)gtk_table_new(camel_dlist_length(certlist), 2, FALSE); - int n = 0; - - while (info->next) { - char *la = NULL; - const char *l = NULL; - - if (info->name) { - if (info->email && strcmp(info->name, info->email) != 0) - l = la = g_strdup_printf("%s <%s>", info->name, info->email); - else - l = info->name; - } else { - if (info->email) - l = info->email; - } - - if (l) { - GtkWidget *w; -#if defined(HAVE_NSS) - ECertDB *db = e_cert_db_peek(); - ECert *ec = NULL; -#endif - w = gtk_label_new(l); - gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5); - g_free(la); - gtk_table_attach(table, w, 0, 1, n, n+1, GTK_FILL, GTK_FILL, 3, 3); -#if defined(HAVE_NSS) - w = gtk_button_new_with_mnemonic(_("_View Certificate")); - gtk_table_attach(table, w, 1, 2, n, n+1, 0, 0, 3, 3); - g_object_set_data((GObject *)w, "e-cert-info", info); - g_signal_connect(w, "clicked", G_CALLBACK(efhd_xpkcs7mime_viewcert_clicked), po); - - if (info->email) - ec = e_cert_db_find_cert_by_email_address(db, info->email, NULL); - if (ec == NULL && info->name) - ec = e_cert_db_find_cert_by_nickname(db, info->name, NULL); - - if (ec == NULL) - gtk_widget_set_sensitive(w, FALSE); - else - g_object_unref(ec); -#else - w = gtk_label_new (_("This certificate is not viewable")); - gtk_table_attach(table, w, 1, 2, n, n+1, 0, 0, 3, 3); -#endif - n++; - } - - info = info->next; - } - - gtk_box_pack_start((GtkBox *)vbox, (GtkWidget *)table, TRUE, TRUE, 6); -} - -static void -efhd_xpkcs7mime_validity_clicked(GtkWidget *button, EMFormatHTMLPObject *pobject) -{ - struct _smime_pobject *po = (struct _smime_pobject *)pobject; - GladeXML *xml; - GtkWidget *vbox, *w; - char *gladefile; - - if (po->widget) - /* FIXME: window raise? */ - return; - - gladefile = g_build_filename (EVOLUTION_GLADEDIR, - "mail-dialogs.glade", - NULL); - xml = glade_xml_new(gladefile, "message_security_dialog", NULL); - g_free (gladefile); - - po->widget = glade_xml_get_widget(xml, "message_security_dialog"); - - vbox = glade_xml_get_widget(xml, "signature_vbox"); - w = gtk_label_new (_(smime_sign_table[po->valid->sign.status].description)); - gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5); - gtk_label_set_line_wrap((GtkLabel *)w, TRUE); - gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6); - if (po->valid->sign.description) { - GtkTextBuffer *buffer; - - buffer = gtk_text_buffer_new(NULL); - gtk_text_buffer_set_text(buffer, po->valid->sign.description, strlen(po->valid->sign.description)); - w = g_object_new(gtk_scrolled_window_get_type(), - "hscrollbar_policy", GTK_POLICY_AUTOMATIC, - "vscrollbar_policy", GTK_POLICY_AUTOMATIC, - "shadow_type", GTK_SHADOW_IN, - "child", g_object_new(gtk_text_view_get_type(), - "buffer", buffer, - "cursor_visible", FALSE, - "editable", FALSE, - "width_request", 500, - "height_request", 160, - NULL), - NULL); - g_object_unref(buffer); - - gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6); - } - - if (!camel_dlist_empty(&po->valid->sign.signers)) - efhd_xpkcs7mime_add_cert_table(vbox, &po->valid->sign.signers, po); - - gtk_widget_show_all(vbox); - - vbox = glade_xml_get_widget(xml, "encryption_vbox"); - w = gtk_label_new(_(smime_encrypt_table[po->valid->encrypt.status].description)); - gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5); - gtk_label_set_line_wrap((GtkLabel *)w, TRUE); - gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6); - if (po->valid->encrypt.description) { - GtkTextBuffer *buffer; - - buffer = gtk_text_buffer_new(NULL); - gtk_text_buffer_set_text(buffer, po->valid->encrypt.description, strlen(po->valid->encrypt.description)); - w = g_object_new(gtk_scrolled_window_get_type(), - "hscrollbar_policy", GTK_POLICY_AUTOMATIC, - "vscrollbar_policy", GTK_POLICY_AUTOMATIC, - "shadow_type", GTK_SHADOW_IN, - "child", g_object_new(gtk_text_view_get_type(), - "buffer", buffer, - "cursor_visible", FALSE, - "editable", FALSE, - "width_request", 500, - "height_request", 160, - NULL), - NULL); - g_object_unref(buffer); - - gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6); - } - - if (!camel_dlist_empty(&po->valid->encrypt.encrypters)) - efhd_xpkcs7mime_add_cert_table(vbox, &po->valid->encrypt.encrypters, po); - - gtk_widget_show_all(vbox); - - g_object_unref(xml); - - g_signal_connect(po->widget, "response", G_CALLBACK(efhd_xpkcs7mime_info_response), po); - gtk_widget_show(po->widget); -} - -static gboolean -efhd_xpkcs7mime_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) -{ - GtkWidget *icon, *button; - struct _smime_pobject *po = (struct _smime_pobject *)pobject; - const char *icon_name; - - /* FIXME: need to have it based on encryption and signing too */ - if (po->valid->sign.status != 0) - icon_name = smime_sign_table[po->valid->sign.status].icon; - else - icon_name = smime_encrypt_table[po->valid->encrypt.status].icon; - - icon = gtk_image_new_from_icon_name ( - icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_widget_show(icon); - - button = gtk_button_new(); - g_signal_connect(button, "clicked", G_CALLBACK(efhd_xpkcs7mime_validity_clicked), pobject); - - gtk_container_add((GtkContainer *)button, icon); - gtk_widget_show(button); - gtk_container_add((GtkContainer *)eb, button); - - return TRUE; -} - -static void -efhd_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid) -{ - /* Note: We call EMFormatClass directly, not EMFormatHTML, our parent */ - efhd_format_class->format_secure(emf, stream, part, valid); - - if (emf->valid == valid - && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE - || valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) { - char *classid; - struct _smime_pobject *pobj; - - camel_stream_printf (stream, "<table border=0 width=\"100%%\" cellpadding=3 cellspacing=0%s><tr>", - smime_sign_colour[valid->sign.status]); - - classid = g_strdup_printf("smime:///em-format-html/%s/icon/signed", emf->part_id->str); - pobj = (struct _smime_pobject *)em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(*pobj), classid, part, efhd_xpkcs7mime_button); - pobj->valid = camel_cipher_validity_clone(valid); - pobj->object.free = efhd_xpkcs7mime_free; - camel_stream_printf(stream, "<td valign=center><object classid=\"%s\"></object></td><td width=100%% valign=center>", classid); - g_free(classid); - if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) { - camel_stream_printf (stream, "%s", _(smime_sign_table[valid->sign.status].shortdesc)); - } - - if (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) { - if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) { - camel_stream_printf (stream, "<br>"); - } - camel_stream_printf (stream, "%s", _(smime_encrypt_table[valid->encrypt.status].shortdesc)); - } - - camel_stream_printf(stream, "</td></tr></table>"); - } -} - static void efhd_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *handle) { @@ -1417,27 +1191,6 @@ efhd_builtin_init(EMFormatHTMLDisplayClass *efhc) em_format_class_add_handler((EMFormatClass *)efhc, &type_builtin_table[i]); } -static const EMFormatHandler * -efhd_find_handler(EMFormat *emf, const char *mime_type) -{ - return ((EMFormatClass *) efhd_parent)->find_handler (emf, mime_type); -} - -static void efhd_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *src) -{ - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; - - if (emf != src) { - if (src) - efhd->priv->show_bar = ((EMFormatHTMLDisplay *)src)->priv->show_bar; - else - efhd->priv->show_bar = FALSE; - ((EMFormatHTML *) emf)->header_wrap_flags = 0; - } - - ((EMFormatClass *)efhd_parent)->format_clone(emf, folder, uid, msg, src); -} - static void efhd_write_image(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri) { @@ -1449,7 +1202,8 @@ efhd_write_image(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri) camel_stream_close(stream); } -static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info) +static void +efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info) { const char *flag, *comp, *due; time_t date; @@ -1508,17 +1262,6 @@ static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePar camel_stream_printf(stream, "</td></tr></table>"); } -/* TODO: if these aren't going to do anything should remove */ -static void efhd_format_error(EMFormat *emf, CamelStream *stream, const char *txt) -{ - ((EMFormatClass *)efhd_parent)->format_error(emf, stream, txt); -} - -static void efhd_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart *part) -{ - ((EMFormatClass *)efhd_parent)->format_source(emf, stream, part); -} - /* ********************************************************************** */ /* Checks on the widget whether it can be processed, based on the state of EMFormatHTML. @@ -2381,7 +2124,7 @@ efhd_message_update_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; const char *classid = "attachment-bar-refresh"; - if (efhd->nobar || efhd->priv->updated) + if (efhd->priv->updated) return; efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); @@ -2397,7 +2140,7 @@ efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, co EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; const char *classid = "attachment-bar"; - if (efhd->nobar || efhd->priv->files) + if (efhd->priv->files) return; efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); @@ -2408,56 +2151,6 @@ efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, co } static void -efhd_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle) -{ - char *classid, *text, *html; - struct _attach_puri *info; - - classid = g_strdup_printf("attachment%s", emf->part_id->str); - info = (struct _attach_puri *)em_format_add_puri(emf, sizeof(*info), classid, part, efhd_attachment_frame); - em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_attachment_button); - info->handle = handle; - info->shown = em_format_is_inline(emf, info->puri.part_id, info->puri.part, handle); - info->snoop_mime_type = emf->snoop_mime_type; - info->attachment = e_attachment_new_from_mime_part (info->puri.part); - e_attachment_bar_create_attachment_cache (info->attachment); - - if (emf->valid) { - info->sign = emf->valid->sign.status; - info->encrypt = emf->valid->encrypt.status; - } - - camel_stream_write_string(stream, - EM_FORMAT_HTML_VPAD - "<table cellspacing=0 cellpadding=0><tr><td>" - "<table width=10 cellspacing=0 cellpadding=0>" - "<tr><td></td></tr></table></td>"); - - camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td>", classid); - - camel_stream_write_string(stream, - "<td><table width=3 cellspacing=0 cellpadding=0>" - "<tr><td></td></tr></table></td><td><font size=-1>"); - - /* output some info about it */ - /* FIXME: should we look up mime_type from object again? */ - text = em_format_describe_part(part, mime_type); - html = camel_text_to_html(text, ((EMFormatHTML *)emf)->text_html_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); - camel_stream_write_string(stream, html); - g_free(html); - g_free(text); - - camel_stream_write_string(stream, - "</font></td></tr><tr></table>\n" - EM_FORMAT_HTML_VPAD); - - if (handle && info->shown) - handle->handler(emf, stream, part, handle); - - g_free(classid); -} - -static void efhd_optional_button_show (GtkWidget *widget, GtkWidget *w) { GtkWidget *label = g_object_get_data (G_OBJECT (widget), "text-label"); @@ -2570,49 +2263,3 @@ efhd_attachment_optional(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPOb return TRUE; } -static void -efhd_format_optional(EMFormat *emf, CamelStream *fstream, CamelMimePart *part, CamelStream *mstream) -{ - char *classid, *html; - struct _attach_puri *info; - CamelStream *stream; - - if (CAMEL_IS_STREAM_FILTER (fstream) && ((CamelStreamFilter *) fstream)->source) - stream = ((CamelStreamFilter *) fstream)->source; - else - stream = fstream; - - classid = g_strdup_printf("optional%s", emf->part_id->str); - info = (struct _attach_puri *)em_format_add_puri(emf, sizeof(*info), classid, part, efhd_attachment_frame); - em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_attachment_optional); - info->handle = em_format_find_handler(emf, "text/plain"); - info->shown = FALSE; - info->snoop_mime_type = "text/plain"; - info->attachment = e_attachment_new_from_mime_part (info->puri.part); - info->mstream = (CamelStreamMem *)mstream; - if (emf->valid) { - info->sign = emf->valid->sign.status; - info->encrypt = emf->valid->encrypt.status; - } - - camel_stream_write_string(stream, - EM_FORMAT_HTML_VPAD - "<table cellspacing=0 cellpadding=0><tr><td><h3><font size=-1 color=red>"); - - html = camel_text_to_html(_("Evolution cannot render this email as it is too large to process. You can view it unformatted or with an external text editor."), ((EMFormatHTML *)emf)->text_html_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); - camel_stream_write_string(stream, html); - camel_stream_write_string(stream, - "</font></h3></td></tr></table>\n"); - camel_stream_write_string(stream, - "<table cellspacing=0 cellpadding=0>" - "<tr>"); - camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td></tr></table>", classid); - - g_free(html); - - camel_stream_write_string(stream, -/* "</font></h2></td></tr></table>\n" */ - EM_FORMAT_HTML_VPAD); - - g_free(classid); -} diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h index b659994114..a74d87207b 100644 --- a/mail/em-format-html-display.h +++ b/mail/em-format-html-display.h @@ -25,8 +25,9 @@ #ifndef EM_FORMAT_HTML_DISPLAY_H #define EM_FORMAT_HTML_DISPLAY_H -#include "mail/em-format-html.h" -#include "widgets/misc/e-attachment-bar.h" +#include <camel/camel-mime-part.h> +#include <mail/em-format-html.h> +#include <widgets/misc/e-attachment-bar.h> /* Standard GObject macros */ #define EM_TYPE_FORMAT_HTML_DISPLAY \ @@ -58,41 +59,32 @@ typedef struct _EMFormatHTMLDisplay EMFormatHTMLDisplay; typedef struct _EMFormatHTMLDisplayClass EMFormatHTMLDisplayClass; typedef struct _EMFormatHTMLDisplayPrivate EMFormatHTMLDisplayPrivate; -struct _CamelMimePart; - struct _EMFormatHTMLDisplay { EMFormatHTML parent; EMFormatHTMLDisplayPrivate *priv; struct _ESearchingTokenizer *search_tok; - - unsigned int nobar:1; }; struct _EMFormatHTMLDisplayClass { EMFormatHTMLClass parent_class; /* a link clicked normally */ - void (*link_clicked)(EMFormatHTMLDisplay *efhd, const char *uri); + void (*link_clicked) (EMFormatHTMLDisplay *efhd, + const gchar *uri); /* a part or a link button pressed event */ - int (*popup_event)(EMFormatHTMLDisplay *efhd, GdkEventButton *event, const char *uri, struct _CamelMimePart *part); + gint (*popup_event) (EMFormatHTMLDisplay *efhd, + GdkEventButton *event, + const gchar *uri, + CamelMimePart *part); /* the mouse is over a link */ - void (*on_url)(EMFormatHTMLDisplay *efhd, const char *uri); + void (*on_url) (EMFormatHTMLDisplay *efhd, + const gchar *uri); }; GType em_format_html_display_get_type (void); EMFormatHTMLDisplay * em_format_html_display_new (void); -gboolean em_format_html_display_get_animate - (EMFormatHTMLDisplay *efhd); -void em_format_html_display_set_animate - (EMFormatHTMLDisplay *efhd, - gboolean animate); -gboolean em_format_html_display_get_caret_mode - (EMFormatHTMLDisplay *efhd); -void em_format_html_display_set_caret_mode - (EMFormatHTMLDisplay *efhd, - gboolean caret_mode); void em_format_html_display_set_search (EMFormatHTMLDisplay *efhd, int type, diff --git a/mail/em-format-html.c b/mail/em-format-html.c index bafb82ae36..6308947a26 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -135,12 +135,7 @@ static void efh_gtkhtml_destroy(GtkHTML *html, EMFormatHTML *efh); static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info); -static void efh_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource); -static void efh_format_error(EMFormat *emf, CamelStream *stream, const char *txt); -static void efh_format_source(EMFormat *, CamelStream *, CamelMimePart *); -static void efh_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *); static void efh_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid); -static gboolean efh_busy(EMFormat *); static void efh_builtin_init(EMFormatHTMLClass *efhc); @@ -151,6 +146,230 @@ static CamelDataCache *emfh_http_cache; #define EMFH_HTTP_CACHE_PATH "http" +/* Sigh, this is so we have a cancellable, async rendering thread */ +struct _format_msg { + MailMsg base; + + EMFormatHTML *format; + EMFormat *format_source; + EMHTMLStream *estream; + CamelFolder *folder; + char *uid; + CamelMimeMessage *message; +}; + +static gchar * +efh_format_desc (struct _format_msg *m) +{ + return g_strdup(_("Formatting message")); +} + +static void +efh_format_exec (struct _format_msg *m) +{ + struct _EMFormatHTMLJob *job; + struct _EMFormatPURITree *puri_level; + int cancelled = FALSE; + CamelURL *base; + + if (m->format->html == NULL) + return; + + camel_stream_printf ( + (CamelStream *)m->estream, + "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n" + "<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n</head>\n" + "<body bgcolor =\"#%06x\" text=\"#%06x\" marginwidth=6 marginheight=6>\n", + e_color_to_value ( + &m->format->priv->colors[ + EM_FORMAT_HTML_COLOR_BODY]), + e_color_to_value ( + &m->format->priv->colors[ + EM_FORMAT_HTML_COLOR_HEADER])); + + /* <insert top-header stuff here> */ + + if (((EMFormat *)m->format)->mode == EM_FORMAT_SOURCE) { + em_format_format_source((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message); + } else { + const EMFormatHandler *handle; + + handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/prefix"); + if (handle) + handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle); + handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/rfc822"); + if (handle) + handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle); + handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/post-header-closure"); + if (handle && !((EMFormat *)m->format)->print) + handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle); + + } + + camel_stream_flush((CamelStream *)m->estream); + + puri_level = ((EMFormat *)m->format)->pending_uri_level; + base = ((EMFormat *)m->format)->base; + + do { + /* now dispatch any added tasks ... */ + g_mutex_lock(m->format->priv->lock); + while ((job = (struct _EMFormatHTMLJob *)e_dlist_remhead(&m->format->priv->pending_jobs))) { + g_mutex_unlock(m->format->priv->lock); + + /* This is an implicit check to see if the gtkhtml has been destroyed */ + if (!cancelled) + cancelled = m->format->html == NULL; + + /* Now do an explicit check for user cancellation */ + if (!cancelled) + cancelled = camel_operation_cancel_check(NULL); + + /* call jobs even if cancelled, so they can clean up resources */ + ((EMFormat *)m->format)->pending_uri_level = job->puri_level; + if (job->base) + ((EMFormat *)m->format)->base = job->base; + job->callback(job, cancelled); + ((EMFormat *)m->format)->base = base; + + /* clean up the job */ + camel_object_unref(job->stream); + if (job->base) + camel_url_free(job->base); + g_free(job); + + g_mutex_lock(m->format->priv->lock); + } + g_mutex_unlock(m->format->priv->lock); + + if (m->estream) { + /* Closing this base stream can queue more jobs, so we need + to check the list again after we've finished */ + d(printf("out of jobs, closing root stream\n")); + camel_stream_write_string((CamelStream *)m->estream, "</body>\n</html>\n"); + camel_stream_close((CamelStream *)m->estream); + camel_object_unref(m->estream); + m->estream = NULL; + } + + /* e_dlist_empty is atomic and doesn't need locking */ + } while (!e_dlist_empty(&m->format->priv->pending_jobs)); + + d(printf("out of jobs, done\n")); + + ((EMFormat *)m->format)->pending_uri_level = puri_level; +} + +static void +efh_format_done (struct _format_msg *m) +{ + d(printf("formatting finished\n")); + + m->format->priv->format_id = -1; + m->format->priv->load_images_now = FALSE; + m->format->state = EM_FORMAT_HTML_STATE_NONE; + g_signal_emit_by_name(m->format, "complete"); +} + +static void +efh_format_free (struct _format_msg *m) +{ + d(printf("formatter freed\n")); + g_object_unref(m->format); + if (m->estream) { + camel_stream_close((CamelStream *)m->estream); + camel_object_unref(m->estream); + } + if (m->folder) + camel_object_unref(m->folder); + g_free(m->uid); + if (m->message) + camel_object_unref(m->message); + if (m->format_source) + g_object_unref(m->format_source); +} + +static MailMsgInfo efh_format_info = { + sizeof (struct _format_msg), + (MailMsgDescFunc) efh_format_desc, + (MailMsgExecFunc) efh_format_exec, + (MailMsgDoneFunc) efh_format_done, + (MailMsgFreeFunc) efh_format_free +}; + +static gboolean +efh_format_timeout(struct _format_msg *m) +{ + GtkHTMLStream *hstream; + EMFormatHTML *efh = m->format; + struct _EMFormatHTMLPrivate *p = efh->priv; + + if (m->format->html == NULL) { + mail_msg_unref(m); + return FALSE; + } + + d(printf("timeout called ...\n")); + if (p->format_id != -1) { + d(printf(" still waiting for cancellation to take effect, waiting ...\n")); + return TRUE; + } + + g_return_val_if_fail (e_dlist_empty(&p->pending_jobs), FALSE); + + d(printf(" ready to go, firing off format thread\n")); + + /* call super-class to kick it off */ + EM_FORMAT_CLASS (parent_class)->format_clone ( + EM_FORMAT (efh), m->folder, m->uid, + m->message, m->format_source); + em_format_html_clear_pobject(m->format); + + /* FIXME: method off EMFormat? */ + if (((EMFormat *)efh)->valid) { + camel_cipher_validity_free(((EMFormat *)efh)->valid); + ((EMFormat *)efh)->valid = NULL; + ((EMFormat *)efh)->valid_parent = NULL; + } + + if (m->message == NULL) { + hstream = gtk_html_begin(efh->html); + gtk_html_stream_close(hstream, GTK_HTML_STREAM_OK); + mail_msg_unref(m); + p->last_part = NULL; + } else { + efh->state = EM_FORMAT_HTML_STATE_RENDERING; + + if (p->last_part != m->message) { + hstream = gtk_html_begin (efh->html); + gtk_html_stream_printf (hstream, "<h5>%s</h5>", _("Formatting Message...")); + gtk_html_stream_close (hstream, GTK_HTML_STREAM_OK); + } + + hstream = NULL; + m->estream = (EMHTMLStream *)em_html_stream_new(efh->html, hstream); + + if (p->last_part == m->message) { + em_html_stream_set_flags (m->estream, + GTK_HTML_BEGIN_KEEP_SCROLL | GTK_HTML_BEGIN_KEEP_IMAGES + | GTK_HTML_BEGIN_BLOCK_UPDATES | GTK_HTML_BEGIN_BLOCK_IMAGES); + } else { + /* clear cache of inline-scanned text parts */ + g_hash_table_remove_all(p->text_inline_parts); + + p->last_part = m->message; + } + + efh->priv->format_id = m->base.seq; + mail_msg_unordered_push (m); + } + + efh->priv->format_timeout_id = 0; + efh->priv->format_timeout_msg = NULL; + + return FALSE; +} + static void efh_free_cache(struct _EMFormatHTMLCache *efhc) { @@ -371,6 +590,143 @@ efh_finalize (GObject *object) } static void +efh_format_clone (EMFormat *emf, + CamelFolder *folder, + const gchar *uid, + CamelMimeMessage *msg, + EMFormat *emfsource) +{ + EMFormatHTML *efh = EM_FORMAT_HTML (emf); + struct _format_msg *m; + + /* How to sub-class ? Might need to adjust api ... */ + + if (efh->html == NULL) + return; + + d(printf("efh_format called\n")); + if (efh->priv->format_timeout_id != 0) { + d(printf(" timeout for last still active, removing ...\n")); + g_source_remove(efh->priv->format_timeout_id); + efh->priv->format_timeout_id = 0; + mail_msg_unref(efh->priv->format_timeout_msg); + efh->priv->format_timeout_msg = NULL; + } + + if (emfsource != NULL) + g_object_ref (emfsource); + + if (folder != NULL) + camel_object_ref (folder); + + if (msg != NULL) + camel_object_ref (msg); + + m = mail_msg_new (&efh_format_info); + m->format = g_object_ref (emf); + m->format_source = emfsource; + m->folder = folder; + m->uid = g_strdup (uid); + m->message = msg; + + if (efh->priv->format_id == -1) { + d(printf(" idle, forcing format\n")); + efh_format_timeout (m); + } else { + d(printf(" still busy, cancelling and queuing wait\n")); + /* cancel and poll for completion */ + mail_msg_cancel (efh->priv->format_id); + efh->priv->format_timeout_msg = m; + efh->priv->format_timeout_id = g_timeout_add ( + 100, (GSourceFunc) efh_format_timeout, m); + } +} + +static void +efh_format_error (EMFormat *emf, + CamelStream *stream, + const gchar *txt) +{ + gchar *html; + + html = camel_text_to_html ( + txt, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); + camel_stream_printf ( + stream, "<em><font color=\"red\">%s</font></em><br>", html); + g_free (html); +} + +static void +efh_format_source (EMFormat *emf, + CamelStream *stream, + CamelMimePart *part) +{ + CamelStreamFilter *filtered_stream; + CamelMimeFilter *filter; + CamelDataWrapper *dw = (CamelDataWrapper *) part; + + filtered_stream = camel_stream_filter_new_with_stream (stream); + + filter = camel_mime_filter_tohtml_new ( + CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | + CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES | + CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0); + camel_stream_filter_add (filtered_stream, filter); + camel_object_unref (filter); + + camel_stream_write_string (stream, "<table><tr><td><tt>"); + em_format_format_text (emf, (CamelStream *) filtered_stream, dw); + camel_object_unref (filtered_stream); + + camel_stream_write_string(stream, "</tt></td></tr></table>"); +} + +static void +efh_format_attachment (EMFormat *emf, + CamelStream *stream, + CamelMimePart *part, + const gchar *mime_type, + const EMFormatHandler *handle) +{ + char *text, *html; + + /* we display all inlined attachments only */ + + /* this could probably be cleaned up ... */ + camel_stream_write_string ( + stream, + "<table border=1 cellspacing=0 cellpadding=0><tr><td>" + "<table width=10 cellspacing=0 cellpadding=0>" + "<tr><td></td></tr></table></td>" + "<td><table width=3 cellspacing=0 cellpadding=0>" + "<tr><td></td></tr></table></td><td><font size=-1>\n"); + + /* output some info about it */ + text = em_format_describe_part(part, mime_type); + html = camel_text_to_html ( + text, ((EMFormatHTML *)emf)->text_html_flags & + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); + camel_stream_write_string (stream, html); + g_free (html); + g_free (text); + + camel_stream_write_string (stream, "</font></td></tr><tr></table>"); + + if (handle && em_format_is_inline (emf, emf->part_id->str, part, handle)) + handle->handler (emf, stream, part, handle); +} + +static gboolean +efh_busy (EMFormat *emf) +{ + EMFormatHTMLPrivate *priv; + + priv = EM_FORMAT_HTML_GET_PRIVATE (emf); + + return (priv->format_id != -1); +} +static void efh_base_init (EMFormatHTMLClass *class) { efh_builtin_init (class); @@ -399,6 +755,8 @@ efh_class_init (EMFormatHTMLClass *class) format_class->format_secure = efh_format_secure; format_class->busy = efh_busy; + class->html_widget_type = GTK_TYPE_HTML; + g_object_class_install_property ( object_class, PROP_BODY_COLOR, @@ -516,8 +874,10 @@ efh_class_init (EMFormatHTMLClass *class) } static void -efh_init (EMFormatHTML *efh) +efh_init (EMFormatHTML *efh, + EMFormatHTMLClass *class) { + GtkHTML *html; GdkColor *color; efh->priv = EM_FORMAT_HTML_GET_PRIVATE (efh); @@ -531,32 +891,35 @@ efh_init (EMFormatHTML *efh) (GDestroyNotify) NULL, (GDestroyNotify) efh_free_cache); - efh->html = (GtkHTML *) gtk_html_new (); - g_object_ref_sink(efh->html); + html = g_object_new (class->html_widget_type, NULL); + efh->html = g_object_ref_sink (html); - gtk_html_set_blocking (efh->html, FALSE); - gtk_html_set_caret_first_focus_anchor (efh->html, EFM_MESSAGE_START_ANAME); + gtk_html_set_blocking (html, FALSE); + gtk_html_set_caret_first_focus_anchor (html, EFM_MESSAGE_START_ANAME); + gtk_html_set_default_content_type (html, "text/html; charset=utf-8"); + gtk_html_set_editable (html, FALSE); - gtk_html_set_default_content_type(efh->html, "text/html; charset=utf-8"); - gtk_html_set_editable(efh->html, FALSE); - - g_signal_connect(efh->html, "url_requested", G_CALLBACK(efh_url_requested), efh); - g_signal_connect(efh->html, "object_requested", G_CALLBACK(efh_object_requested), efh); + g_signal_connect ( + html, "url-requested", + G_CALLBACK (efh_url_requested), efh); + g_signal_connect ( + html, "object-requested", + G_CALLBACK (efh_object_requested), efh); color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY]; - gdk_color_parse ("0xeeeeee", color); + gdk_color_parse ("#eeeeee", color); color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT]; - gdk_color_parse ("0xffffff", color); + gdk_color_parse ("#ffffff", color); color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME]; - gdk_color_parse ("0x3f3f3f", color); + gdk_color_parse ("#3f3f3f", color); color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_HEADER]; - gdk_color_parse ("0xeeeeee", color); + gdk_color_parse ("#eeeeee", color); color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_TEXT]; - gdk_color_parse ("0x000000", color); + gdk_color_parse ("#000000", color); efh->text_html_flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | @@ -590,18 +953,13 @@ em_format_html_get_type (void) }; type = g_type_register_static ( - em_format_get_type(), "EMFormatHTML", &type_info, 0); + em_format_get_type(), "EMFormatHTML", + &type_info, G_TYPE_FLAG_ABSTRACT); } return type; } -EMFormatHTML * -em_format_html_new(void) -{ - return g_object_new (EM_TYPE_FORMAT_HTML, NULL); -} - void em_format_html_load_images (EMFormatHTML *efh) { @@ -688,7 +1046,7 @@ em_format_html_get_image_loading_policy (EMFormatHTML *efh) { g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0); - return efh->priv->image_loading_policy;; + return efh->priv->image_loading_policy; } void @@ -1711,284 +2069,6 @@ efh_builtin_init(EMFormatHTMLClass *efhc) /* ********************************************************************** */ -/* Sigh, this is so we have a cancellable, async rendering thread */ -struct _format_msg { - MailMsg base; - - EMFormatHTML *format; - EMFormat *format_source; - EMHTMLStream *estream; - CamelFolder *folder; - char *uid; - CamelMimeMessage *message; -}; - -static gchar * -efh_format_desc (struct _format_msg *m) -{ - return g_strdup(_("Formatting message")); -} - -static void -efh_format_exec (struct _format_msg *m) -{ - struct _EMFormatHTMLJob *job; - struct _EMFormatPURITree *puri_level; - int cancelled = FALSE; - CamelURL *base; - - if (m->format->html == NULL) - return; - - camel_stream_printf ( - (CamelStream *)m->estream, - "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n" - "<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n</head>\n" - "<body bgcolor =\"#%06x\" text=\"#%06x\" marginwidth=6 marginheight=6>\n", - e_color_to_value ( - &m->format->priv->colors[ - EM_FORMAT_HTML_COLOR_BODY]), - e_color_to_value ( - &m->format->priv->colors[ - EM_FORMAT_HTML_COLOR_HEADER])); - - /* <insert top-header stuff here> */ - - if (((EMFormat *)m->format)->mode == EM_FORMAT_SOURCE) { - em_format_format_source((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message); - } else { - const EMFormatHandler *handle; - - handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/prefix"); - if (handle) - handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle); - handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/rfc822"); - if (handle) - handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle); - handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/post-header-closure"); - if (handle && !((EMFormat *)m->format)->print) - handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle); - - } - - camel_stream_flush((CamelStream *)m->estream); - - puri_level = ((EMFormat *)m->format)->pending_uri_level; - base = ((EMFormat *)m->format)->base; - - do { - /* now dispatch any added tasks ... */ - g_mutex_lock(m->format->priv->lock); - while ((job = (struct _EMFormatHTMLJob *)e_dlist_remhead(&m->format->priv->pending_jobs))) { - g_mutex_unlock(m->format->priv->lock); - - /* This is an implicit check to see if the gtkhtml has been destroyed */ - if (!cancelled) - cancelled = m->format->html == NULL; - - /* Now do an explicit check for user cancellation */ - if (!cancelled) - cancelled = camel_operation_cancel_check(NULL); - - /* call jobs even if cancelled, so they can clean up resources */ - ((EMFormat *)m->format)->pending_uri_level = job->puri_level; - if (job->base) - ((EMFormat *)m->format)->base = job->base; - job->callback(job, cancelled); - ((EMFormat *)m->format)->base = base; - - /* clean up the job */ - camel_object_unref(job->stream); - if (job->base) - camel_url_free(job->base); - g_free(job); - - g_mutex_lock(m->format->priv->lock); - } - g_mutex_unlock(m->format->priv->lock); - - if (m->estream) { - /* Closing this base stream can queue more jobs, so we need - to check the list again after we've finished */ - d(printf("out of jobs, closing root stream\n")); - camel_stream_write_string((CamelStream *)m->estream, "</body>\n</html>\n"); - camel_stream_close((CamelStream *)m->estream); - camel_object_unref(m->estream); - m->estream = NULL; - } - - /* e_dlist_empty is atomic and doesn't need locking */ - } while (!e_dlist_empty(&m->format->priv->pending_jobs)); - - d(printf("out of jobs, done\n")); - - ((EMFormat *)m->format)->pending_uri_level = puri_level; -} - -static void -efh_format_done (struct _format_msg *m) -{ - d(printf("formatting finished\n")); - - m->format->priv->format_id = -1; - m->format->priv->load_images_now = FALSE; - m->format->state = EM_FORMAT_HTML_STATE_NONE; - g_signal_emit_by_name(m->format, "complete"); -} - -static void -efh_format_free (struct _format_msg *m) -{ - d(printf("formatter freed\n")); - g_object_unref(m->format); - if (m->estream) { - camel_stream_close((CamelStream *)m->estream); - camel_object_unref(m->estream); - } - if (m->folder) - camel_object_unref(m->folder); - g_free(m->uid); - if (m->message) - camel_object_unref(m->message); - if (m->format_source) - g_object_unref(m->format_source); -} - -static MailMsgInfo efh_format_info = { - sizeof (struct _format_msg), - (MailMsgDescFunc) efh_format_desc, - (MailMsgExecFunc) efh_format_exec, - (MailMsgDoneFunc) efh_format_done, - (MailMsgFreeFunc) efh_format_free -}; - -static gboolean -efh_format_timeout(struct _format_msg *m) -{ - GtkHTMLStream *hstream; - EMFormatHTML *efh = m->format; - struct _EMFormatHTMLPrivate *p = efh->priv; - - if (m->format->html == NULL) { - mail_msg_unref(m); - return FALSE; - } - - d(printf("timeout called ...\n")); - if (p->format_id != -1) { - d(printf(" still waiting for cancellation to take effect, waiting ...\n")); - return TRUE; - } - - g_return_val_if_fail (e_dlist_empty(&p->pending_jobs), FALSE); - - d(printf(" ready to go, firing off format thread\n")); - - /* call super-class to kick it off */ - EM_FORMAT_CLASS (parent_class)->format_clone ( - EM_FORMAT (efh), m->folder, m->uid, - m->message, m->format_source); - em_format_html_clear_pobject(m->format); - - /* FIXME: method off EMFormat? */ - if (((EMFormat *)efh)->valid) { - camel_cipher_validity_free(((EMFormat *)efh)->valid); - ((EMFormat *)efh)->valid = NULL; - ((EMFormat *)efh)->valid_parent = NULL; - } - - if (m->message == NULL) { - hstream = gtk_html_begin(efh->html); - gtk_html_stream_close(hstream, GTK_HTML_STREAM_OK); - mail_msg_unref(m); - p->last_part = NULL; - } else { - efh->state = EM_FORMAT_HTML_STATE_RENDERING; - - if (p->last_part != m->message) { - hstream = gtk_html_begin (efh->html); - gtk_html_stream_printf (hstream, "<h5>%s</h5>", _("Formatting Message...")); - gtk_html_stream_close (hstream, GTK_HTML_STREAM_OK); - } - - hstream = NULL; - m->estream = (EMHTMLStream *)em_html_stream_new(efh->html, hstream); - - if (p->last_part == m->message) { - em_html_stream_set_flags (m->estream, - GTK_HTML_BEGIN_KEEP_SCROLL | GTK_HTML_BEGIN_KEEP_IMAGES - | GTK_HTML_BEGIN_BLOCK_UPDATES | GTK_HTML_BEGIN_BLOCK_IMAGES); - } else { - /* clear cache of inline-scanned text parts */ - g_hash_table_remove_all(p->text_inline_parts); - - p->last_part = m->message; - } - - efh->priv->format_id = m->base.seq; - mail_msg_unordered_push (m); - } - - efh->priv->format_timeout_id = 0; - efh->priv->format_timeout_msg = NULL; - - return FALSE; -} - -static void efh_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource) -{ - EMFormatHTML *efh = (EMFormatHTML *)emf; - struct _format_msg *m; - - /* How to sub-class ? Might need to adjust api ... */ - - if (efh->html == NULL) - return; - - d(printf("efh_format called\n")); - if (efh->priv->format_timeout_id != 0) { - d(printf(" timeout for last still active, removing ...\n")); - g_source_remove(efh->priv->format_timeout_id); - efh->priv->format_timeout_id = 0; - mail_msg_unref(efh->priv->format_timeout_msg); - efh->priv->format_timeout_msg = NULL; - } - - m = mail_msg_new(&efh_format_info); - m->format = (EMFormatHTML *)emf; - g_object_ref(emf); - m->format_source = emfsource; - if (emfsource) - g_object_ref(emfsource); - m->folder = folder; - if (folder) - camel_object_ref(folder); - m->uid = g_strdup(uid); - m->message = msg; - if (msg) - camel_object_ref(msg); - - if (efh->priv->format_id == -1) { - d(printf(" idle, forcing format\n")); - efh_format_timeout(m); - } else { - d(printf(" still busy, cancelling and queuing wait\n")); - /* cancel and poll for completion */ - mail_msg_cancel(efh->priv->format_id); - efh->priv->format_timeout_msg = m; - efh->priv->format_timeout_id = g_timeout_add(100, (GSourceFunc)efh_format_timeout, m); - } -} - -static void efh_format_error(EMFormat *emf, CamelStream *stream, const char *txt) -{ - char *html; - - html = camel_text_to_html (txt, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL|CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); - camel_stream_printf(stream, "<em><font color=\"red\">%s</font></em><br>", html); - g_free(html); -} - static void efh_format_text_header (EMFormatHTML *emfh, CamelStream *stream, const char *label, const char *value, guint32 flags) { @@ -2563,7 +2643,8 @@ efh_format_headers(EMFormatHTML *efh, CamelStream *stream, CamelMedium *part) } } -static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info) +static void +efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info) { const EMFormatHandler *handle; @@ -2595,57 +2676,3 @@ static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart emf->valid = save; emf->valid_parent = save_parent; } - -static void efh_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart *part) -{ - CamelStreamFilter *filtered_stream; - CamelMimeFilter *html_filter; - CamelDataWrapper *dw = (CamelDataWrapper *)part; - - filtered_stream = camel_stream_filter_new_with_stream ((CamelStream *) stream); - html_filter = camel_mime_filter_tohtml_new (CAMEL_MIME_FILTER_TOHTML_CONVERT_NL - | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES - | CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0); - camel_stream_filter_add(filtered_stream, html_filter); - camel_object_unref(html_filter); - - camel_stream_write_string((CamelStream *)stream, "<table><tr><td><tt>"); - em_format_format_text(emf, (CamelStream *)filtered_stream, dw); - camel_object_unref(filtered_stream); - - camel_stream_write_string(stream, "</tt></td></tr></table>"); -} - -static void -efh_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle) -{ - char *text, *html; - - /* we display all inlined attachments only */ - - /* this could probably be cleaned up ... */ - camel_stream_write_string(stream, - "<table border=1 cellspacing=0 cellpadding=0><tr><td>" - "<table width=10 cellspacing=0 cellpadding=0>" - "<tr><td></td></tr></table></td>" - "<td><table width=3 cellspacing=0 cellpadding=0>" - "<tr><td></td></tr></table></td><td><font size=-1>\n"); - - /* output some info about it */ - text = em_format_describe_part(part, mime_type); - html = camel_text_to_html(text, ((EMFormatHTML *)emf)->text_html_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); - camel_stream_write_string(stream, html); - g_free(html); - g_free(text); - - camel_stream_write_string(stream, "</font></td></tr><tr></table>"); - - if (handle && em_format_is_inline(emf, emf->part_id->str, part, handle)) - handle->handler(emf, stream, part, handle); -} - -static gboolean -efh_busy(EMFormat *emf) -{ - return (((EMFormatHTML *)emf)->priv->format_id != -1); -} diff --git a/mail/em-format-html.h b/mail/em-format-html.h index 33d60ae19a..d35556316a 100644 --- a/mail/em-format-html.h +++ b/mail/em-format-html.h @@ -22,7 +22,7 @@ */ /* - Concrete class for formatting mails to html + Abstract class for formatting mails to html */ #ifndef EM_FORMAT_HTML_H @@ -226,10 +226,11 @@ struct _EMFormatHTML { struct _EMFormatHTMLClass { EMFormatClass parent_class; + + GType html_widget_type; }; GType em_format_html_get_type (void); -EMFormatHTML * em_format_html_new (void); void em_format_html_load_images (EMFormatHTML *efh); void em_format_html_get_color (EMFormatHTML *efh, EMFormatHTMLColorType type, diff --git a/mail/em-html-stream.c b/mail/em-html-stream.c index daa81d356d..096e1c9aa5 100644 --- a/mail/em-html-stream.c +++ b/mail/em-html-stream.c @@ -27,84 +27,39 @@ #endif #include <stdio.h> -#include <gtkhtml/gtkhtml.h> -#include <gtkhtml/gtkhtml-stream.h> #include <gtk/gtk.h> #include "em-html-stream.h" #define d(x) -static void em_html_stream_class_init (EMHTMLStreamClass *klass); -static void em_html_stream_init (CamelObject *object); -static void em_html_stream_finalize (CamelObject *object); - -static ssize_t emhs_sync_write(CamelStream *stream, const char *buffer, size_t n); -static int emhs_sync_close(CamelStream *stream); -static int emhs_sync_flush(CamelStream *stream); - static EMSyncStreamClass *parent_class = NULL; -CamelType -em_html_stream_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - parent_class = (EMSyncStreamClass *)em_sync_stream_get_type(); - type = camel_type_register (em_sync_stream_get_type(), - "EMHTMLStream", - sizeof (EMHTMLStream), - sizeof (EMHTMLStreamClass), - (CamelObjectClassInitFunc) em_html_stream_class_init, - NULL, - (CamelObjectInitFunc) em_html_stream_init, - (CamelObjectFinalizeFunc) em_html_stream_finalize); - } - - return type; -} - -static void -em_html_stream_class_init (EMHTMLStreamClass *klass) -{ - ((EMSyncStreamClass *)klass)->sync_write = emhs_sync_write; - ((EMSyncStreamClass *)klass)->sync_flush = emhs_sync_flush; - ((EMSyncStreamClass *)klass)->sync_close = emhs_sync_close; -} - -static void -em_html_stream_init (CamelObject *object) -{ - /*EMHTMLStream *emhs = (EMHTMLStream *)object;*/ -} - static void -emhs_cleanup(EMHTMLStream *emhs) +emhs_cleanup (EMHTMLStream *emhs) { if (emhs->sync.cancel && emhs->html_stream) - gtk_html_stream_close (emhs->html_stream, GTK_HTML_STREAM_ERROR); + gtk_html_stream_close ( + emhs->html_stream, GTK_HTML_STREAM_ERROR); + emhs->html_stream = NULL; emhs->sync.cancel = TRUE; - g_signal_handler_disconnect(emhs->html, emhs->destroy_id); - g_object_unref(emhs->html); + g_signal_handler_disconnect (emhs->html, emhs->destroy_id); + g_object_unref (emhs->html); emhs->html = NULL; } static void -em_html_stream_finalize (CamelObject *object) +emhs_gtkhtml_destroy (GtkHTML *html, + EMHTMLStream *emhs) { - EMHTMLStream *emhs = (EMHTMLStream *)object; - - d(printf("%p: finalising stream\n", object)); - if (emhs->html_stream) { - d(printf("%p: html stream still open - error\n", object)); - /* set 'in finalise' flag */ - camel_stream_close((CamelStream *)emhs); - } + emhs->sync.cancel = TRUE; + emhs_cleanup (emhs); } static ssize_t -emhs_sync_write(CamelStream *stream, const char *buffer, size_t n) +emhs_sync_write (CamelStream *stream, + const char *buffer, + size_t n) { EMHTMLStream *emhs = EM_HTML_STREAM (stream); @@ -112,9 +67,10 @@ emhs_sync_write(CamelStream *stream, const char *buffer, size_t n) return -1; if (emhs->html_stream == NULL) - emhs->html_stream = gtk_html_begin_full (emhs->html, NULL, NULL, emhs->flags); + emhs->html_stream = gtk_html_begin_full ( + emhs->html, NULL, NULL, emhs->flags); - gtk_html_stream_write(emhs->html_stream, buffer, n); + gtk_html_stream_write (emhs->html_stream, buffer, n); return (ssize_t) n; } @@ -133,48 +89,93 @@ emhs_sync_flush(CamelStream *stream) } static int -emhs_sync_close(CamelStream *stream) +emhs_sync_close (CamelStream *stream) { EMHTMLStream *emhs = (EMHTMLStream *)stream; if (emhs->html_stream == NULL) return -1; - gtk_html_stream_close(emhs->html_stream, GTK_HTML_STREAM_OK); - emhs_cleanup(emhs); + gtk_html_stream_close (emhs->html_stream, GTK_HTML_STREAM_OK); + emhs_cleanup (emhs); return 0; } static void -emhs_gtkhtml_destroy(struct _GtkHTML *html, EMHTMLStream *emhs) +em_html_stream_class_init (EMHTMLStreamClass *class) { - d(printf("%p: emhs gtkhtml destroy\n", emhs)); - emhs->sync.cancel = TRUE; - emhs_cleanup(emhs); + EMSyncStreamClass *sync_stream_class; + + parent_class = (EMSyncStreamClass *)em_sync_stream_get_type(); + + sync_stream_class = EM_SYNC_STREAM_CLASS (class); + sync_stream_class->sync_write = emhs_sync_write; + sync_stream_class->sync_flush = emhs_sync_flush; + sync_stream_class->sync_close = emhs_sync_close; +} + +static void +em_html_stream_init (EMHTMLStream *emhs) +{ +} + +static void +em_html_stream_finalize (EMHTMLStream *emhs) +{ + if (emhs->html_stream) { + /* set 'in finalise' flag */ + camel_stream_close (CAMEL_STREAM (emhs)); + } +} + +CamelType +em_html_stream_get_type (void) +{ + static CamelType type = CAMEL_INVALID_TYPE; + + if (G_UNLIKELY (type == CAMEL_INVALID_TYPE)) { + type = camel_type_register ( + em_sync_stream_get_type(), + "EMHTMLStream", + sizeof (EMHTMLStream), + sizeof (EMHTMLStreamClass), + (CamelObjectClassInitFunc) em_html_stream_class_init, + NULL, + (CamelObjectInitFunc) em_html_stream_init, + (CamelObjectFinalizeFunc) em_html_stream_finalize); + } + + return type; } /* TODO: Could pass NULL for html_stream, and do a gtk_html_begin on first data -> less flashing */ CamelStream * -em_html_stream_new(struct _GtkHTML *html, struct _GtkHTMLStream *html_stream) +em_html_stream_new (GtkHTML *html, + GtkHTMLStream *html_stream) { EMHTMLStream *new; + g_return_val_if_fail (GTK_IS_HTML (html), NULL); + new = EM_HTML_STREAM (camel_object_new (EM_HTML_STREAM_TYPE)); new->html_stream = html_stream; - new->html = html; + new->html = g_object_ref (html); new->flags = 0; - g_object_ref(html); - new->destroy_id = g_signal_connect(html, "destroy", G_CALLBACK(emhs_gtkhtml_destroy), new); + new->destroy_id = g_signal_connect ( + html, "destroy", + G_CALLBACK (emhs_gtkhtml_destroy), new); - em_sync_stream_set_buffer_size(&new->sync, 8192); + em_sync_stream_set_buffer_size (&new->sync, 8192); - return (CamelStream *)new; + return CAMEL_STREAM (new); } void em_html_stream_set_flags (EMHTMLStream *emhs, GtkHTMLBeginFlags flags) { + g_return_if_fail (EM_IS_HTML_STREAM (emhs)); + emhs->flags = flags; } diff --git a/mail/em-html-stream.h b/mail/em-html-stream.h index a8eabdda55..674cc590af 100644 --- a/mail/em-html-stream.h +++ b/mail/em-html-stream.h @@ -24,44 +24,47 @@ #ifndef EM_HTML_STREAM_H #define EM_HTML_STREAM_H -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ +#include <gtkhtml/gtkhtml.h> +#include <gtkhtml/gtkhtml-stream.h> +#include <mail/em-sync-stream.h> -#define EM_HTML_STREAM_TYPE (em_html_stream_get_type ()) -#define EM_HTML_STREAM(obj) (CAMEL_CHECK_CAST((obj), EM_HTML_STREAM_TYPE, EMHTMLStream)) -#define EM_HTML_STREAM_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), EM_HTML_STREAM_TYPE, EMHTMLStreamClass)) -#define EM_IS_HTML_STREAM(o) (CAMEL_CHECK_TYPE((o), EM_HTML_STREAM_TYPE)) +#define EM_HTML_STREAM_TYPE \ + (em_html_stream_get_type ()) +#define EM_HTML_STREAM(obj) \ + (CAMEL_CHECK_CAST \ + ((obj), EM_HTML_STREAM_TYPE, EMHTMLStream)) +#define EM_HTML_STREAM_CLASS(cls) \ + (CAMEL_CHECK_CLASS_CAST \ + ((cls), EM_HTML_STREAM_TYPE, EMHTMLStreamClass)) +#define EM_IS_HTML_STREAM(obj) \ + (CAMEL_CHECK_TYPE \ + ((obj), EM_HTML_STREAM_TYPE)) -struct _GtkHTML; -struct _GtkHTMLStream; +G_BEGIN_DECLS -#include "mail/em-sync-stream.h" +typedef struct _EMHTMLStream EMHTMLStream; +typedef struct _EMHTMLStreamClass EMHTMLStreamClass; -typedef struct _EMHTMLStream { +struct _EMHTMLStream { EMSyncStream sync; guint destroy_id; - struct _GtkHTML *html; - struct _GtkHTMLStream *html_stream; + GtkHTML *html; + GtkHTMLStream *html_stream; GtkHTMLBeginFlags flags; -} EMHTMLStream; +}; -typedef struct { +struct _EMHTMLStreamClass { EMSyncStreamClass parent_class; -} EMHTMLStreamClass; +}; +CamelType em_html_stream_get_type (void); +CamelStream * em_html_stream_new (GtkHTML *html, + GtkHTMLStream *html_stream); +void em_html_stream_set_flags (EMHTMLStream *emhs, + GtkHTMLBeginFlags flags); -CamelType em_html_stream_get_type (void); - -/* the html_stream is closed when we are finalised (with an error), or closed (ok) */ -CamelStream *em_html_stream_new(struct _GtkHTML *html, struct _GtkHTMLStream *html_stream); -void em_html_stream_set_flags (EMHTMLStream *emhs, GtkHTMLBeginFlags flags); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +G_END_DECLS #endif /* EM_HTML_STREAM_H */ |