/* * * 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 * * * Authors: * Jeffrey Stedfast * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "em-format-html-print.h" #include "em-format-html-display.h" #include "e-mail-attachment-bar.h" #include #include #include #include #include "em-format-html-print.h" #define d(x) static gpointer parent_class = NULL; struct _EMFormatHTMLPrintPrivate { EMFormatHTML *original_formatter; EMFormatPURI *top_level_puri; /* List of attachment PURIs */ GList *attachments; }; enum { PROP_0, PROP_ORIGINAL_FORMATTER }; static void efhp_write_print_layout (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); static void efhp_write_headers (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); static void efhp_write_inline_attachment (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); static void efhp_write_attachments_list (EMFormatHTMLPrint *efhp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable) { GString *str; GList *iter; if (!efhp->priv->attachments) return; str = g_string_new ( "\n"); g_string_append_printf (str, "\n" "\n", _("Attachments"), _("Name"), _("Size")); for (iter = efhp->priv->attachments; iter; iter = iter->next) { EMFormatPURI *puri = iter->data; EAttachment *attachment; GFileInfo *fi; gchar *name, *size; GByteArray *ba; CamelDataWrapper *dw; attachment = ((EMFormatAttachmentPURI *) puri)->attachment; fi = e_attachment_get_file_info (attachment); if (!fi) continue; if (e_attachment_get_description (attachment) && *e_attachment_get_description (attachment)) { name = g_strdup_printf ("%s (%s)", e_attachment_get_description (attachment), g_file_info_get_display_name (fi)); } else { name = g_strdup (g_file_info_get_display_name (fi)); } dw = camel_medium_get_content ((CamelMedium *) puri->part); ba = camel_data_wrapper_get_byte_array (dw); size = g_format_size (ba->len); g_string_append_printf (str, "\n", name, size); g_free (name); g_free (size); } g_string_append (str, "

%s

%s%s
%s%s
\n"); camel_stream_write_string (stream, str->str, cancellable, NULL); g_string_free (str, TRUE); } static void efhp_write_headers (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable) { struct _camel_header_raw raw_header; GString *str, *tmp; gchar *subject; const gchar *buf; EMFormatPURI *p; GList *iter; gint attachments_count; gchar *puri_prefix; buf = camel_medium_get_header (CAMEL_MEDIUM (puri->part), "subject"); subject = camel_header_decode_string (buf, "UTF-8"); str = g_string_new ("\n"); g_string_append_printf ( str, "" "" "\n", subject); g_free (subject); for (iter = g_queue_peek_head_link (&emf->header_list); iter; iter = iter->next) { EMFormatHeader *header = iter->data; raw_header.name = header->name; /* Skip 'Subject' header, it's already displayed. */ if (g_ascii_strncasecmp (header->name, "Subject", 7) == 0) continue; if (header->value && *header->value) { raw_header.value = header->value; em_format_html_format_header (emf, str, CAMEL_MEDIUM (puri->part), &raw_header, header->flags | EM_FORMAT_HTML_HEADER_NOLINKS, "UTF-8"); } else { raw_header.value = g_strdup (camel_medium_get_header ( CAMEL_MEDIUM (emf->message), header->name)); if (raw_header.value && *raw_header.value) { em_format_html_format_header (emf, str, CAMEL_MEDIUM (puri->part), &raw_header, header->flags | EM_FORMAT_HTML_HEADER_NOLINKS, "UTF-8"); } if (raw_header.value) g_free (raw_header.value); } } /* Get prefix of this PURI */ puri_prefix = g_strndup (puri->uri, g_strrstr (puri->uri, ".") - puri->uri); /* Add encryption/signature header */ raw_header.name = _("Security"); tmp = g_string_new (""); /* Find first secured part. */ for (iter = emf->mail_part_list, puri; iter; iter = iter->next) { p = iter->data; if (p->validity_type == 0) continue; if (!g_str_has_prefix (p->uri, puri_prefix)) continue; if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_PGP) && (p->validity_type & EM_FORMAT_VALIDITY_FOUND_SIGNED)) { g_string_append (tmp, _("GPG signed")); } if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_PGP) && (p->validity_type & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED)) { if (tmp->len > 0) g_string_append (tmp, ", "); g_string_append (tmp, _("GPG encrpyted")); } if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_SMIME) && (p->validity_type & EM_FORMAT_VALIDITY_FOUND_SIGNED)) { if (tmp->len > 0) g_string_append (tmp, ", "); g_string_append (tmp, _("S/MIME signed")); } if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_SMIME) && (p->validity_type & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED)) { if (tmp->len > 0) g_string_append (tmp, ", "); g_string_append (tmp, _("S/MIME encrpyted")); } break; } if (tmp->len > 0) { raw_header.value = tmp->str; em_format_html_format_header (emf, str, CAMEL_MEDIUM (p->part), &raw_header, EM_FORMAT_HEADER_BOLD | EM_FORMAT_HTML_HEADER_NOLINKS, "UTF-8"); } g_string_free (tmp, TRUE); /* Count attachments and display the number as a header */ attachments_count = 0; for (iter = emf->mail_part_list; iter; iter = iter ? iter->next : iter) { p = iter->data; if (!g_str_has_prefix (p->uri, puri_prefix)) continue; if ((p->is_attachment || g_str_has_suffix(p->uri, ".attachment")) && (!p->cid)) { attachments_count++; /* EFHD sometimes creates two PURIs per attachment! */ if (iter->next && iter->next->data) { EMFormatPURI *p2 = iter->next->data; if (g_str_has_prefix (p2->uri, p->uri)) iter = iter->next; } } } if (attachments_count > 0) { raw_header.name = _("Attachments"); raw_header.value = g_strdup_printf ("%d", attachments_count); em_format_html_format_header (emf, str, CAMEL_MEDIUM (puri->part), &raw_header, EM_FORMAT_HEADER_BOLD | EM_FORMAT_HTML_HEADER_NOLINKS, "UTF-8"); g_free (raw_header.value); } g_string_append (str, "

%s

"); camel_stream_write_string (stream, str->str, cancellable, NULL); g_string_free (str, TRUE); g_free (puri_prefix); } static void efhp_write_inline_attachment (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable) { gchar *name; EMFormatAttachmentPURI *att_puri = (EMFormatAttachmentPURI *) puri; EAttachment *attachment; GFileInfo *fi; attachment = att_puri->attachment; fi = e_attachment_get_file_info (attachment); if (e_attachment_get_description (attachment) && *e_attachment_get_description (attachment)) { name = g_strdup_printf ("

Attachment: %s (%s)

\n", e_attachment_get_description (attachment), g_file_info_get_display_name (fi)); } else { name = g_strdup_printf ("

Attachment: %s

\n", g_file_info_get_display_name (fi)); } camel_stream_write_string (stream, name, cancellable, NULL); g_free (name); } static void efhp_write_print_layout (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable) { GList *iter; EMFormatWriterInfo print_info = { EM_FORMAT_WRITE_MODE_PRINTING, FALSE, FALSE }; EMFormatHTMLPrint *efhp = EM_FORMAT_HTML_PRINT (emf); g_list_free (efhp->priv->attachments); efhp->priv->attachments = NULL; camel_stream_write_string (stream, "\n\n" "\n\n" "Evolution Mail Display\n" "\n" "\n" "", cancellable, NULL); for (iter = emf->mail_part_list; iter != NULL; iter = iter ? iter->next : iter) { EMFormatPURI *puri = iter->data; if (g_str_has_suffix (puri->uri, "print_layout")) continue; /* To late to change .headers writer_func, do it manually. */ if (g_str_has_suffix (puri->uri, ".headers")) { efhp_write_headers (emf, puri, stream, &print_info, cancellable); continue; } if (g_str_has_suffix (puri->uri, ".rfc822")) { puri->write_func (emf, puri, stream, &print_info, cancellable); while (iter && !g_str_has_suffix (puri->uri, ".rfc822.end")) { iter = iter->next; if (iter) puri = iter->data; } if (!iter) break; continue; } if (puri->is_attachment || g_str_has_suffix (puri->uri, ".attachment")) { const EMFormatHandler *handler; CamelContentType *ct; gchar *mime_type; if (puri->cid && g_ascii_strncasecmp (puri->cid, "cid:", 4) == 0) continue; ct = camel_mime_part_get_content_type (puri->part); mime_type = camel_content_type_simple (ct); handler = em_format_find_handler (puri->emf, mime_type); d(printf("Handler for PURI %s (%s): %s\n", puri->uri, mime_type, handler ? handler->mime_type : "(null)")); g_free (mime_type); efhp->priv->attachments = g_list_append (efhp->priv->attachments, puri); /* If we can't inline this attachment, skip it */ if (handler && puri->write_func) { efhp_write_inline_attachment (puri->emf, puri, stream, &print_info, cancellable); if (iter->next && iter->next->data) { EMFormatPURI *p; p = iter->next->data; /* Has the next PURI the same prefix? */ if (p->write_func && g_str_has_prefix (p->uri, puri->uri)) { p->write_func (emf, p, stream, &print_info, cancellable); iter = iter->next; } else { if (puri->write_func) { puri->write_func (emf, puri, stream, &print_info, cancellable); } } } } continue; } /* Ignore widget parts and unwritable non-attachment parts */ if (puri->write_func == NULL) continue; /* Passed all tests, probably a regular part - display it */ puri->write_func (puri->emf, puri, stream, &print_info, cancellable); } efhp_write_attachments_list (efhp, stream, &print_info, cancellable); camel_stream_write_string (stream, "", cancellable, NULL); } static void efhp_finalize (GObject *object) { EMFormatHTMLPrint *efhp = EM_FORMAT_HTML_PRINT (object); if (efhp->priv->original_formatter) { g_object_unref (efhp->priv->original_formatter); efhp->priv->original_formatter = NULL; } if (efhp->priv->top_level_puri) { em_format_puri_free (efhp->priv->top_level_puri); efhp->priv->top_level_puri = NULL; } if (efhp->priv->attachments) { g_list_free (efhp->priv->attachments); efhp->priv->attachments = NULL; } /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (parent_class)->finalize (object); } static gboolean efhp_is_inline (EMFormat *emf, const gchar *part_id, CamelMimePart *mime_part, const EMFormatHandler *handle) { /* When printing, inline any part that has a handler. */ return (handle != NULL); } static void efhp_set_orig_formatter (EMFormatHTMLPrint *efhp, EMFormat *formatter) { EMFormat *emfp, *emfs; EMFormatPURI *puri; GHashTableIter iter; gpointer key, value; efhp->priv->original_formatter = g_object_ref (formatter); emfp = EM_FORMAT (efhp); emfs = EM_FORMAT (formatter); emfp->mail_part_list = g_list_copy (emfs->mail_part_list); /* Make a shallow copy of the table. This table will NOT destroy * the PURIs when free'd! */ if (emfp->mail_part_table) g_hash_table_unref (emfp->mail_part_table); emfp->mail_part_table = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_iter_init (&iter, emfs->mail_part_table); while (g_hash_table_iter_next (&iter, &key, &value)) g_hash_table_insert (emfp->mail_part_table, key, value); if (emfs->folder) emfp->folder = g_object_ref (emfs->folder); emfp->message_uid = g_strdup (emfs->message_uid); emfp->message = g_object_ref (emfs->message); /* Add a generic PURI that will write a HTML layout * for all the parts */ puri = em_format_puri_new (EM_FORMAT (efhp), sizeof (EMFormatPURI), NULL, "print_layout"); puri->write_func = efhp_write_print_layout; puri->mime_type = g_strdup ("text/html"); em_format_add_puri (EM_FORMAT (efhp), puri); efhp->priv->top_level_puri = puri; } static EMFormatHandler type_builtin_table[] = { { (gchar *) "x-evolution/message/headers", 0, efhp_write_headers, }, }; static void efhp_builtin_init (EMFormatHTMLPrintClass *efhc) { EMFormatClass *emfc; gint ii; emfc = (EMFormatClass *) efhc; for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++) em_format_class_add_handler ( emfc, &type_builtin_table[ii]); } static void efhp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_ORIGINAL_FORMATTER: efhp_set_orig_formatter ( EM_FORMAT_HTML_PRINT (object), (EMFormat *) g_value_get_object (value)); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } static void efhp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EMFormatHTMLPrintPrivate *priv; priv = EM_FORMAT_HTML_PRINT (object)->priv; switch (prop_id) { case PROP_ORIGINAL_FORMATTER: g_value_set_pointer (value, priv->original_formatter); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } static void em_format_html_print_base_init (EMFormatHTMLPrintClass *klass) { efhp_builtin_init (klass); } static void em_format_html_print_class_init (EMFormatHTMLPrintClass *klass) { GObjectClass *object_class; EMFormatClass *format_class; parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (klass, sizeof (EMFormatHTMLPrintPrivate)); object_class = G_OBJECT_CLASS (klass); object_class->finalize = efhp_finalize; object_class->set_property = efhp_set_property; object_class->get_property = efhp_get_property; format_class = EM_FORMAT_CLASS (klass); format_class->is_inline = efhp_is_inline; g_object_class_install_property ( object_class, PROP_ORIGINAL_FORMATTER, g_param_spec_object ( "original-formatter", NULL, NULL, EM_TYPE_FORMAT, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); } static void em_format_html_print_init (EMFormatHTMLPrint *efhp) { efhp->priv = G_TYPE_INSTANCE_GET_PRIVATE ( efhp, EM_TYPE_FORMAT_HTML_PRINT, EMFormatHTMLPrintPrivate); efhp->priv->attachments = NULL; efhp->export_filename = NULL; } GType em_format_html_print_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GTypeInfo type_info = { sizeof (EMFormatHTMLPrintClass), (GBaseInitFunc) em_format_html_print_base_init, (GBaseFinalizeFunc) NULL, (GClassInitFunc) em_format_html_print_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (EMFormatHTMLPrint), 0, /* n_preallocs */ (GInstanceInitFunc) em_format_html_print_init, NULL /* value_table */ }; type = g_type_register_static ( em_format_html_get_type(), "EMFormatHTMLPrint", &type_info, 0); } return type; } EMFormatHTMLPrint * em_format_html_print_new (EMFormatHTML *source) { EMFormatHTMLPrint *efhp; CamelSession *session; g_return_val_if_fail (EM_IS_FORMAT_HTML (source), NULL); session = em_format_get_session (EM_FORMAT (source)); efhp = g_object_new ( EM_TYPE_FORMAT_HTML_PRINT, "session", session, "original-formatter", source, NULL); return efhp; }