aboutsummaryrefslogtreecommitdiffstats
path: root/mail/em-format-html.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/em-format-html.c')
-rw-r--r--mail/em-format-html.c1627
1 files changed, 0 insertions, 1627 deletions
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
deleted file mode 100644
index f3b9b46c5a..0000000000
--- a/mail/em-format-html.c
+++ /dev/null
@@ -1,1627 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: Michael Zucchi <notzed@ximian.com>
- *
- * Copyright 2003 Ximian, Inc. (www.ximian.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <ctype.h>
-
-#include <gal/util/e-iconv.h>
-#include <gal/util/e-util.h> /* for e_utf8_strftime, what about e_time_format_time? */
-#include "e-util/e-time-utils.h"
-
-#include <gtkhtml/gtkhtml.h>
-#include <gtkhtml/gtkhtml-embedded.h>
-#include <gtkhtml/gtkhtml-stream.h>
-#include <gtkhtml/htmlengine.h>
-
-#include <libgnomevfs/gnome-vfs-utils.h>
-#include <libgnomevfs/gnome-vfs-mime-utils.h>
-#include <libgnomevfs/gnome-vfs-mime-handlers.h>
-
-#include <camel/camel-mime-message.h>
-#include <camel/camel-stream.h>
-#include <camel/camel-stream-filter.h>
-#include <camel/camel-mime-filter.h>
-#include <camel/camel-mime-filter-tohtml.h>
-#include <camel/camel-mime-filter-enriched.h>
-#include <camel/camel-multipart.h>
-#include <camel/camel-multipart-signed.h>
-#include <camel/camel-gpg-context.h>
-#include <camel/camel-smime-context.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-url.h>
-#include <camel/camel-stream-fs.h>
-#include <camel/camel-string-utils.h>
-#include <camel/camel-http-stream.h>
-#include <camel/camel-data-cache.h>
-#include <camel/camel-file-utils.h>
-
-
-#include <e-util/e-msgport.h>
-
-#include "mail-component.h"
-#include "mail-mt.h"
-
-#include "em-format-html.h"
-#include "em-html-stream.h"
-#include "em-utils.h"
-
-#define d(x)
-
-#define EFH_TABLE_OPEN "<table>"
-
-struct _EMFormatHTMLPrivate {
- struct _CamelMedium *last_part; /* not reffed, DO NOT dereference */
- volatile int format_id; /* format thread id */
- guint format_timeout_id;
- struct _format_msg *format_timeout_msg;
-
- /* Table that re-maps text parts into a mutlipart/mixed */
- GHashTable *text_inline_parts;
-
- EDList pending_jobs;
- GMutex *lock;
-};
-
-static void efh_url_requested(GtkHTML *html, const char *url, GtkHTMLStream *handle, EMFormatHTML *efh);
-static gboolean efh_object_requested(GtkHTML *html, GtkHTMLEmbedded *eb, EMFormatHTML *efh);
-static void efh_gtkhtml_destroy(GtkHTML *html, EMFormatHTML *efh);
-
-static void efh_format_clone(EMFormat *, CamelMedium *, EMFormat *);
-static void efh_format_error(EMFormat *emf, CamelStream *stream, const char *txt);
-static void efh_format_message(EMFormat *, CamelStream *, CamelMedium *);
-static void efh_format_source(EMFormat *, CamelStream *, CamelMimePart *);
-static void efh_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *);
-static gboolean efh_busy(EMFormat *);
-
-static void efh_builtin_init(EMFormatHTMLClass *efhc);
-
-static void efh_write_image(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri);
-
-static EMFormatClass *efh_parent;
-static CamelDataCache *emfh_http_cache;
-
-#define EMFH_HTTP_CACHE_PATH "http"
-
-static void
-efh_init(GObject *o)
-{
- EMFormatHTML *efh = (EMFormatHTML *)o;
-
- efh->priv = g_malloc0(sizeof(*efh->priv));
-
- e_dlist_init(&efh->pending_object_list);
- e_dlist_init(&efh->priv->pending_jobs);
- efh->priv->lock = g_mutex_new();
- efh->priv->format_id = -1;
- efh->priv->text_inline_parts = g_hash_table_new(NULL, NULL);
-
- efh->html = (GtkHTML *)gtk_html_new();
- gtk_html_set_blocking(efh->html, FALSE);
- g_object_ref(efh->html);
- gtk_object_sink((GtkObject *)efh->html);
-
- 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, "destroy", G_CALLBACK(efh_gtkhtml_destroy), efh);
- 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);
-
- efh->body_colour = 0xeeeeee;
- efh->text_colour = 0;
- efh->frame_colour = 0x3f3f3f;
- efh->content_colour = 0xffffff;
- efh->text_html_flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES
- | CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
-}
-
-static void
-efh_gtkhtml_destroy(GtkHTML *html, EMFormatHTML *efh)
-{
- if (efh->priv->format_timeout_id != 0) {
- g_source_remove(efh->priv->format_timeout_id);
- efh->priv->format_timeout_id = 0;
- mail_msg_free(efh->priv->format_timeout_msg);
- efh->priv->format_timeout_msg = NULL;
- }
-
- /* This probably works ... */
- if (efh->priv->format_id != -1)
- mail_msg_cancel(efh->priv->format_id);
-
- if (efh->html) {
- g_object_unref(efh->html);
- efh->html = NULL;
- }
-}
-
-static void
-efh_free_inline_parts(void *key, void *data, void *user)
-{
- camel_object_unref(data);
-}
-
-static void
-efh_finalise(GObject *o)
-{
- EMFormatHTML *efh = (EMFormatHTML *)o;
-
- /* FIXME: check for leaked stuff */
-
- em_format_html_clear_pobject(efh);
- camel_cipher_validity_free(efh->valid);
-
- efh_gtkhtml_destroy(efh->html, efh);
-
- g_hash_table_foreach(efh->priv->text_inline_parts, efh_free_inline_parts, NULL);
- g_hash_table_destroy(efh->priv->text_inline_parts);
-
- g_free(efh->priv);
-
- ((GObjectClass *)efh_parent)->finalize(o);
-}
-
-static void
-efh_base_init(EMFormatHTMLClass *efhklass)
-{
- efh_builtin_init(efhklass);
-}
-
-static void
-efh_class_init(GObjectClass *klass)
-{
- ((EMFormatClass *)klass)->format_clone = efh_format_clone;
- ((EMFormatClass *)klass)->format_error = efh_format_error;
- ((EMFormatClass *)klass)->format_message = efh_format_message;
- ((EMFormatClass *)klass)->format_source = efh_format_source;
- ((EMFormatClass *)klass)->format_attachment = efh_format_attachment;
- ((EMFormatClass *)klass)->busy = efh_busy;
-
- klass->finalize = efh_finalise;
-}
-
-GType
-em_format_html_get_type(void)
-{
- static GType type = 0;
-
- if (type == 0) {
- static const GTypeInfo info = {
- sizeof(EMFormatHTMLClass),
- (GBaseInitFunc)efh_base_init, NULL,
- (GClassInitFunc)efh_class_init,
- NULL, NULL,
- sizeof(EMFormatHTML), 0,
- (GInstanceInitFunc)efh_init
- };
- const char *base_directory = mail_component_peek_base_directory (mail_component_peek ());
- char *path;
-
- efh_parent = g_type_class_ref(em_format_get_type());
- type = g_type_register_static(em_format_get_type(), "EMFormatHTML", &info, 0);
-
- /* cache expiry - 2 hour access, 1 day max */
- path = alloca(strlen(base_directory)+16);
- sprintf(path, "%s/cache", base_directory);
- emfh_http_cache = camel_data_cache_new(path, 0, NULL);
- camel_data_cache_set_expire_age(emfh_http_cache, 24*60*60);
- camel_data_cache_set_expire_access(emfh_http_cache, 2*60*60);
- }
-
- return type;
-}
-
-EMFormatHTML *em_format_html_new(void)
-{
- EMFormatHTML *efh;
-
- efh = g_object_new(em_format_html_get_type(), 0);
-
- return efh;
-}
-
-/* force loading of http images */
-void em_format_html_load_http(EMFormatHTML *emfh)
-{
- if (emfh->load_http)
- return;
-
- /* This will remain set while we're still rendering the same message, then it wont be */
- emfh->load_http_now = TRUE;
- d(printf("redrawing with images forced on\n"));
- em_format_format_clone((EMFormat *)emfh, emfh->format.message, (EMFormat *)emfh);
-}
-
-void
-em_format_html_set_load_http(EMFormatHTML *emfh, int state)
-{
- if (emfh->load_http ^ state) {
- emfh->load_http = state;
- em_format_format_clone((EMFormat *)emfh, emfh->format.message, (EMFormat *)emfh);
- }
-}
-
-void
-em_format_html_set_mark_citations(EMFormatHTML *emfh, int state, guint32 citation_colour)
-{
- if (emfh->mark_citations ^ state || emfh->citation_colour != citation_colour) {
- emfh->mark_citations = state;
- emfh->citation_colour = citation_colour;
- em_format_format_clone((EMFormat *)emfh, emfh->format.message, (EMFormat *)emfh);
- }
-}
-
-void
-em_format_html_set_xmailer_mask(EMFormatHTML *emfh, unsigned int xmailer_mask)
-{
- if (emfh->xmailer_mask ^ xmailer_mask) {
- emfh->xmailer_mask = xmailer_mask;
- em_format_format_clone((EMFormat *)emfh, emfh->format.message, (EMFormat *)emfh);
- }
-}
-
-CamelMimePart *
-em_format_html_file_part(EMFormatHTML *efh, const char *mime_type, const char *path, const char *name)
-{
- CamelMimePart *part;
- CamelStream *stream;
- CamelDataWrapper *dw;
- char *filename;
-
- filename = g_build_filename(path, name, NULL);
- stream = camel_stream_fs_new_with_name(filename, O_RDONLY, 0);
- g_free(filename);
- if (stream == NULL)
- return NULL;
-
- part = camel_mime_part_new();
- dw = camel_data_wrapper_new();
- camel_data_wrapper_construct_from_stream(dw, stream);
- camel_object_unref(stream);
- if (mime_type)
- camel_data_wrapper_set_mime_type(dw, mime_type);
- part = camel_mime_part_new();
- camel_medium_set_content_object((CamelMedium *)part, dw);
- camel_object_unref(dw);
- camel_mime_part_set_filename(part, name);
-
- return part;
-}
-
-/* all this api is a pain in the bum ... */
-
-EMFormatHTMLPObject *
-em_format_html_add_pobject(EMFormatHTML *efh, size_t size, const char *classid, CamelMimePart *part, EMFormatHTMLPObjectFunc func)
-{
- EMFormatHTMLPObject *pobj;
-
- g_assert(size >= sizeof(EMFormatHTMLPObject));
-
- pobj = g_malloc0(size);
- if (classid) {
- pobj->classid = g_strdup(classid);
- } else {
- static unsigned int uriid = 0;
-
- pobj->classid = g_strdup_printf("e-object:///%u", uriid++);
- }
-
- pobj->format = efh;
- pobj->func = func;
- pobj->part = part;
-
- e_dlist_addtail(&efh->pending_object_list, (EDListNode *)pobj);
-
- return pobj;
-}
-
-EMFormatHTMLPObject *
-em_format_html_find_pobject(EMFormatHTML *emf, const char *classid)
-{
- EMFormatHTMLPObject *pw;
-
- pw = (EMFormatHTMLPObject *)emf->pending_object_list.head;
- while (pw->next) {
- if (!strcmp(pw->classid, classid))
- return pw;
- pw = pw->next;
- }
-
- return NULL;
-}
-
-EMFormatHTMLPObject *
-em_format_html_find_pobject_func(EMFormatHTML *emf, CamelMimePart *part, EMFormatHTMLPObjectFunc func)
-{
- EMFormatHTMLPObject *pw;
-
- pw = (EMFormatHTMLPObject *)emf->pending_object_list.head;
- while (pw->next) {
- if (pw->func == func && pw->part == part)
- return pw;
- pw = pw->next;
- }
-
- return NULL;
-}
-
-void
-em_format_html_remove_pobject(EMFormatHTML *emf, EMFormatHTMLPObject *pobject)
-{
- e_dlist_remove((EDListNode *)pobject);
- if (pobject->free)
- pobject->free(pobject);
- g_free(pobject->classid);
- g_free(pobject);
-}
-
-void
-em_format_html_clear_pobject(EMFormatHTML *emf)
-{
- d(printf("clearing pending objects\n"));
- while (!e_dlist_empty(&emf->pending_object_list))
- em_format_html_remove_pobject(emf, (EMFormatHTMLPObject *)emf->pending_object_list.head);
-}
-
-struct _EMFormatHTMLJob *
-em_format_html_job_new(EMFormatHTML *emfh, void (*callback)(struct _EMFormatHTMLJob *job, int cancelled), void *data)
-{
- struct _EMFormatHTMLJob *job = g_malloc0(sizeof(*job));
-
- job->format = emfh;
- job->puri_level = ((EMFormat *)emfh)->pending_uri_level;
- job->callback = callback;
- job->u.data = data;
- if (((EMFormat *)emfh)->base)
- job->base = camel_url_copy(((EMFormat *)emfh)->base);
-
- return job;
-}
-
-void
-em_format_html_job_queue(EMFormatHTML *emfh, struct _EMFormatHTMLJob *job)
-{
- g_mutex_lock(emfh->priv->lock);
- e_dlist_addtail(&emfh->priv->pending_jobs, (EDListNode *)job);
- g_mutex_unlock(emfh->priv->lock);
-}
-
-/* ********************************************************************** */
-
-static void emfh_getpuri(struct _EMFormatHTMLJob *job, int cancelled)
-{
- d(printf(" running getpuri task\n"));
- if (!cancelled)
- job->u.puri->func((EMFormat *)job->format, job->stream, job->u.puri);
-}
-
-static void emfh_gethttp(struct _EMFormatHTMLJob *job, int cancelled)
-{
- CamelStream *cistream = NULL, *costream = NULL, *instream = NULL;
- CamelURL *url;
- ssize_t n, total = 0;
- char buffer[1500];
-
- if (cancelled
- || (url = camel_url_new(job->u.uri, NULL)) == NULL)
- goto badurl;
-
- d(printf(" running load uri task: %s\n", job->u.uri));
-
- if (emfh_http_cache)
- instream = cistream = camel_data_cache_get(emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
-
- if (instream == NULL) {
- char *proxy;
-
- if (!job->format->load_http_now) {
- /* TODO: Ideally we would put the http requests into another queue and only send them out
- if the user selects 'load images', when they do. The problem is how to maintain this
- state with multiple renderings, and how to adjust the thread dispatch/setup routine to handle it */
- /* FIXME: Need to handle 'load if sender in addressbook' case too */
- camel_url_free(url);
- goto done;
- }
-
- instream = camel_http_stream_new(CAMEL_HTTP_METHOD_GET, ((EMFormat *)job->format)->session, url);
- proxy = em_utils_get_proxy_uri();
- camel_http_stream_set_proxy((CamelHttpStream *)instream, proxy);
- g_free(proxy);
- camel_operation_start(NULL, _("Retrieving `%s'"), job->u.uri);
- } else
- camel_operation_start_transient(NULL, _("Retrieving `%s'"), job->u.uri);
-
- camel_url_free(url);
-
- if (instream == NULL)
- goto done;
-
- if (emfh_http_cache != NULL && cistream == NULL)
- costream = camel_data_cache_add(emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
-
- do {
- /* FIXME: progress reporting in percentage, can we get the length always? do we care? */
- n = camel_stream_read(instream, buffer, 1500);
- if (n > 0) {
- camel_operation_progress_count(NULL, total);
- total += n;
- d(printf(" read %d bytes\n", n));
- if (costream && camel_stream_write(costream, buffer, n) == -1) {
- camel_data_cache_remove(emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
- camel_object_unref(costream);
- costream = NULL;
- }
-
- camel_stream_write(job->stream, buffer, n);
- } else if (n < 0 && costream) {
- camel_data_cache_remove(emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
- camel_object_unref(costream);
- costream = NULL;
- }
- } while (n>0);
-
- /* indicates success */
- if (n == 0)
- camel_stream_close(job->stream);
-
- if (costream)
- camel_object_unref(costream);
-
- camel_object_unref(instream);
-done:
- camel_operation_end(NULL);
-badurl:
- g_free(job->u.uri);
-}
-
-/* ********************************************************************** */
-
-static void
-efh_url_requested(GtkHTML *html, const char *url, GtkHTMLStream *handle, EMFormatHTML *efh)
-{
- EMFormatPURI *puri;
- struct _EMFormatHTMLJob *job = NULL;
-
- d(printf("url requested, html = %p, url '%s'\n", html, url));
-
- puri = em_format_find_visible_puri((EMFormat *)efh, url);
- if (puri) {
- puri->use_count++;
-
- d(printf(" adding puri job\n"));
- job = em_format_html_job_new(efh, emfh_getpuri, puri);
- } else if (g_ascii_strncasecmp(url, "http:", 5) == 0 || g_ascii_strncasecmp(url, "https:", 6) == 0) {
- d(printf(" adding job, get %s\n", url));
- job = em_format_html_job_new(efh, emfh_gethttp, g_strdup(url));
- } else {
- d(printf("HTML Includes reference to unknown uri '%s'\n", url));
- gtk_html_stream_close(handle, GTK_HTML_STREAM_ERROR);
- }
-
- if (job) {
- job->stream = em_html_stream_new(html, handle);
- em_format_html_job_queue(efh, job);
- }
-}
-
-static gboolean
-efh_object_requested(GtkHTML *html, GtkHTMLEmbedded *eb, EMFormatHTML *efh)
-{
- EMFormatHTMLPObject *pobject;
- int res = FALSE;
-
- if (eb->classid == NULL)
- return FALSE;
-
- pobject = em_format_html_find_pobject(efh, eb->classid);
- if (pobject) {
- /* This stops recursion of the part */
- e_dlist_remove((EDListNode *)pobject);
- res = pobject->func(efh, eb, pobject);
- e_dlist_addhead(&efh->pending_object_list, (EDListNode *)pobject);
- } else {
- printf("HTML Includes reference to unknown object '%s'\n", eb->classid);
- }
-
- return res;
-}
-
-/* ********************************************************************** */
-#include "em-inline-filter.h"
-#include <camel/camel-stream-null.h>
-
-/* FIXME: This is duplicated in em-format-html-display, should be exported or in security module */
-static const struct {
- const char *icon, *shortdesc;
-} smime_sign_table[4] = {
- { "pgp-signature-nokey.png", N_("Unsigned") },
- { "pgp-signature-ok.png", N_("Valid signature") },
- { "pgp-signature-bad.png", N_("Invalid signature") },
- { "pgp-signature-nokey.png", N_("Valid signature, cannot verify sender") },
-};
-
-static const struct {
- const char *icon, *shortdesc;
-} smime_encrypt_table[4] = {
- { NULL, N_("Unencrypted") },
- { "pgp-signature-ok.png", N_("Encrypted, weak"),},
- { "pgp-signature-ok.png", N_("Encrypted") },
- { "pgp-signature-ok.png", N_("Encrypted, strong") },
-};
-
-/* TODO: this could probably be virtual on em-format-html
- then we only need one version of each type handler */
-static void
-efh_output_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid)
-{
- CamelCipherValidity *save = ((EMFormatHTML *)emf)->valid_parent;
-
- /* Note: this same logic is in efhd_output_secure */
- if (((EMFormatHTML *)emf)->valid == NULL) {
- ((EMFormatHTML *)emf)->valid = valid;
- } else {
- e_dlist_addtail(&((EMFormatHTML *)emf)->valid_parent->children, (EDListNode *)valid);
- camel_cipher_validity_envelope(((EMFormatHTML *)emf)->valid_parent, valid);
- }
-
- ((EMFormatHTML *)emf)->valid_parent = valid;
- em_format_part(emf, stream, part);
- ((EMFormatHTML *)emf)->valid_parent = save;
-
- if (((EMFormatHTML *)emf)->valid == valid
- && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
- || valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) {
- char *classid;
- CamelMimePart *iconpart;
-
- camel_stream_printf(stream, "<table border=0 width=\"100%%\" cellpadding=3 cellspacing=0 bgcolor=%s><tr>",
- valid->sign.status == CAMEL_CIPHER_VALIDITY_SIGN_GOOD?"#88bb88":"#bb8888");
-
- classid = g_strdup_printf("smime:///em-format-html/%p/icon/signed", part);
- camel_stream_printf(stream, "<td valign=\"top\"><img src=\"%s\"></td><td valign=\"top\" width=\"100%%\">", classid);
- iconpart = em_format_html_file_part((EMFormatHTML *)emf, "image/png",
- EVOLUTION_ICONSDIR, smime_sign_table[valid->sign.status].icon);
- if (iconpart) {
- (void)em_format_add_puri(emf, sizeof(EMFormatPURI), classid, iconpart, efh_write_image);
- camel_object_unref(iconpart);
- }
- g_free(classid);
-
- if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
- camel_stream_printf(stream, "%s<br>", _(smime_sign_table[valid->sign.status].shortdesc));
- }
-
- if (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
- camel_stream_printf(stream, "%s<br>", _(smime_encrypt_table[valid->encrypt.status].shortdesc));
- }
-
- camel_stream_printf(stream, "</td></tr></table>");
- }
-}
-
-static void
-efh_application_xpkcs7mime(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
-{
- CamelCipherContext *context;
- CamelException *ex;
- extern CamelSession *session;
- CamelMimePart *opart;
- CamelCipherValidity *valid;
-
- ex = camel_exception_new();
-
- context = camel_smime_context_new(session);
-
- opart = camel_mime_part_new();
- valid = camel_cipher_decrypt(context, part, opart, ex);
- if (valid == NULL) {
- em_format_format_error(emf, stream, ex->desc?ex->desc:_("Could not parse S/MIME message: Unknown error"));
- em_format_part_as(emf, stream, part, NULL);
- } else {
- efh_output_secure(emf, stream, opart, valid);
- }
-
- camel_object_unref(opart);
- camel_object_unref(context);
- camel_exception_free(ex);
-}
-
-static void
-efh_text_plain(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
-{
- CamelStreamFilter *filtered_stream;
- CamelMimeFilter *html_filter;
- CamelMultipart *mp;
- CamelContentType *type;
- const char *format;
- guint32 rgb = 0x737373, flags;
- int i, count;
-
- camel_stream_printf (stream,
- "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=1 width=100%%><tr><td>\n"
- "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=0 width=100%%><tr><td>\n"
- "<table cellspacing=0 cellpadding=10><td><tr>\n",
- efh->frame_colour & 0xffffff, efh->content_colour & 0xffffff);
-
- flags = efh->text_html_flags;
-
- /* Check for RFC 2646 flowed text. */
- type = camel_mime_part_get_content_type(part);
- if (camel_content_type_is (type, "text", "plain")
- && (format = camel_content_type_param (type, "format"))
- && !g_ascii_strcasecmp(format, "flowed"))
- flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
-
- /* This scans the text part for inline-encoded data, creates
- a multipart of all the parts inside it. */
-
- /* FIXME: We should discard this multipart if it only contains
- the original text, but it makes this hash lookup more complex */
-
- /* TODO: We could probably put this in the superclass, since
- no knowledge of html is required - but this messes with
- filters a bit. Perhaps the superclass should just deal with
- html anyway and be done with it ... */
-
- mp = g_hash_table_lookup(efh->priv->text_inline_parts, part);
- if (mp == NULL) {
- EMInlineFilter *inline_filter;
- CamelStream *null;
-
- null = camel_stream_null_new();
- filtered_stream = camel_stream_filter_new_with_stream(null);
- camel_object_unref(null);
- inline_filter = em_inline_filter_new(camel_mime_part_get_encoding(part));
- camel_stream_filter_add(filtered_stream, (CamelMimeFilter *)inline_filter);
- camel_data_wrapper_write_to_stream(camel_medium_get_content_object((CamelMedium *)part), (CamelStream *)filtered_stream);
- camel_stream_close((CamelStream *)filtered_stream);
- camel_object_unref(filtered_stream);
- mp = em_inline_filter_get_multipart(inline_filter);
- g_hash_table_insert(efh->priv->text_inline_parts, part, mp);
- camel_object_unref(inline_filter);
- }
-
- filtered_stream = camel_stream_filter_new_with_stream(stream);
- html_filter = camel_mime_filter_tohtml_new(flags, rgb);
- camel_stream_filter_add(filtered_stream, html_filter);
- camel_object_unref(html_filter);
-
- /* We handle our made-up multipart here, so we don't recursively call ourselves */
-
- count = camel_multipart_get_number(mp);
- for (i=0;i<count;i++) {
- CamelMimePart *newpart = camel_multipart_get_part(mp, i);
-
- type = camel_mime_part_get_content_type(newpart);
- if (camel_content_type_is (type, "text", "plain")) {
- camel_stream_write_string(stream, "<tt>\n");
- em_format_format_text((EMFormat *)efh, (CamelStream *)filtered_stream, camel_medium_get_content_object((CamelMedium *)newpart));
- camel_stream_flush((CamelStream *)filtered_stream);
- camel_stream_write_string(stream, "</tt>\n");
- } else {
- em_format_part((EMFormat *)efh, stream, newpart);
- }
- }
-
- camel_object_unref(filtered_stream);
- camel_stream_write_string(stream,
- "</td></tr></table>\n"
- "</td></tr></table>\n"
- "</td></tr></table>\n");
-}
-
-static void
-efh_text_enriched(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
-{
- CamelStreamFilter *filtered_stream;
- CamelMimeFilter *enriched;
- CamelDataWrapper *dw;
- guint32 flags = 0;
-
- dw = camel_medium_get_content_object((CamelMedium *)part);
-
- if (!strcmp(info->mime_type, "text/richtext")) {
- flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
- camel_stream_write_string( stream, "\n<!-- text/richtext -->\n");
- } else {
- camel_stream_write_string( stream, "\n<!-- text/enriched -->\n");
- }
-
- enriched = camel_mime_filter_enriched_new(flags);
- filtered_stream = camel_stream_filter_new_with_stream (stream);
- camel_stream_filter_add(filtered_stream, enriched);
- camel_object_unref(enriched);
-
- camel_stream_write_string(stream, EFH_TABLE_OPEN "<tr><td><tt>\n");
- em_format_format_text((EMFormat *)efh, (CamelStream *)filtered_stream, dw);
-
- camel_stream_write_string(stream, "</tt></td></tr></table>\n");
- camel_object_unref(filtered_stream);
-}
-
-static void
-efh_write_text_html(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
-{
- em_format_format_text(emf, stream, camel_medium_get_content_object((CamelMedium *)puri->part));
-}
-
-static void
-efh_text_html(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
-{
- const char *location, *base;
- EMFormatPURI *puri;
-
- camel_stream_printf (stream,
- "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=1 width=100%%><tr><td>\n"
- "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=0 width=100%%><tr><td>\n"
- "<!-- text/html -->\n",
- efh->frame_colour & 0xffffff, efh->content_colour & 0xffffff);
-
- if ((base = camel_medium_get_header((CamelMedium *)part, "Content-Base"))) {
- char *base_url;
- size_t len;
-
- len = strlen(base);
- if (*base == '"' && *(base + len - 1) == '"') {
- len -= 2;
- base_url = alloca(len + 1);
- memcpy(base_url, base + 1, len);
- base_url[len] = '\0';
- base = base_url;
- }
-
- /* FIXME: set base needs to go on the gtkhtml stream? */
- gtk_html_set_base(efh->html, base);
- }
-
- puri = em_format_add_puri((EMFormat *)efh, sizeof(EMFormatPURI), NULL, part, efh_write_text_html);
- location = puri->uri?puri->uri:puri->cid;
- d(printf("adding iframe, location %s\n", location));
- camel_stream_printf(stream,
- "<iframe src=\"%s\" frameborder=0 scrolling=no>could not get %s</iframe>\n"
- "</td></tr></table>\n"
- "</td></tr></table>\n",
- location, location);
-}
-
-/* This is a lot of code for something useless ... */
-static void
-efh_message_external(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
-{
- CamelContentType *type;
- const char *access_type;
- char *url = NULL, *desc = NULL;
-
- /* needs to be cleaner */
- type = camel_mime_part_get_content_type(part);
- access_type = camel_content_type_param (type, "access-type");
- if (!access_type) {
- camel_stream_printf(stream, _("Malformed external-body part."));
- return;
- }
-
- if (!g_ascii_strcasecmp(access_type, "ftp") ||
- !g_ascii_strcasecmp(access_type, "anon-ftp")) {
- const char *name, *site, *dir, *mode;
- char *path;
- char ftype[16];
-
- name = camel_content_type_param (type, "name");
- site = camel_content_type_param (type, "site");
- dir = camel_content_type_param (type, "directory");
- mode = camel_content_type_param (type, "mode");
- if (name == NULL || site == NULL)
- goto fail;
-
- /* Generate the path. */
- if (dir)
- path = g_strdup_printf("/%s/%s", *dir=='/'?dir+1:dir, name);
- else
- path = g_strdup_printf("/%s", *name=='/'?name+1:name);
-
- if (mode && &mode)
- sprintf(ftype, ";type=%c", *mode);
- else
- ftype[0] = 0;
-
- url = g_strdup_printf ("ftp://%s%s%s", site, path, ftype);
- g_free (path);
- desc = g_strdup_printf (_("Pointer to FTP site (%s)"), url);
- } else if (!g_ascii_strcasecmp (access_type, "local-file")) {
- const char *name, *site;
-
- name = camel_content_type_param (type, "name");
- site = camel_content_type_param (type, "site");
- if (name == NULL)
- goto fail;
-
- url = g_strdup_printf ("file:///%s", *name == '/' ? name+1:name);
- if (site)
- desc = g_strdup_printf(_("Pointer to local file (%s) valid at site \"%s\""), name, site);
- else
- desc = g_strdup_printf(_("Pointer to local file (%s)"), name);
- } else if (!g_ascii_strcasecmp (access_type, "URL")) {
- const char *urlparam;
- char *s, *d;
-
- /* RFC 2017 */
-
- urlparam = camel_content_type_param (type, "url");
- if (urlparam == NULL)
- goto fail;
-
- /* For obscure MIMEy reasons, the URL may be split into words */
- url = g_strdup (urlparam);
- s = d = url;
- while (*s) {
- /* FIXME: use camel_isspace */
- if (!isspace ((unsigned char)*s))
- *d++ = *s;
- s++;
- }
- *d = 0;
- desc = g_strdup_printf (_("Pointer to remote data (%s)"), url);
- } else
- goto fail;
-
- camel_stream_printf(stream, "<a href=\"%s\">%s</a>", url, desc);
- g_free(url);
- g_free(desc);
-
- return;
-
-fail:
- camel_stream_printf(stream, _("Pointer to unknown external data (\"%s\" type)"), access_type);
-}
-
-static void
-emfh_write_related(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
-{
- em_format_format_content(emf, stream, puri->part);
- camel_stream_close(stream);
-}
-
-static void
-emfh_multipart_related_check(struct _EMFormatHTMLJob *job, int cancelled)
-{
- struct _EMFormatPURITree *ptree;
- EMFormatPURI *puri, *purin;
-
- if (cancelled)
- return;
-
- d(printf(" running multipart/related check task\n"));
-
- ptree = job->puri_level;
- puri = (EMFormatPURI *)ptree->uri_list.head;
- purin = puri->next;
- while (purin) {
- if (puri->use_count == 0) {
- d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"", puri->cid, puri->use_count));
- if (puri->func == emfh_write_related)
- em_format_part((EMFormat *)job->format, (CamelStream *)job->stream, puri->part);
- /* else it was probably added by a previous format this loop */
- }
- puri = purin;
- purin = purin->next;
- }
-}
-
-/* RFC 2387 */
-static void
-efh_multipart_related(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
-{
- CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
- CamelMimePart *body_part, *display_part = NULL;
- CamelContentType *content_type;
- const char *location, *start;
- int i, nparts;
- CamelURL *base_save = NULL;
- EMFormatPURI *puri;
- struct _EMFormatHTMLJob *job;
-
- if (!CAMEL_IS_MULTIPART(mp)) {
- em_format_format_source(emf, stream, part);
- return;
- }
-
- nparts = camel_multipart_get_number(mp);
- content_type = camel_mime_part_get_content_type(part);
- start = camel_content_type_param (content_type, "start");
- if (start && strlen(start)>2) {
- int len;
- const char *cid;
-
- /* strip <>'s */
- len = strlen (start) - 2;
- start++;
-
- for (i=0; i<nparts; i++) {
- body_part = camel_multipart_get_part(mp, i);
- cid = camel_mime_part_get_content_id(body_part);
-
- if (cid && !strncmp(cid, start, len) && strlen(cid) == len) {
- display_part = body_part;
- break;
- }
- }
- } else {
- display_part = camel_multipart_get_part(mp, 0);
- }
-
- if (display_part == NULL) {
- em_format_part_as(emf, stream, part, "multipart/mixed");
- return;
- }
-
- /* stack of present location and pending uri's */
- location = camel_mime_part_get_content_location(part);
- if (location) {
- d(printf("setting content location %s\n", location));
- base_save = emf->base;
- emf->base = camel_url_new(location, NULL);
- }
- em_format_push_level(emf);
-
- /* queue up the parts for possible inclusion */
- for (i = 0; i < nparts; i++) {
- body_part = camel_multipart_get_part(mp, i);
- if (body_part != display_part) {
- puri = em_format_add_puri(emf, sizeof(EMFormatPURI), NULL, body_part, emfh_write_related);
- d(printf(" part '%s' '%s' added\n", puri->uri?puri->uri:"", puri->cid));
- }
- }
-
- em_format_part(emf, stream, display_part);
- camel_stream_flush(stream);
-
- /* queue a job to check for un-referenced parts to add as attachments */
- job = em_format_html_job_new((EMFormatHTML *)emf, emfh_multipart_related_check, NULL);
- job->stream = stream;
- camel_object_ref(stream);
- em_format_html_job_queue((EMFormatHTML *)emf, job);
-
- em_format_pull_level(emf);
-
- if (location) {
- camel_url_free(emf->base);
- emf->base = base_save;
- }
-}
-
-static void
-efh_multipart_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
-{
- CamelMimePart *cpart;
- CamelMultipartSigned *mps;
- CamelCipherContext *cipher = NULL;
-
- mps = (CamelMultipartSigned *)camel_medium_get_content_object((CamelMedium *)part);
- if (!CAMEL_IS_MULTIPART_SIGNED(mps)
- || (cpart = camel_multipart_get_part((CamelMultipart *)mps, CAMEL_MULTIPART_SIGNED_CONTENT)) == NULL) {
- em_format_format_error(emf, stream, _("Could not parse MIME message. Displaying as source."));
- em_format_format_source(emf, stream, part);
- return;
- }
-
- /* FIXME: Should be done via a plugin interface */
- /* FIXME: duplicated in em-format-html-display.c */
- if (g_ascii_strcasecmp("application/x-pkcs7-signature", mps->protocol) == 0)
- cipher = camel_smime_context_new(emf->session);
- else if (g_ascii_strcasecmp("application/pgp-signature", mps->protocol) == 0)
- cipher = camel_gpg_context_new(emf->session);
-
- if (cipher == NULL) {
- em_format_format_error(emf, stream, _("Unsupported signature format"));
- em_format_part_as(emf, stream, part, NULL);
- } else {
- CamelException *ex = camel_exception_new();
- CamelCipherValidity *valid;
-
- valid = camel_cipher_verify(cipher, part, ex);
- if (valid == NULL) {
- em_format_format_error(emf, stream, ex->desc?ex->desc:_("Unknown error verifying signature"));
- em_format_part_as(emf, stream, part, NULL);
- } else {
- efh_output_secure(emf, stream, cpart, valid);
- }
-
- camel_exception_free(ex);
- camel_object_unref(cipher);
- }
-}
-
-static void
-efh_write_image(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
-{
- CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)puri->part);
-
- d(printf("writing image '%s'\n", puri->uri?puri->uri:puri->cid));
- camel_data_wrapper_decode_to_stream(dw, stream);
- camel_stream_close(stream);
-}
-
-static void
-efh_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
-{
- EMFormatPURI *puri;
- const char *location;
-
- puri = em_format_add_puri((EMFormat *)efh, sizeof(EMFormatPURI), NULL, part, efh_write_image);
- location = puri->uri?puri->uri:puri->cid;
- d(printf("adding image '%s'\n", location));
- camel_stream_printf(stream, "<img hspace=10 vspace=10 src=\"%s\">", location);
-}
-
-static EMFormatHandler type_builtin_table[] = {
- { "application/x-pkcs7-mime", (EMFormatFunc)efh_application_xpkcs7mime },
-
- { "image/gif", (EMFormatFunc)efh_image },
- { "image/jpeg", (EMFormatFunc)efh_image },
- { "image/png", (EMFormatFunc)efh_image },
- { "image/x-png", (EMFormatFunc)efh_image },
- { "image/tiff", (EMFormatFunc)efh_image },
- { "image/x-bmp", (EMFormatFunc)efh_image },
- { "image/bmp", (EMFormatFunc)efh_image },
- { "image/svg", (EMFormatFunc)efh_image },
- { "image/x-cmu-raster", (EMFormatFunc)efh_image },
- { "image/x-ico", (EMFormatFunc)efh_image },
- { "image/x-portable-anymap", (EMFormatFunc)efh_image },
- { "image/x-portable-bitmap", (EMFormatFunc)efh_image },
- { "image/x-portable-graymap", (EMFormatFunc)efh_image },
- { "image/x-portable-pixmap", (EMFormatFunc)efh_image },
- { "image/x-xpixmap", (EMFormatFunc)efh_image },
- { "text/enriched", (EMFormatFunc)efh_text_enriched },
- { "text/plain", (EMFormatFunc)efh_text_plain },
- { "text/html", (EMFormatFunc)efh_text_html },
- { "text/richtext", (EMFormatFunc)efh_text_enriched },
- /*{ "text/ *", (EMFormatFunc)efh_text_plain },*/
- { "message/external-body", (EMFormatFunc)efh_message_external },
- { "multipart/signed", (EMFormatFunc)efh_multipart_signed },
- { "multipart/related", (EMFormatFunc)efh_multipart_related },
-
- /* This is where one adds those busted, non-registered types,
- that some idiot mailer writers out there decide to pull out
- of their proverbials at random. */
-
- { "image/jpg", (EMFormatFunc)efh_image },
- { "image/pjpeg", (EMFormatFunc)efh_image },
-};
-
-static void
-efh_builtin_init(EMFormatHTMLClass *efhc)
-{
- int i;
-
- for (i=0;i<sizeof(type_builtin_table)/sizeof(type_builtin_table[0]);i++)
- em_format_class_add_handler((EMFormatClass *)efhc, &type_builtin_table[i]);
-}
-
-/* ********************************************************************** */
-
-/* Sigh, this is so we have a cancellable, async rendering thread */
-struct _format_msg {
- struct _mail_msg msg;
-
- EMFormatHTML *format;
- EMFormat *format_source;
- EMHTMLStream *estream;
- CamelMedium *message;
-};
-
-static char *efh_format_desc(struct _mail_msg *mm, int done)
-{
- return g_strdup(_("Formatting message"));
-}
-
-static void efh_format_do(struct _mail_msg *mm)
-{
- struct _format_msg *m = (struct _format_msg *)mm;
- 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",
- m->format->body_colour & 0xffffff,
- m->format->text_colour & 0xffffff);
-
- /* <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
- em_format_format_message((EMFormat *)m->format, (CamelStream *)m->estream, m->message);
-
- 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;
-
- puri_level = ((EMFormat *)m->format)->pending_uri_level;
- base = ((EMFormat *)m->format)->base;
-
- /* 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);
- d(printf("out of jobs, done\n"));
-
- ((EMFormat *)m->format)->pending_uri_level = puri_level;
-}
-
-static void efh_format_done(struct _mail_msg *mm)
-{
- struct _format_msg *m = (struct _format_msg *)mm;
-
- d(printf("formatting finished\n"));
-
- m->format->priv->format_id = -1;
- g_signal_emit_by_name(m->format, "complete");
-}
-
-static void efh_format_free(struct _mail_msg *mm)
-{
- struct _format_msg *m = (struct _format_msg *)mm;
-
- 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->message)
- camel_object_unref(m->message);
- if (m->format_source)
- g_object_unref(m->format_source);
-}
-
-static struct _mail_msg_op efh_format_op = {
- efh_format_desc,
- efh_format_do,
- efh_format_done,
- 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_free(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_assert(e_dlist_empty(&p->pending_jobs));
-
- d(printf(" ready to go, firing off format thread\n"));
-
- /* call super-class to kick it off */
- efh_parent->format_clone((EMFormat *)efh, m->message, m->format_source);
- em_format_html_clear_pobject(m->format);
-
- if (efh->valid) {
- camel_cipher_validity_free(efh->valid);
- efh->valid = NULL;
- 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_free(m);
- p->last_part = NULL;
- } else {
- /*hstream = gtk_html_begin(efh->html);*/
- hstream = NULL;
- m->estream = (EMHTMLStream *)em_html_stream_new(efh->html, hstream);
-
- if (p->last_part == m->message) {
- /* HACK: so we redraw in the same spot */
- /* FIXME: It doesn't work! */
- efh->html->engine->newPage = FALSE;
- } else {
- /* clear cache of inline-scanned text parts */
- g_hash_table_foreach(p->text_inline_parts, efh_free_inline_parts, NULL);
- g_hash_table_destroy(p->text_inline_parts);
- p->text_inline_parts = g_hash_table_new(NULL, NULL);
-
- p->last_part = m->message;
- /* FIXME: Need to handle 'load if sender in addressbook' case too */
- efh->load_http_now = efh->load_http;
- }
-
- efh->priv->format_id = m->msg.seq;
- e_thread_put(mail_thread_new, (EMsg *)m);
- }
-
- efh->priv->format_timeout_id = 0;
- efh->priv->format_timeout_msg = NULL;
-
- return FALSE;
-}
-
-static void efh_format_clone(EMFormat *emf, CamelMedium *part, 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_free(efh->priv->format_timeout_msg);
- efh->priv->format_timeout_msg = NULL;
- }
-
- m = mail_msg_new(&efh_format_op, NULL, sizeof(*m));
- m->format = (EMFormatHTML *)emf;
- g_object_ref(emf);
- m->format_source = emfsource;
- if (emfsource)
- g_object_ref(emfsource);
- m->message = part;
- if (part)
- camel_object_ref(part);
-
- 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(EMFormat *emf, CamelStream *stream, const char *label, const char *value, guint32 flags)
-{
- char *mhtml = NULL;
- const char *fmt, *html;
-
- if (value == NULL)
- return;
-
- while (*value == ' ')
- value++;
-
- if (flags & EM_FORMAT_HTML_HEADER_HTML)
- html = value;
- else
- html = mhtml = camel_text_to_html(value, ((EMFormatHTML *)emf)->text_html_flags, 0);
-
- if (((EMFormatHTML *)emf)->simple_headers) {
- fmt = "<b>%s</b>: %s<br>";
- } else {
- if (flags & EM_FORMAT_HTML_HEADER_NOCOLUMNS) {
- if (flags & EM_FORMAT_HEADER_BOLD)
- fmt = "<tr><td><b>%s:</b> %s</td></tr>";
- else
- fmt = "<tr><td>%s: %s</td></tr>";
- } else {
- if (flags & EM_FORMAT_HEADER_BOLD)
- fmt = "<tr><th align=\"right\" valign=\"top\">%s:<b>&nbsp;</b></th><td>%s</td></tr>";
- else
- fmt = "<tr><td align=\"right\" valign=\"top\">%s:<b>&nbsp;</b></td><td>%s</td></tr>";
- }
- }
-
- camel_stream_printf(stream, fmt, label, html);
- g_free(mhtml);
-}
-
-static void
-efh_format_address(EMFormat *emf, CamelStream *stream, const CamelInternetAddress *cia, const char *name, guint32 flags)
-{
- char *text;
-
- if (cia == NULL || !camel_internet_address_get(cia, 0, NULL, NULL))
- return;
-
- text = camel_address_format((CamelAddress *)cia);
- efh_format_text_header(emf, stream, name, text, flags | EM_FORMAT_HEADER_BOLD);
- g_free(text);
-}
-
-static void
-efh_format_header(EMFormat *emf, CamelStream *stream, CamelMedium *part, const char *namein, guint32 flags, const char *charset)
-{
-#define msg ((CamelMimeMessage *)part)
-#define efh ((EMFormatHTML *)emf)
- char *name;
-
- name = alloca(strlen(namein)+1);
- strcpy(name, namein);
- camel_strdown(name);
-
- if (!strcmp(name, "from"))
- efh_format_address(emf, stream, camel_mime_message_get_from(msg), _("From"), flags);
- else if (!strcmp(name, "reply-to"))
- efh_format_address(emf, stream, camel_mime_message_get_reply_to(msg), _("Reply-To"), flags);
- else if (!strcmp(name, "to"))
- efh_format_address(emf, stream, camel_mime_message_get_recipients(msg, CAMEL_RECIPIENT_TYPE_TO), _("To"), flags);
- else if (!strcmp(name, "cc"))
- efh_format_address(emf, stream, camel_mime_message_get_recipients(msg, CAMEL_RECIPIENT_TYPE_CC), _("Cc"), flags);
- else if (!strcmp(name, "bcc"))
- efh_format_address(emf, stream, camel_mime_message_get_recipients(msg, CAMEL_RECIPIENT_TYPE_BCC), _("Bcc"), flags);
- else {
- const char *txt, *label;
- char *value = NULL;
-
- if (!strcmp(name, "subject")) {
- txt = camel_mime_message_get_subject(msg);
- label = _("Subject");
- flags |= EM_FORMAT_HEADER_BOLD;
- } else if (!strcmp(name, "x-evolution-mailer")) { /* pseudo-header */
- txt = camel_medium_get_header(part, "x-mailer");
- if (txt == NULL)
- txt = camel_medium_get_header(part, "user-agent");
- if (txt == NULL
- || ((efh->xmailer_mask & EM_FORMAT_HTML_XMAILER_OTHER) == 0
- && ((efh->xmailer_mask & EM_FORMAT_HTML_XMAILER_EVOLUTION) == 0
- || strstr(txt, "Evolution") == NULL)))
- return;
-
- label = _("Mailer");
- flags |= EM_FORMAT_HEADER_BOLD;
- } else if (!strcmp(name, "date")) {
- int msg_offset, local_tz;
- time_t msg_date;
- struct tm local;
- const char *date;
-
- date = camel_medium_get_header(part, "date");
- if (date == NULL)
- return;
-
- /* Show the local timezone equivalent in brackets if the sender is remote */
- msg_date = camel_header_decode_date (date, &msg_offset);
- e_localtime_with_offset(msg_date, &local, &local_tz);
-
- /* Convert message offset to minutes (e.g. -0400 --> -240) */
- msg_offset = ((msg_offset / 100) * 60) + (msg_offset % 100);
- /* Turn into offset from localtime, not UTC */
- msg_offset -= local_tz / 60;
-
- if (msg_offset) {
- char buf[32], *html;
-
- msg_offset += (local.tm_hour * 60) + local.tm_min;
- if (msg_offset >= (24 * 60) || msg_offset < 0) {
- /* translators: strftime format for local time equivalent in Date header display, with day */
- e_utf8_strftime(buf, sizeof(buf), _("<I> (%a, %R %Z)</I>"), &local);
- } else {
- /* translators: strftime format for local time equivalent in Date header display, without day */
- e_utf8_strftime(buf, sizeof(buf), _("<I> (%R %Z)</I>"), &local);
- }
-
- html = camel_text_to_html(date, ((EMFormatHTML *)emf)->text_html_flags, 0);
- txt = value = g_strdup_printf("%s %s", html, buf);
- g_free(html);
- flags |= EM_FORMAT_HTML_HEADER_HTML;
- } else {
- txt = date;
- }
-
- label = _("Date");
- flags |= EM_FORMAT_HEADER_BOLD;
- } else {
- txt = camel_medium_get_header(part, name);
- value = camel_header_decode_string (txt, charset);
- txt = value;
- label = namein;
- }
-
- efh_format_text_header(emf, stream, label, txt, flags);
- g_free(value);
- }
-#undef msg
-#undef efh
-}
-
-void
-em_format_html_format_headers(EMFormatHTML *efh, CamelStream *stream, CamelMedium *part)
-{
- EMFormatHeader *h;
- const char *charset;
- CamelContentType *ct;
-#define emf ((EMFormat *)efh)
-
- ct = camel_mime_part_get_content_type((CamelMimePart *)part);
- charset = camel_content_type_param (ct, "charset");
- charset = e_iconv_charset_name(charset);
-
- if (!efh->simple_headers)
- camel_stream_printf(stream,
- "<font color=\"#%06x\">\n"
- "<table cellpadding=0>\n",
- efh->text_colour & 0xffffff);
-
- /* dump selected headers */
- h = (EMFormatHeader *)emf->header_list.head;
- if (h->next == NULL || emf->mode == EM_FORMAT_ALLHEADERS) {
- struct _camel_header_raw *header;
-
- header = ((CamelMimePart *)part)->headers;
- while (header) {
- efh_format_header(emf, stream, part, header->name, EM_FORMAT_HTML_HEADER_NOCOLUMNS, charset);
- header = header->next;
- }
- } else {
- while (h->next) {
- efh_format_header(emf, stream, part, h->name, h->flags, charset);
- h = h->next;
- }
- }
-
- if (!efh->simple_headers)
- camel_stream_printf(stream,
- "</table>\n</font>\n");
-#undef emf
-}
-
-static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMedium *part)
-{
-#define efh ((EMFormatHTML *)emf)
- CamelCipherValidity *save = efh->valid, *save_parent = efh->valid_parent;
-
- efh->valid = NULL;
- efh->valid_parent = NULL;
-
- if (emf->message != part)
- camel_stream_printf(stream, "<blockquote>\n");
-
- if (!efh->hide_headers)
- em_format_html_format_headers(efh, stream, part);
-
- camel_stream_printf(stream, "<table height=6><tr><td><a></a></td></tr></table>\n");
- em_format_part(emf, stream, (CamelMimePart *)part);
-
- if (emf->message != part)
- camel_stream_printf(stream, "</blockquote>\n");
-
- camel_cipher_validity_free(efh->valid);
-
- efh->valid = save;
- efh->valid_parent = save_parent;
-#undef efh
-}
-
-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_ESCAPE_8BIT, 0);
- camel_stream_filter_add(filtered_stream, html_filter);
- camel_object_unref(html_filter);
-
- camel_stream_write_string((CamelStream *)stream, EFH_TABLE_OPEN "<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, part))
- handle->handler(emf, stream, part, handle);
-}
-
-static gboolean
-efh_busy(EMFormat *emf)
-{
- return (((EMFormatHTML *)emf)->priv->format_id != -1);
-}