From 5b8340563c271fb684a88c6e5bb6dd3bfb629058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Wed, 6 Jun 2012 15:27:19 +0200 Subject: Mail formatter rewrite All mail-parsing and formatting code has been moved to em-format. Parsing is handeled by EMailParser class, formatting by EMailFormatter. Both classes have registry which hold extensions - simple classes that do actual parsing and formatting. Each supported mime-type has it's own parser and formatter extension class. --- composer/e-msg-composer.c | 63 +- data/webview.css | 2 +- em-format/Makefile.am | 105 +- em-format/e-mail-extension-registry.c | 294 ++ em-format/e-mail-extension-registry.h | 156 ++ em-format/e-mail-extension.c | 67 + em-format/e-mail-extension.h | 60 + em-format/e-mail-format-extensions.c | 124 + em-format/e-mail-format-extensions.h | 88 + em-format/e-mail-formatter-attachment-bar.c | 154 ++ em-format/e-mail-formatter-attachment.c | 403 +++ em-format/e-mail-formatter-error.c | 160 ++ em-format/e-mail-formatter-extension.c | 189 ++ em-format/e-mail-formatter-extension.h | 106 + em-format/e-mail-formatter-headers.c | 615 +++++ em-format/e-mail-formatter-image.c | 191 ++ em-format/e-mail-formatter-message-rfc822.c | 276 ++ em-format/e-mail-formatter-print-headers.c | 258 ++ em-format/e-mail-formatter-print.c | 266 ++ em-format/e-mail-formatter-print.h | 63 + em-format/e-mail-formatter-quote-attachment.c | 163 ++ em-format/e-mail-formatter-quote-headers.c | 162 ++ em-format/e-mail-formatter-quote-message-rfc822.c | 188 ++ em-format/e-mail-formatter-quote-text-enriched.c | 141 + em-format/e-mail-formatter-quote-text-html.c | 143 + em-format/e-mail-formatter-quote-text-plain.c | 162 ++ em-format/e-mail-formatter-quote.c | 224 ++ em-format/e-mail-formatter-quote.h | 79 + em-format/e-mail-formatter-secure-button.c | 472 ++++ em-format/e-mail-formatter-source.c | 178 ++ em-format/e-mail-formatter-text-enriched.c | 154 ++ em-format/e-mail-formatter-text-html.c | 376 +++ em-format/e-mail-formatter-text-plain.c | 212 ++ em-format/e-mail-formatter-utils.c | 434 +++ em-format/e-mail-formatter-utils.h | 56 + em-format/e-mail-formatter.c | 1510 +++++++++++ em-format/e-mail-formatter.h | 266 ++ em-format/e-mail-inline-filter.c | 462 ++++ em-format/e-mail-inline-filter.h | 82 + em-format/e-mail-parser-application-mbox.c | 213 ++ em-format/e-mail-parser-application-smime.c | 199 ++ em-format/e-mail-parser-attachment-bar.c | 120 + em-format/e-mail-parser-extension.c | 101 + em-format/e-mail-parser-extension.h | 86 + em-format/e-mail-parser-headers.c | 112 + em-format/e-mail-parser-image.c | 147 + em-format/e-mail-parser-inlinepgp-encrypted.c | 205 ++ em-format/e-mail-parser-inlinepgp-signed.c | 230 ++ em-format/e-mail-parser-message-deliverystatus.c | 116 + em-format/e-mail-parser-message-external.c | 211 ++ em-format/e-mail-parser-message-rfc822.c | 174 ++ em-format/e-mail-parser-message.c | 129 + em-format/e-mail-parser-multipart-alternative.c | 191 ++ em-format/e-mail-parser-multipart-appledouble.c | 130 + em-format/e-mail-parser-multipart-digest.c | 175 ++ em-format/e-mail-parser-multipart-encrypted.c | 220 ++ em-format/e-mail-parser-multipart-mixed.c | 158 ++ em-format/e-mail-parser-multipart-related.c | 162 ++ em-format/e-mail-parser-multipart-signed.c | 252 ++ em-format/e-mail-parser-secure-button.c | 104 + em-format/e-mail-parser-source.c | 108 + em-format/e-mail-parser-text-enriched.c | 128 + em-format/e-mail-parser-text-html.c | 138 + em-format/e-mail-parser-text-plain.c | 253 ++ em-format/e-mail-parser.c | 693 +++++ em-format/e-mail-parser.h | 114 + em-format/e-mail-part-attachment-bar.h | 34 + em-format/e-mail-part-attachment.c | 30 + em-format/e-mail-part-attachment.h | 45 + em-format/e-mail-part-list.c | 130 + em-format/e-mail-part-list.h | 76 + em-format/e-mail-part-utils.c | 546 ++++ em-format/e-mail-part-utils.h | 58 + em-format/e-mail-part.c | 196 ++ em-format/e-mail-part.h | 98 + em-format/e-mail-stripsig-filter.c | 165 ++ em-format/e-mail-stripsig-filter.h | 69 + em-format/em-format-quote.c | 844 ------ em-format/em-format-quote.h | 79 - em-format/em-format.c | 2676 ------------------ em-format/em-format.h | 333 --- em-format/em-inline-filter.c | 463 ---- em-format/em-inline-filter.h | 80 - em-format/em-stripsig-filter.c | 165 -- em-format/em-stripsig-filter.h | 69 - mail/Makefile.am | 10 - mail/e-http-request.c | 67 +- mail/e-mail-attachment-bar.c | 771 ------ mail/e-mail-attachment-bar.h | 79 - mail/e-mail-browser.c | 7 +- mail/e-mail-browser.h | 2 +- mail/e-mail-config-lookup-page.c | 2 +- mail/e-mail-display.c | 779 +++--- mail/e-mail-display.h | 16 +- mail/e-mail-folder-pane.c | 1 - mail/e-mail-paned-view.h | 2 - mail/e-mail-printer.c | 160 +- mail/e-mail-printer.h | 8 +- mail/e-mail-reader-utils.c | 351 ++- mail/e-mail-reader-utils.h | 17 +- mail/e-mail-reader.c | 217 +- mail/e-mail-reader.h | 4 + mail/e-mail-request.c | 110 +- mail/em-composer-utils.c | 57 +- mail/em-composer-utils.h | 6 +- mail/em-format-hook.c | 286 -- mail/em-format-hook.h | 90 - mail/em-format-html-display.c | 1080 -------- mail/em-format-html-display.h | 117 - mail/em-format-html-print.c | 634 ----- mail/em-format-html-print.h | 66 - mail/em-format-html.c | 3011 --------------------- mail/em-format-html.h | 223 -- mail/em-utils.c | 75 +- mail/em-utils.h | 4 +- modules/mail/e-mail-config-format-html.c | 4 +- modules/mail/e-mail-shell-backend.c | 73 +- modules/mail/e-mail-shell-content.h | 1 - modules/mail/e-mail-shell-view-actions.c | 2 +- modules/mail/em-mailer-prefs.c | 1 - widgets/misc/Makefile.am | 2 + widgets/misc/e-attachment-bar.c | 773 ++++++ widgets/misc/e-attachment-bar.h | 79 + widgets/misc/e-attachment-button.c | 3 +- 124 files changed, 17415 insertions(+), 11904 deletions(-) create mode 100644 em-format/e-mail-extension-registry.c create mode 100644 em-format/e-mail-extension-registry.h create mode 100644 em-format/e-mail-extension.c create mode 100644 em-format/e-mail-extension.h create mode 100644 em-format/e-mail-format-extensions.c create mode 100644 em-format/e-mail-format-extensions.h create mode 100644 em-format/e-mail-formatter-attachment-bar.c create mode 100644 em-format/e-mail-formatter-attachment.c create mode 100644 em-format/e-mail-formatter-error.c create mode 100644 em-format/e-mail-formatter-extension.c create mode 100644 em-format/e-mail-formatter-extension.h create mode 100644 em-format/e-mail-formatter-headers.c create mode 100644 em-format/e-mail-formatter-image.c create mode 100644 em-format/e-mail-formatter-message-rfc822.c create mode 100644 em-format/e-mail-formatter-print-headers.c create mode 100644 em-format/e-mail-formatter-print.c create mode 100644 em-format/e-mail-formatter-print.h create mode 100644 em-format/e-mail-formatter-quote-attachment.c create mode 100644 em-format/e-mail-formatter-quote-headers.c create mode 100644 em-format/e-mail-formatter-quote-message-rfc822.c create mode 100644 em-format/e-mail-formatter-quote-text-enriched.c create mode 100644 em-format/e-mail-formatter-quote-text-html.c create mode 100644 em-format/e-mail-formatter-quote-text-plain.c create mode 100644 em-format/e-mail-formatter-quote.c create mode 100644 em-format/e-mail-formatter-quote.h create mode 100644 em-format/e-mail-formatter-secure-button.c create mode 100644 em-format/e-mail-formatter-source.c create mode 100644 em-format/e-mail-formatter-text-enriched.c create mode 100644 em-format/e-mail-formatter-text-html.c create mode 100644 em-format/e-mail-formatter-text-plain.c create mode 100644 em-format/e-mail-formatter-utils.c create mode 100644 em-format/e-mail-formatter-utils.h create mode 100644 em-format/e-mail-formatter.c create mode 100644 em-format/e-mail-formatter.h create mode 100644 em-format/e-mail-inline-filter.c create mode 100644 em-format/e-mail-inline-filter.h create mode 100644 em-format/e-mail-parser-application-mbox.c create mode 100644 em-format/e-mail-parser-application-smime.c create mode 100644 em-format/e-mail-parser-attachment-bar.c create mode 100644 em-format/e-mail-parser-extension.c create mode 100644 em-format/e-mail-parser-extension.h create mode 100644 em-format/e-mail-parser-headers.c create mode 100644 em-format/e-mail-parser-image.c create mode 100644 em-format/e-mail-parser-inlinepgp-encrypted.c create mode 100644 em-format/e-mail-parser-inlinepgp-signed.c create mode 100644 em-format/e-mail-parser-message-deliverystatus.c create mode 100644 em-format/e-mail-parser-message-external.c create mode 100644 em-format/e-mail-parser-message-rfc822.c create mode 100644 em-format/e-mail-parser-message.c create mode 100644 em-format/e-mail-parser-multipart-alternative.c create mode 100644 em-format/e-mail-parser-multipart-appledouble.c create mode 100644 em-format/e-mail-parser-multipart-digest.c create mode 100644 em-format/e-mail-parser-multipart-encrypted.c create mode 100644 em-format/e-mail-parser-multipart-mixed.c create mode 100644 em-format/e-mail-parser-multipart-related.c create mode 100644 em-format/e-mail-parser-multipart-signed.c create mode 100644 em-format/e-mail-parser-secure-button.c create mode 100644 em-format/e-mail-parser-source.c create mode 100644 em-format/e-mail-parser-text-enriched.c create mode 100644 em-format/e-mail-parser-text-html.c create mode 100644 em-format/e-mail-parser-text-plain.c create mode 100644 em-format/e-mail-parser.c create mode 100644 em-format/e-mail-parser.h create mode 100644 em-format/e-mail-part-attachment-bar.h create mode 100644 em-format/e-mail-part-attachment.c create mode 100644 em-format/e-mail-part-attachment.h create mode 100644 em-format/e-mail-part-list.c create mode 100644 em-format/e-mail-part-list.h create mode 100644 em-format/e-mail-part-utils.c create mode 100644 em-format/e-mail-part-utils.h create mode 100644 em-format/e-mail-part.c create mode 100644 em-format/e-mail-part.h create mode 100644 em-format/e-mail-stripsig-filter.c create mode 100644 em-format/e-mail-stripsig-filter.h delete mode 100644 em-format/em-format-quote.c delete mode 100644 em-format/em-format-quote.h delete mode 100644 em-format/em-format.c delete mode 100644 em-format/em-format.h delete mode 100644 em-format/em-inline-filter.c delete mode 100644 em-format/em-inline-filter.h delete mode 100644 em-format/em-stripsig-filter.c delete mode 100644 em-format/em-stripsig-filter.h delete mode 100644 mail/e-mail-attachment-bar.c delete mode 100644 mail/e-mail-attachment-bar.h delete mode 100644 mail/em-format-hook.c delete mode 100644 mail/em-format-hook.h delete mode 100644 mail/em-format-html-display.c delete mode 100644 mail/em-format-html-display.h delete mode 100644 mail/em-format-html-print.c delete mode 100644 mail/em-format-html-print.h delete mode 100644 mail/em-format-html.c delete mode 100644 mail/em-format-html.h create mode 100644 widgets/misc/e-attachment-bar.c create mode 100644 widgets/misc/e-attachment-bar.h diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index ae5048208e..90ce610eb9 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -40,11 +40,15 @@ #include #include #include -#include -#include #include "e-composer-private.h" +#include +#include +#include + +#include + typedef struct _AsyncContext AsyncContext; struct _AsyncContext { @@ -179,49 +183,50 @@ static gchar * emcu_part_to_html (CamelSession *session, CamelMimePart *part, gssize *len, - EMFormat *source, GCancellable *cancellable) { - EMFormatQuote *emfq; CamelStreamMem *mem; GByteArray *buf; gchar *text; - EMFormatParserInfo p_info = { 0 }; - EMFormatWriterInfo w_info = { 0 }; + EMailParser *parser; + EMailFormatter *formatter; + EMailPartList *part_list; GString *part_id; + EShell *shell; + GtkWindow *window; + + shell = e_shell_get_default (); + window = e_shell_get_active_window (shell); buf = g_byte_array_new (); mem = (CamelStreamMem *) camel_stream_mem_new (); camel_stream_mem_set_byte_array (mem, buf); - emfq = em_format_quote_new ( - session, NULL, (CamelStream *) mem, - EM_FORMAT_QUOTE_KEEP_SIG); - em_format_set_composer ((EMFormat *) emfq, TRUE); - if (source) { - /* Copy over things we can, other things are internal. - * XXX Perhaps need different api than 'clone'. */ - if (em_format_get_default_charset (source)) - em_format_set_default_charset ( - (EMFormat *) emfq, em_format_get_default_charset (source)); - if (em_format_get_charset (source)) - em_format_set_charset ( - (EMFormat *) emfq, em_format_get_charset (source)); - } + part_list = e_mail_part_list_new (); part_id = g_string_sized_new (0); - em_format_parse_part (EM_FORMAT (emfq), part, part_id, &p_info, cancellable); - em_format_write (EM_FORMAT (emfq), CAMEL_STREAM (mem), &w_info, cancellable); + parser = e_mail_parser_new (session); + part_list->list = e_mail_parser_parse_part (parser, part, part_id, cancellable); g_string_free (part_id, TRUE); + g_object_unref (parser); + + formatter = e_mail_formatter_quote_new (NULL, E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG); + e_mail_formatter_set_style (formatter, + gtk_widget_get_style (GTK_WIDGET (window)), + gtk_widget_get_state (GTK_WIDGET (window))); - g_object_unref (emfq); + e_mail_formatter_format_sync ( + formatter, part_list, (CamelStream *) mem, + 0, E_MAIL_FORMATTER_MODE_PRINTING, cancellable); + g_object_unref (formatter); + g_object_unref (part_list); camel_stream_write((CamelStream *) mem, "", 1, cancellable, NULL); g_object_unref (mem); text = (gchar *) buf->data; if (len) - *len = buf->len-1; + *len = buf->len - 1; g_byte_array_free (buf, FALSE); return text; @@ -2711,7 +2716,7 @@ handle_multipart_signed (EMsgComposer *composer, gssize length; html = emcu_part_to_html ( - session, mime_part, &length, NULL, cancellable); + session, mime_part, &length, cancellable); e_msg_composer_set_pending_body (composer, html, length); } else { e_msg_composer_attach (composer, mime_part); @@ -2799,7 +2804,7 @@ handle_multipart_encrypted (EMsgComposer *composer, gssize length; html = emcu_part_to_html ( - session, mime_part, &length, NULL, cancellable); + session, mime_part, &length, cancellable); e_msg_composer_set_pending_body (composer, html, length); } else { e_msg_composer_attach (composer, mime_part); @@ -2880,7 +2885,7 @@ handle_multipart_alternative (EMsgComposer *composer, gssize length; html = emcu_part_to_html ( - session, text_part, &length, NULL, cancellable); + session, text_part, &length, cancellable); e_msg_composer_set_pending_body (composer, html, length); } } @@ -2948,7 +2953,7 @@ handle_multipart (EMsgComposer *composer, /* Since the first part is not multipart/alternative, * this must be the body. */ html = emcu_part_to_html ( - session, mime_part, &length, NULL, cancellable); + session, mime_part, &length, cancellable); e_msg_composer_set_pending_body (composer, html, length); } else if (camel_mime_part_get_content_id (mime_part) || camel_mime_part_get_content_location (mime_part)) { @@ -3325,7 +3330,7 @@ e_msg_composer_new_with_message (EShell *shell, html = emcu_part_to_html ( session, CAMEL_MIME_PART (message), - &length, NULL, cancellable); + &length, cancellable); e_msg_composer_set_pending_body (composer, html, length); } diff --git a/data/webview.css b/data/webview.css index 5b0e7348c3..09f94043fb 100644 --- a/data/webview.css +++ b/data/webview.css @@ -58,13 +58,13 @@ img.navigable { } .part-container { - width: 100%; height: 100%; background: #FFF; margin-top: 2px; margin-bottom: 3px; border-width: 1px; border-style: solid; + right: 0; } .part-container-inner-margin { diff --git a/em-format/Makefile.am b/em-format/Makefile.am index 392a195044..6b42ec1262 100644 --- a/em-format/Makefile.am +++ b/em-format/Makefile.am @@ -3,33 +3,118 @@ emformatincludedir = $(privincludedir)/em-format privsolib_LTLIBRARIES = libemformat.la emformatinclude_HEADERS = \ - em-format.h \ - em-format-quote.h \ - em-inline-filter.h \ - em-stripsig-filter.h + e-mail-extension-registry.h \ + e-mail-extension.h \ + e-mail-formatter-extension.h \ + e-mail-formatter.h \ + e-mail-formatter-print.h \ + e-mail-formatter-quote.h \ + e-mail-formatter-utils.h \ + e-mail-inline-filter.h \ + e-mail-parser-extension.h \ + e-mail-parser.h \ + e-mail-part.h \ + e-mail-part-attachment.h \ + e-mail-part-attachment-bar.h \ + e-mail-part-list.h \ + e-mail-part-utils.h \ + e-mail-stripsig-filter.h libemformat_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir) \ + -I$(top_srcdir)/em-format \ + -I$(top_srcdir)/smime/lib \ + -I$(top_srcdir)/smime/gui \ -I$(top_srcdir)/widgets \ $(EVOLUTION_DATA_SERVER_CFLAGS) \ $(GNOME_PLATFORM_CFLAGS) \ - $(LIBSOUP_CFLAGS) + $(LIBSOUP_CFLAGS) \ + -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" + +if ENABLE_SMIME +SMIME_EXTENSIONS = e-mail-parser-application-smime.c +endif libemformat_la_SOURCES = \ $(emformatinclude_HEADERS) \ - em-format.c \ - em-format-quote.c \ - em-inline-filter.c \ - em-stripsig-filter.c + $(emformatextensions_SOURCES) \ + e-mail-extension-registry.c \ + e-mail-extension.c \ + e-mail-inline-filter.c \ + e-mail-format-extensions.c \ + e-mail-formatter.c \ + e-mail-formatter-print.c \ + e-mail-formatter-quote.c \ + e-mail-formatter-utils.c \ + e-mail-formatter-attachment.c \ + e-mail-formatter-attachment-bar.c \ + e-mail-formatter-error.c \ + e-mail-formatter-extension.c \ + e-mail-formatter-headers.c \ + e-mail-formatter-image.c \ + e-mail-formatter-message-rfc822.c \ + e-mail-formatter-secure-button.c \ + e-mail-formatter-source.c \ + e-mail-formatter-text-enriched.c \ + e-mail-formatter-text-html.c \ + e-mail-formatter-text-plain.c \ + e-mail-formatter-print-headers.c \ + e-mail-formatter-quote-attachment.c \ + e-mail-formatter-quote-headers.c \ + e-mail-formatter-quote-message-rfc822.c \ + e-mail-formatter-quote-text-enriched.c \ + e-mail-formatter-quote-text-html.c \ + e-mail-formatter-quote-text-plain.c \ + e-mail-parser-extension.c \ + e-mail-parser.c \ + e-mail-parser-application-mbox.c \ + e-mail-parser-attachment-bar.c \ + e-mail-parser-headers.c \ + e-mail-parser-image.c \ + e-mail-parser-inlinepgp-encrypted.c \ + e-mail-parser-inlinepgp-signed.c \ + e-mail-parser-message.c \ + e-mail-parser-message-deliverystatus.c \ + e-mail-parser-message-external.c \ + e-mail-parser-message-rfc822.c \ + e-mail-parser-multipart-alternative.c \ + e-mail-parser-multipart-appledouble.c \ + e-mail-parser-multipart-digest.c \ + e-mail-parser-multipart-encrypted.c \ + e-mail-parser-multipart-mixed.c \ + e-mail-parser-multipart-related.c \ + e-mail-parser-multipart-signed.c \ + e-mail-parser-secure-button.c \ + e-mail-parser-source.c \ + e-mail-parser-text-enriched.c \ + e-mail-parser-text-html.c \ + e-mail-parser-text-plain.c \ + e-mail-part.c \ + e-mail-part-attachment.c \ + e-mail-part-list.c \ + e-mail-part-utils.c \ + e-mail-stripsig-filter.c \ + $(SMIME_EXTENSIONS) libemformat_la_LDFLAGS = -avoid-version $(NO_UNDEFINED) + +if ENABLE_SMIME +SMIME_LIBS = \ + $(top_builddir)/smime/lib/libessmime.la \ + $(top_builddir)/smime/gui/libevolution-smime.la +endif + libemformat_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ - $(LIBSOUP_LIBS) + $(LIBSOUP_LIBS) \ + $(SMIME_LIBS) -include $(top_srcdir)/git.mk diff --git a/em-format/e-mail-extension-registry.c b/em-format/e-mail-extension-registry.c new file mode 100644 index 0000000000..ef08761300 --- /dev/null +++ b/em-format/e-mail-extension-registry.c @@ -0,0 +1,294 @@ +/* + * e-mail-extension-registry.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 + * + */ + +#include + +#include "e-mail-extension-registry.h" +#include "e-mail-extension.h" +#include "e-mail-format-extensions.h" +#include +#include + +#include + +#include + +#define E_MAIL_EXTENSION_REGISTRY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistryPrivate)) + +struct _EMailExtensionRegistryPrivate { + GHashTable *table; +}; + +static gconstpointer parent_class = 0; + +G_DEFINE_ABSTRACT_TYPE ( + EMailExtensionRegistry, + e_mail_extension_registry, + G_TYPE_OBJECT) + +/** + * EMailExtensionRegistry: + * + * The #EMailExtensionRegistry is an abstract class representing a registry + * for #EMailExtensions. + * + * #EMailParser and #EMailFormatter both have internally a registry object + * based on the #EMailExtensionRegistry. + * + * One extension can registry itself for more mime-types. + */ + +static void +mail_extension_registry_finalize (GObject *object) +{ + EMailExtensionRegistry *reg = E_MAIL_EXTENSION_REGISTRY (object); + + if (reg->priv->table) { + g_hash_table_destroy (reg->priv->table); + reg->priv->table = NULL; + } + + /* Chain up to parent's finalize() */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +void +e_mail_extension_registry_class_init (EMailExtensionRegistryClass *klass) +{ + GObjectClass *object_class; + + g_type_class_add_private (klass, sizeof (EMailExtensionRegistryPrivate)); + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = mail_extension_registry_finalize; +} + +static void +destroy_queue (GQueue *queue) +{ + g_queue_free_full (queue, g_object_unref); +} + +void +e_mail_extension_registry_init (EMailExtensionRegistry *reg) +{ + reg->priv = E_MAIL_EXTENSION_REGISTRY_GET_PRIVATE (reg); + + reg->priv->table = g_hash_table_new_full ( + g_str_hash, g_str_equal, NULL, (GDestroyNotify) destroy_queue); +} + +/** + * e_mail_extension_registry_add_extension: + * @reg: An #EMailExtensionRegistry + * @extension: An #EMailExtension + * + * Registrys the @extension as a handler for all mime-types that it is able + * to handle. + */ +void +e_mail_extension_registry_add_extension (EMailExtensionRegistry *reg, + EMailExtension *extension) +{ + gint i; + const gchar **types; + + g_return_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg)); + g_return_if_fail (E_IS_MAIL_EXTENSION (extension)); + + /* One reference per extension is enough */ + g_object_ref (extension); + + types = e_mail_extension_get_mime_types (extension); + for (i = 0; types && types[i]; i++) { + GQueue *queue; + + queue = g_hash_table_lookup (reg->priv->table, types[i]); + if (!queue) { + queue = g_queue_new (); + g_queue_push_head (queue, extension); + g_hash_table_insert (reg->priv->table, (gchar *) types[i], queue); + } else { + g_queue_push_head (queue, extension); + } + + if (camel_debug ("emformat:registry")) { + printf("Added extension '%s' for type '%s'\n", + G_OBJECT_TYPE_NAME (extension), types[i]); + } + } +} + +/** + * e_mail_extension_registry_remove_extension: + * @reg: An #EMailExtensionRegistry + * @extension: An #EMailExtension + * + * Removes @extension from the registry. + */ +void +e_mail_extension_registry_remove_extension (EMailExtensionRegistry *reg, + EMailExtension *extension) +{ + gint i; + const gchar **types; + + g_return_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg)); + g_return_if_fail (E_IS_MAIL_EXTENSION (extension)); + + types = e_mail_extension_get_mime_types (extension); + for (i = 0; types && types[i]; i++) { + GQueue *queue; + + queue = g_hash_table_lookup (reg->priv->table, types[i]); + if (!queue) { + i++; + continue; + } + + g_queue_remove (queue, extension); + + if (camel_debug ("emformat:registry")) { + printf("Removed extension '%s' from type '%s'\n", + G_OBJECT_TYPE_NAME (extension), types[i]); + } + } + + g_object_unref (extension); +} + +/** + * e_mail_extension_registry_get_for_mime_type: + * @reg: An #EMailExtensionRegistry + * @mime_type: A string with mime-type to look up + * + * Tries to lookup list of #EMailExtensions that has registryed themselves + * as handlers for the @mime_type. + * + * Return value: Returns #GQueue of #EMailExtensions or %NULL when there + * are no extension registryed for given @mime_type. + */ +GQueue * +e_mail_extension_registry_get_for_mime_type (EMailExtensionRegistry *reg, + const gchar *mime_type) +{ + g_return_val_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg), NULL); + g_return_val_if_fail (mime_type && *mime_type, NULL); + + return g_hash_table_lookup (reg->priv->table, mime_type); +} + +/** + * e_mail_extension_registry_get_fallback: + * @reg: An #EMailExtensionRegistry + * @mime_type: A string with mime-type whose fallback to look up + * + * Tries to lookup fallback parsers for given mime type. For instance, for + * multipart/alternative, it will try to lookup multipart/ * parser. + * + * Return Value: Returns #QGueue of #EMailExtension>s or %NULL when there + * are no extensions registryed for the fallback type. + */ +GQueue * +e_mail_extension_registry_get_fallback (EMailExtensionRegistry *reg, + const gchar *mime_type) +{ + gchar *s, *type; + gsize len; + GQueue *parsers; + + g_return_val_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg), NULL); + g_return_val_if_fail (mime_type && *mime_type, NULL); + + s = strchr (mime_type, '/'); + len = s - mime_type; + + s = g_alloca (len); + strncpy (s, mime_type, len); + type = g_ascii_strdown (s, len); + s = g_strdup_printf ("%s/*", type); + + parsers = g_hash_table_lookup (reg->priv->table, s); + + g_free (type); + g_free (s); + + return parsers; +} + +/******************************************************************************/ + +static void e_mail_parser_extension_registry_extensible_interface_init (EExtensibleInterface *iface); + +G_DEFINE_TYPE_WITH_CODE ( + EMailParserExtensionRegistry, + e_mail_parser_extension_registry, + E_TYPE_MAIL_EXTENSION_REGISTRY, + G_IMPLEMENT_INTERFACE ( + E_TYPE_EXTENSIBLE, + e_mail_parser_extension_registry_extensible_interface_init)); + +static void +e_mail_parser_extension_registry_init (EMailParserExtensionRegistry *parser_ereg) +{ + +} + +static void +e_mail_parser_extension_registry_class_init (EMailParserExtensionRegistryClass *klass) +{ + e_mail_parser_extension_registry_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_extension_registry_extensible_interface_init (EExtensibleInterface *interface) +{ + +} + +/******************************************************************************/ + +static void e_mail_formatter_extension_registry_extensible_interface_init (EExtensibleInterface *iface); + +G_DEFINE_TYPE_WITH_CODE ( + EMailFormatterExtensionRegistry, + e_mail_formatter_extension_registry, + E_TYPE_MAIL_EXTENSION_REGISTRY, + G_IMPLEMENT_INTERFACE ( + E_TYPE_EXTENSIBLE, + e_mail_formatter_extension_registry_extensible_interface_init)); + +static void +e_mail_formatter_extension_registry_init (EMailFormatterExtensionRegistry *formatter_ereg) +{ + +} + +static void +e_mail_formatter_extension_registry_class_init (EMailFormatterExtensionRegistryClass *klass) +{ + e_mail_formatter_extension_registry_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_extension_registry_extensible_interface_init (EExtensibleInterface *interface) +{ + +} diff --git a/em-format/e-mail-extension-registry.h b/em-format/e-mail-extension-registry.h new file mode 100644 index 0000000000..a6ddb441e0 --- /dev/null +++ b/em-format/e-mail-extension-registry.h @@ -0,0 +1,156 @@ +/* + * e-mail-extension-registry.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 + * + */ + +#ifndef E_MAIL_EXTENSION_REGISTRY_H_ +#define E_MAIL_EXTENSION_REGISTRY_H_ + +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_EXTENSION_REGISTRY \ + (e_mail_extension_registry_get_type ()) +#define E_MAIL_EXTENSION_REGISTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistry)) +#define E_MAIL_EXTENSION_REGISTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistryClass)) +#define E_IS_MAIL_EXTENSION_REGISTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_EXTENSION_REGISTRY)) +#define E_IS_MAIL_EXTENSION_REGISTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_EXTENSION_REGISTRY)) +#define E_MAIL_EXTENSION_REGISTRY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistryClass)) + +G_BEGIN_DECLS + +typedef struct _EMailExtensionRegistry EMailExtensionRegistry; +typedef struct _EMailExtensionRegistryClass EMailExtensionRegistryClass; +typedef struct _EMailExtensionRegistryPrivate EMailExtensionRegistryPrivate; + +struct _EMailExtensionRegistryClass { + GObjectClass parent_class; +}; + +struct _EMailExtensionRegistry { + GObject parent; + EMailExtensionRegistryPrivate *priv; +}; + +GType e_mail_extension_registry_get_type (void); + +void e_mail_extension_registry_add_extension (EMailExtensionRegistry *reg, + EMailExtension *extension); + +void e_mail_extension_registry_remove_extension + (EMailExtensionRegistry *reg, + EMailExtension *extension); + +GQueue * e_mail_extension_registry_get_for_mime_type + (EMailExtensionRegistry *reg, + const gchar *mime_type); + +GQueue * e_mail_extension_registry_get_fallback (EMailExtensionRegistry *reg, + const gchar *mime_type); + +G_END_DECLS + +/******************************************************************************/ + +/* Standard GObject macros */ +#define E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY \ + (e_mail_parser_extension_registry_get_type ()) +#define E_MAIL_PARSER_EXTENSION_REGISTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, EMailParserExtensionRegistry)) +#define E_MAIL_PARSER_EXTENSION_REGISTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, EMailParserExtensionRegistryClass)) +#define E_IS_MAIL_PARSER_EXTENSION_REGISTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY)) +#define E_IS_MAIL_PARSER_EXTENSION_REGISTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY)) +#define E_MAIL_PARSER_EXTENSION_REGISTRY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, EMailParserExtensionRegistryClass)) + +G_BEGIN_DECLS + +typedef struct _EMailParserExtensionRegistry EMailParserExtensionRegistry; +typedef struct _EMailParserExtensionRegistryClass EMailParserExtensionRegistryClass; +typedef struct _EMailParserExtensionRegistryPrivate EMailParserExtensionRegistryPrivate; + +struct _EMailParserExtensionRegistryClass { + EMailExtensionRegistryClass parent_class; +}; + +struct _EMailParserExtensionRegistry { + EMailExtensionRegistry parent; + EMailParserExtensionRegistryPrivate *priv; +}; + +GType e_mail_parser_extension_registry_get_type (void); + +G_END_DECLS + +/******************************************************************************/ + +/* Standard GObject macros */ +#define E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY \ + (e_mail_formatter_extension_registry_get_type ()) +#define E_MAIL_FORMATTER_EXTENSION_REGISTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, EMailFormatterExtensionRegistry)) +#define E_MAIL_FORMATTER_EXTENSION_REGISTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, EMailFormatterExtensionRegistryClass)) +#define E_IS_MAIL_FORMATTER_EXTENSION_REGISTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY)) +#define E_IS_MAIL_FORMATTER_EXTENSION_REGISTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY)) +#define E_MAIL_FORMATTER_EXTENSION_REGISTRY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, EMailFormatterExtensionRegistryClass)) + +G_BEGIN_DECLS + +typedef struct _EMailFormatterExtensionRegistry EMailFormatterExtensionRegistry; +typedef struct _EMailFormatterExtensionRegistryClass EMailFormatterExtensionRegistryClass; +typedef struct _EMailFormatterExtensionRegistryPrivate EMailFormatterExtensionRegistryPrivate; + +struct _EMailFormatterExtensionRegistryClass { + EMailExtensionRegistryClass parent_class; +}; + +struct _EMailFormatterExtensionRegistry { + EMailExtensionRegistry parent; + EMailFormatterExtensionRegistryPrivate *priv; +}; + +GType e_mail_formatter_extension_registry_get_type (void); + +G_END_DECLS + +#endif /* E_MAIL_EXTENSION_REGISTRY_H_ */ diff --git a/em-format/e-mail-extension.c b/em-format/e-mail-extension.c new file mode 100644 index 0000000000..9516974824 --- /dev/null +++ b/em-format/e-mail-extension.c @@ -0,0 +1,67 @@ +/* + * e-mail-extension.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 + * + */ + +#include "e-mail-extension.h" + +#include + +G_DEFINE_INTERFACE (EMailExtension, e_mail_extension, G_TYPE_OBJECT) + +static void +e_mail_extension_default_init (EMailExtensionInterface *iface) +{ + +} + +/** + * EMailExtension: + * + * The #EMailExtension is an abstract interface for all extensions for + * #EMailParser and #EmailFormatter. + * + * The interface is further extended by #EMailParserExtension and + * #EMailFormatterExtension interfaces which define final API for both types + * of extensions. + */ + +/** + * e_mail_extension_get_mime_types: + * @extension: an #EMailExtension + * + * A virtual function reimplemented in all mail extensions that returns a + * @NULL-terminated array of mime types that the particular extension is able + * to process. + * + * The mime-types can be either full (like text/plain), or with common subtype, + * e.g. text/ *. User should try to find the best mathing mime-type handler and + * use the latter type only as a fallback. + * + * Return value: a @NULL-terminated array or @NULL + */ +const gchar ** +e_mail_extension_get_mime_types (EMailExtension *extension) +{ + EMailExtensionInterface *interface; + + g_return_val_if_fail (E_IS_MAIL_EXTENSION (extension), NULL); + + interface = E_MAIL_EXTENSION_GET_INTERFACE (extension); + g_return_val_if_fail (interface->mime_types != NULL, NULL); + + return interface->mime_types (extension); +} diff --git a/em-format/e-mail-extension.h b/em-format/e-mail-extension.h new file mode 100644 index 0000000000..941638aed8 --- /dev/null +++ b/em-format/e-mail-extension.h @@ -0,0 +1,60 @@ +/* + * e-mail-extension.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 + * + */ + +#ifndef E_MAIL_EXTENSION_H +#define E_MAIL_EXTENSION_H + +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_EXTENSION \ + (e_mail_extension_get_type ()) +#define E_MAIL_EXTENSION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_EXTENSION, EMailExtension)) +#define E_MAIL_EXTENSION_INTERFACE(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_EXTENSION, EMailExtensionInterface)) +#define E_IS_MAIL_EXTENSION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_EXTENSION)) +#define E_IS_MAIL_EXTENSION_INTERFACE(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_EXTENSION)) +#define E_MAIL_EXTENSION_GET_INTERFACE(obj) \ + (G_TYPE_INSTANCE_GET_INTERFACE \ + ((obj), E_TYPE_MAIL_EXTENSION, EMailExtensionInterface)) + +G_BEGIN_DECLS + +typedef struct _EMailExtension EMailExtension; +typedef struct _EMailExtensionInterface EMailExtensionInterface; + +struct _EMailExtensionInterface { + GTypeInterface parent_interface; + + const gchar ** (*mime_types) (EMailExtension *extension); +}; + +GType e_mail_extension_get_type (void); + +const gchar ** e_mail_extension_get_mime_types (EMailExtension *extension); + +G_END_DECLS + +#endif /* E_MAIL_EXTENSION_H */ diff --git a/em-format/e-mail-format-extensions.c b/em-format/e-mail-format-extensions.c new file mode 100644 index 0000000000..fa7d5d8683 --- /dev/null +++ b/em-format/e-mail-format-extensions.c @@ -0,0 +1,124 @@ +/* + * e-mail-format-extensions.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 + * + */ + +#include "e-mail-format-extensions.h" + +#include "em-format/e-mail-parser-extension.h" +#include "em-format/e-mail-formatter-extension.h" + +typedef GType (*TypeFunc) (void); + +TypeFunc parser_funcs[] = { + e_mail_parser_application_mbox_get_type, + e_mail_parser_attachment_bar_get_type, + e_mail_parser_headers_get_type, + e_mail_parser_message_get_type, + e_mail_parser_secure_button_get_type, + e_mail_parser_source_get_type, + e_mail_parser_image_get_type, + e_mail_parser_inline_pgp_encrypted_get_type, + e_mail_parser_inline_pgp_signed_get_type, + e_mail_parser_message_delivery_status_get_type, + e_mail_parser_message_external_get_type, + e_mail_parser_message_rfc822_get_type, + e_mail_parser_multipart_alternative_get_type, + e_mail_parser_multipart_apple_double_get_type, + e_mail_parser_multipart_digest_get_type, + e_mail_parser_multipart_encrypted_get_type, + e_mail_parser_multipart_mixed_get_type, + e_mail_parser_multipart_related_get_type, + e_mail_parser_multipart_signed_get_type, + e_mail_parser_text_enriched_get_type, + e_mail_parser_text_html_get_type, + e_mail_parser_text_plain_get_type, +#ifdef ENABLE_SMIME + e_mail_parser_application_smime_get_type, +#endif + NULL +}; + +TypeFunc formatter_funcs[] = { + e_mail_formatter_attachment_get_type, + e_mail_formatter_attachment_bar_get_type, + e_mail_formatter_error_get_type, + e_mail_formatter_headers_get_type, + e_mail_formatter_secure_button_get_type, + e_mail_formatter_source_get_type, + e_mail_formatter_image_get_type, + e_mail_formatter_message_rfc822_get_type, + e_mail_formatter_text_enriched_get_type, + e_mail_formatter_text_html_get_type, + e_mail_formatter_text_plain_get_type, + NULL +}; + +TypeFunc quote_formatter_funcs[] = { + e_mail_formatter_quote_attachment_get_type, + e_mail_formatter_quote_headers_get_type, + e_mail_formatter_quote_message_rfc822_get_type, + e_mail_formatter_quote_text_enriched_get_type, + e_mail_formatter_quote_text_html_get_type, + e_mail_formatter_quote_text_plain_get_type, + NULL +}; + +TypeFunc print_formatter_funcs[] = { + e_mail_formatter_print_headers_get_type, + NULL +}; + +static void +load (EMailExtensionRegistry *ereg, + TypeFunc *func_array) +{ + gint i = 0; + + for (i = 0; func_array[i] != NULL; i++) { + GType type; + EMailExtension *extension; + + type = func_array[i](); + extension = g_object_new (type, NULL); + + e_mail_extension_registry_add_extension (ereg, extension); + } +} + +void +e_mail_parser_internal_extensions_load (EMailExtensionRegistry *ereg) +{ + load (ereg, parser_funcs); +} + +void +e_mail_formatter_internal_extensions_load (EMailExtensionRegistry *ereg) +{ + load (ereg, formatter_funcs); +} + +void +e_mail_formatter_quote_internal_extensions_load (EMailExtensionRegistry *ereg) +{ + load (ereg, quote_formatter_funcs); +} + +void +e_mail_formatter_print_internal_extensions_load (EMailExtensionRegistry *ereg) +{ + load (ereg, print_formatter_funcs); +} diff --git a/em-format/e-mail-format-extensions.h b/em-format/e-mail-format-extensions.h new file mode 100644 index 0000000000..74638ef499 --- /dev/null +++ b/em-format/e-mail-format-extensions.h @@ -0,0 +1,88 @@ +/* + * extensions.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 + * + */ + +#ifndef EXTENSIONS_H_ +#define EXTENSIONS_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +G_BEGIN_DECLS + +void e_mail_formatter_internal_extensions_load (EMailExtensionRegistry *ereg); +void e_mail_parser_internal_extensions_load (EMailExtensionRegistry *ereg); +void e_mail_formatter_quote_internal_extensions_load (EMailExtensionRegistry *ereg); +void e_mail_formatter_print_internal_extensions_load (EMailExtensionRegistry *ereg); + +GType e_mail_formatter_attachment_get_type (void); +GType e_mail_formatter_attachment_bar_get_type + (void); +GType e_mail_formatter_error_get_type (void); +GType e_mail_formatter_headers_get_type (void); +GType e_mail_formatter_secure_button_get_type + (void); +GType e_mail_formatter_source_get_type (void); +GType e_mail_formatter_image_get_type (void); +GType e_mail_formatter_message_rfc822_get_type (void); +GType e_mail_formatter_text_enriched_get_type (void); +GType e_mail_formatter_text_html_get_type (void); +GType e_mail_formatter_text_plain_get_type (void); + +GType e_mail_parser_application_mbox_get_type (void); +GType e_mail_parser_attachment_bar_get_type (void); +GType e_mail_parser_headers_get_type (void); +GType e_mail_parser_message_get_type (void); +GType e_mail_parser_secure_button_get_type (void); +GType e_mail_parser_source_get_type (void); +GType e_mail_parser_image_get_type (void); +GType e_mail_parser_inline_pgp_encrypted_get_type (void); +GType e_mail_parser_inline_pgp_signed_get_type (void); +GType e_mail_parser_message_delivery_status_get_type (void); +GType e_mail_parser_message_external_get_type (void); +GType e_mail_parser_message_rfc822_get_type (void); +GType e_mail_parser_multipart_alternative_get_type (void); +GType e_mail_parser_multipart_apple_double_get_type (void); +GType e_mail_parser_multipart_digest_get_type (void); +GType e_mail_parser_multipart_encrypted_get_type (void); +GType e_mail_parser_multipart_mixed_get_type (void); +GType e_mail_parser_multipart_related_get_type (void); +GType e_mail_parser_multipart_signed_get_type (void); +GType e_mail_parser_text_enriched_get_type (void); +GType e_mail_parser_text_html_get_type (void); +GType e_mail_parser_text_plain_get_type (void); +#ifdef ENABLE_SMIME +GType e_mail_parser_application_smime_get_type (void); +#endif + +GType e_mail_formatter_quote_attachment_get_type (void); +GType e_mail_formatter_quote_headers_get_type (void); +GType e_mail_formatter_quote_message_rfc822_get_type (void); +GType e_mail_formatter_quote_text_enriched_get_type (void); +GType e_mail_formatter_quote_text_html_get_type (void); +GType e_mail_formatter_quote_text_plain_get_type (void); + +GType e_mail_formatter_print_headers_get_type (void); + +G_END_DECLS + +#endif /* EXTENSIONS_H_ */ diff --git a/em-format/e-mail-formatter-attachment-bar.c b/em-format/e-mail-formatter-attachment-bar.c new file mode 100644 index 0000000000..c1fda1636c --- /dev/null +++ b/em-format/e-mail-formatter-attachment-bar.c @@ -0,0 +1,154 @@ +/* + * e-mail-formatter-attachment-bar.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "e-mail-format-extensions.h" +#include "e-mail-part-attachment-bar.h" +#include + +#include + +#include +#include + +typedef struct _EMailFormatterAttachmentBar { + GObject parent; +} EMailFormatterAttachmentBar; + +typedef struct _EMailFormatterAttachmentBarClass { + GObjectClass parent_class; +} EMailFormatterAttachmentBarClass; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterAttachmentBar, + e_mail_formatter_attachment_bar, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.widget.attachment-bar", NULL }; + +static gboolean +emfe_attachment_bar_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + gchar *str; + + if ((context->mode != E_MAIL_FORMATTER_MODE_NORMAL) && + (context->mode != E_MAIL_FORMATTER_MODE_RAW)) + return FALSE; + + str = g_strdup_printf ( + "", + part->id, part->id); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + return TRUE; +} + +static void +unset_bar_from_store_data (GObject *store, + EAttachmentBar *bar) +{ + /* + if (E_IS_ATTACHMENT_STORE (store)) + g_object_set_data (store, "attachment-bar", NULL); + */ +} + +static GtkWidget * +emfe_attachment_bar_get_widget (EMailFormatterExtension *extension, + EMailPartList *context, + EMailPart *part, + GHashTable *params) +{ + EMailPartAttachmentBar *empab; + GtkWidget *widget; + + g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAttachmentBar), NULL); + + empab = (EMailPartAttachmentBar *) part; + widget = e_attachment_bar_new (empab->store); + g_object_set_data (G_OBJECT (empab->store), "attachment-bar", widget); + g_object_weak_ref (G_OBJECT (widget), + (GWeakNotify) unset_bar_from_store_data, empab->store); + + return widget; +} + +static const gchar * +emfe_attachment_bar_get_display_name (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar * +emfe_attachment_bar_get_description (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar ** +emfe_attachment_bar_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_attachment_bar_class_init (EMailFormatterAttachmentBarClass *klass) +{ + e_mail_formatter_attachment_bar_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_attachment_bar_format; + iface->get_widget = emfe_attachment_bar_get_widget; + iface->get_display_name = emfe_attachment_bar_get_display_name; + iface->get_description = emfe_attachment_bar_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_attachment_bar_mime_types; +} + +static void +e_mail_formatter_attachment_bar_init (EMailFormatterAttachmentBar *extension) +{ + +} diff --git a/em-format/e-mail-formatter-attachment.c b/em-format/e-mail-formatter-attachment.c new file mode 100644 index 0000000000..3d63413a69 --- /dev/null +++ b/em-format/e-mail-formatter-attachment.c @@ -0,0 +1,403 @@ +/* + * e-mail-formatter-attachment.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" +#include "e-mail-part-attachment.h" +#include "e-mail-part-attachment-bar.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define d(x) + +typedef struct _EMailFormatterAttachment { + GObject parent; +} EMailFormatterAttachment; + +typedef struct _EMailFormatterAttachmentClass { + GObjectClass parent_class; +} EMailFormatterAttachmentClass; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterAttachment, + e_mail_formatter_attachment, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init) +) + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.attachment", + "application/vnd.evolution.widget.attachment-button", + NULL }; + +static EAttachmentStore * +find_attachment_store (GSList *parts, + const gchar *start_id) +{ + gchar *tmp, *pos; + EMailPart *part; + gchar *id; + + id = g_strconcat (start_id, ".attachment-bar", NULL); + tmp = g_strdup (id); + part = NULL; + do { + GSList *iter; + + d(printf("Looking up attachment bar as %s\n", id)); + + for (iter = parts; iter; iter = iter->next) { + EMailPart *p = iter->data; + + if (!p) + continue; + + if (g_strcmp0 (p->id, id) == 0) { + part = p; + break; + } + } + + pos = g_strrstr (tmp, "."); + if (!pos) + break; + + g_free (id); + g_free (tmp); + tmp = g_strndup (start_id, pos - tmp); + id = g_strdup_printf ("%s.attachment-bar", tmp); + + } while (pos && !part); + + g_free (id); + g_free (tmp); + + if (part) { + return ((EMailPartAttachmentBar *) part)->store; + } + + return NULL; +} + +static gboolean +emfe_attachment_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + gchar *str, *text, *html; + gchar *button_id; + EAttachmentStore *store; + EMailExtensionRegistry *reg; + GQueue *extensions; + EMailPartAttachment *empa; + gchar *attachment_part_id; + + g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAttachment), FALSE); + + empa = (EMailPartAttachment *) part; + + if ((context->mode == E_MAIL_FORMATTER_MODE_NORMAL) || + (context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) { + if (part->validity) { + e_attachment_set_signed ( + empa->attachment, part->validity->sign.status); + e_attachment_set_encrypted ( + empa->attachment, part->validity->encrypt.status); + } + + store = find_attachment_store (context->parts, part->id); + if (store) { + GList *attachments = e_attachment_store_get_attachments (store); + if (!g_list_find (attachments, empa->attachment)) { + e_attachment_store_add_attachment ( + store, empa->attachment); + } + g_list_free (attachments); + } else { + g_warning ("Failed to locate attachment-bar for %s", part->id); + } + } + + /* If the attachment is requested as RAW, then call the handler directly + * and do not append any other code. */ + if ((context->mode == E_MAIL_FORMATTER_MODE_RAW) || + (context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) { + EMailExtensionRegistry *reg; + GQueue *extensions; + GList *iter; + reg = e_mail_formatter_get_extension_registry (formatter); + + extensions = e_mail_extension_registry_get_for_mime_type ( + reg, empa->snoop_mime_type); + if (!extensions) { + extensions = e_mail_extension_registry_get_fallback ( + reg, empa->snoop_mime_type); + } + + if (!extensions) + return FALSE; + + if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) { + gchar *name; + EAttachment *attachment; + GFileInfo *fi; + const gchar *description; + + attachment = empa->attachment; + fi = e_attachment_get_file_info (attachment); + + description = e_attachment_get_description (attachment); + if (description && *description) { + name = g_strdup_printf ("

Attachment: %s (%s)

\n", + description, 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); + } + + for (iter = g_queue_peek_head_link (extensions); iter; iter = iter->next) { + + EMailFormatterExtension *ext; + ext = iter->data; + if (!ext) + continue; + + if (e_mail_formatter_extension_format (ext, formatter, + context, part, stream, cancellable)) { + return TRUE; + } + } + + return FALSE; + } + + /* E_MAIL_FORMATTER_MODE_NORMAL: */ + + reg = e_mail_formatter_get_extension_registry (formatter); + extensions = e_mail_extension_registry_get_for_mime_type ( + reg, empa->snoop_mime_type); + + if (!extensions) { + extensions = e_mail_extension_registry_get_fallback ( + reg, empa->snoop_mime_type); + } + + text = e_mail_part_describe (part->part, empa->snoop_mime_type); + html = camel_text_to_html ( + text, e_mail_formatter_get_text_format_flags (formatter) & + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); + g_free (text); + + if (empa->attachment_view_part_id) + attachment_part_id = empa->attachment_view_part_id; + else + attachment_part_id = part->id; + + button_id = g_strconcat (attachment_part_id, ".attachment_button", NULL); + + str = g_strdup_printf ( + "
" + "" + "" + "" + "" + "", part->id, button_id, html); + + camel_stream_write_string (stream, str, cancellable, NULL); + g_free (button_id); + g_free (str); + g_free (html); + + if (extensions) { + GList *iter; + CamelStream *content_stream; + gboolean ok; + + content_stream = camel_stream_mem_new (); + ok = FALSE; + if (empa->attachment_view_part_id != NULL) { + + GSList *att_parts; + + att_parts = e_mail_part_list_get_iter ( + context->parts, + empa->attachment_view_part_id); + + if (att_parts && att_parts->data) { + ok = e_mail_formatter_format_as ( + formatter, context, att_parts->data, + content_stream, NULL, cancellable); + } + + } else { + + for (iter = g_queue_peek_head_link (extensions); iter; iter = iter->next) { + + EMailFormatterExtension *ext; + + ext = iter->data; + if (!ext) + continue; + + if (e_mail_formatter_extension_format ( + ext, formatter, context, + part, content_stream, + cancellable)) { + ok = TRUE; + break; + } + } + } + + if (ok) { + str = g_strdup_printf ( + "", cancellable, NULL); + } + + g_object_unref (content_stream); + } + + camel_stream_write_string (stream, "
" + "" + "%s
" + "
", + attachment_part_id); + + camel_stream_write_string ( + stream, str, cancellable, NULL); + g_free (str); + + g_seekable_seek ( + G_SEEKABLE (content_stream), 0, + G_SEEK_SET, cancellable, NULL); + camel_stream_write_to_stream ( + content_stream, stream, + cancellable, NULL); + + camel_stream_write_string ( + stream, "
", cancellable, NULL); + + return TRUE; +} + +static GtkWidget * +emfe_attachment_get_widget (EMailFormatterExtension *extension, + EMailPartList *context, + EMailPart *part, + GHashTable *params) +{ + EMailPartAttachment *empa; + EAttachmentStore *store; + EAttachmentView *view; + GtkWidget *widget; + + g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAttachment), NULL); + empa = (EMailPartAttachment *) part; + + store = find_attachment_store (context->list, part->id); + widget = e_attachment_button_new (); + g_object_set_data (G_OBJECT (widget), "uri", part->id); + e_attachment_button_set_attachment ( + E_ATTACHMENT_BUTTON (widget), empa->attachment); + view = g_object_get_data (G_OBJECT (store), "attachment-bar"); + if (view) { + e_attachment_button_set_view ( + E_ATTACHMENT_BUTTON (widget), view); + } + + gtk_widget_set_can_focus (widget, TRUE); + gtk_widget_show (widget); + + return widget; +} + +static const gchar * +emfe_attachment_get_display_name (EMailFormatterExtension *extension) +{ + return _("Attachment"); +} + +static const gchar * +emfe_attachment_get_description (EMailFormatterExtension *extension) +{ + return _("Display as attachment"); +} + +static const gchar ** +emfe_attachment_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_attachment_class_init (EMailFormatterAttachmentClass *klass) +{ + e_mail_formatter_attachment_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_attachment_format; + iface->get_widget = emfe_attachment_get_widget; + iface->get_display_name = emfe_attachment_get_display_name; + iface->get_description = emfe_attachment_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_attachment_mime_types; +} + +static void +e_mail_formatter_attachment_init (EMailFormatterAttachment *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-error.c b/em-format/e-mail-formatter-error.c new file mode 100644 index 0000000000..95f201145b --- /dev/null +++ b/em-format/e-mail-formatter-error.c @@ -0,0 +1,160 @@ +/* + * e-mail-formatter-error.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "e-mail-format-extensions.h" + +#include + +#include +#include +#include + +#include + +typedef struct _EMailFormatterError { + GObject parent; +} EMailFormatterError; + +typedef struct _EMailFormatterErrorClass { + GObjectClass parent_class; +} EMailFormatterErrorClass; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterError, + e_mail_formatter_error, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.error", NULL }; + +static gboolean +emfe_error_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + CamelStream *filtered_stream; + CamelMimeFilter *filter; + CamelDataWrapper *dw; + gchar *html; + + dw = camel_medium_get_content ((CamelMedium *) part->part); + + html = g_strdup_printf ( + "
" + "
\n" + "\n" + "\n" + "\n" + "\n" + "
" + "", + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_FRAME)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_BODY)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_TEXT)), + GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG); + + camel_stream_write_string (stream, html, cancellable, NULL); + g_free (html); + + filtered_stream = camel_stream_filter_new (stream); + filter = camel_mime_filter_tohtml_new ( + CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); + camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered_stream), filter); + g_object_unref (filter); + + camel_data_wrapper_decode_to_stream_sync (dw, filtered_stream, cancellable, NULL); + camel_stream_flush (filtered_stream, cancellable, NULL); + g_object_unref (filtered_stream); + + camel_stream_write_string (stream, + "
\n" + "
\n" + "
", + cancellable, NULL); + + return TRUE; +} + +static const gchar * +emfe_error_get_display_name (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar * +emfe_error_get_description (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar ** +emfe_error_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_error_class_init (EMailFormatterErrorClass *klass) +{ + e_mail_formatter_error_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_error_format; + iface->get_display_name = emfe_error_get_display_name; + iface->get_description = emfe_error_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_error_mime_types; +} + +static void +e_mail_formatter_error_init (EMailFormatterError *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-extension.c b/em-format/e-mail-formatter-extension.c new file mode 100644 index 0000000000..381855bac5 --- /dev/null +++ b/em-format/e-mail-formatter-extension.c @@ -0,0 +1,189 @@ +/* + * e-mail-formatter-extension.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 + * + */ + +#include "e-mail-formatter-extension.h" + +G_DEFINE_INTERFACE ( + EMailFormatterExtension, + e_mail_formatter_extension, + E_TYPE_MAIL_EXTENSION) + +/** + * EMailFormatterExtension: + * + * The #EMailFormatterExtension is an abstract interface for all extensions for + * #EmailFormatter. + */ + +static void +e_mail_formatter_extension_default_init (EMailFormatterExtensionInterface *iface) +{ + +} + +/** + * e_mail_formatter_extension_format + * @extension: an #EMailFormatterExtension + * @formatter: an #EMailFormatter + * @context: an #EMailFormatterContext + * @part: a #EMailPart to be formatter + * @stream: a #CamelStream to which the output should be written + * @cancellable: (allow-none) a #GCancellable + * + * A virtual function reimplemented in all mail formatter extensions. The function + * formats @part, generated HTML (or other format that can be displayed to user) + * and writes it to the @stream. + * + * When the function is unable to format the @part (either because it's broken + * or because it is a different mimetype then the extension is specialized for), the + * function will return @FALSE indicating the #EMailFormatter, that it should pick + * another extension. + * + * Implementation of this function must be thread-safe. + * + * Return value: Returns @TRUE when the @part was successfully formatted and + * data were written to the @stream, @FALSE otherwise. + */ +gboolean +e_mail_formatter_extension_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + EMailFormatterExtensionInterface *interface; + + g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), FALSE); + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE); + g_return_val_if_fail (context != NULL, FALSE); + g_return_val_if_fail (part != NULL, FALSE); + g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE); + + interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension); + g_return_val_if_fail (interface->format != NULL, FALSE); + + return interface->format (extension, formatter, context, part, stream, cancellable); +} + +/** + * e_mail_formatter_extension_has_widget: + * @extension: an #EMailFormatterExtension + * + * Returns whether the extension can provide a GtkWidget. + * + * Return value: Returns %TRUE when @extension reimplements get_widget(), %FALSE + * otherwise. + */ +gboolean +e_mail_formatter_extension_has_widget (EMailFormatterExtension *extension) +{ + EMailFormatterExtensionInterface *interface; + + g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), FALSE); + + interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension); + + return (interface->get_widget != NULL); +} + +/** + * e_mail_formatter_extension_get_widget: + * @extension: an #EMailFormatterExtension + * @part: an #EMailPart + * @params: a #GHashTable + * + * A virtual function reimplemented in some mail formatter extensions. The function + * should construct a #GtkWidget for given @part. The @params hash table can contain + * additional parameters listed in the <object> HTML element that has requested + * the widget. + * + * When @bind_dom_func is not %NULL, the callee will set a callback function + * which should be called when the webpage is completely rendered to setup + * bindings between DOM events and the widget. + * + * Return value: Returns a #GtkWidget or %NULL, when error occurs or given @extension + * does not reimplement this method. + */ +GtkWidget * +e_mail_formatter_extension_get_widget (EMailFormatterExtension *extension, + EMailPartList *context, + EMailPart *part, + GHashTable *params) +{ + EMailFormatterExtensionInterface *interface; + GtkWidget *widget; + + g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), NULL); + g_return_val_if_fail (part != NULL, NULL); + g_return_val_if_fail (params != NULL, NULL); + + interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension); + + widget = NULL; + if (interface->get_widget) { + widget = interface->get_widget ( + extension, context, part, params); + } + + return widget; +} + +/** + * e_mail_formatter_extension_get_display_name: + * @extension: an #EMailFormatterExtension + * + * A virtual function reimplemented in all formatter extensions. It returns a + * short name of the extension that can be displayed in user interface. + * + * Return value: A (localized) string with name of the extension + */ +const gchar * +e_mail_formatter_extension_get_display_name (EMailFormatterExtension *extension) +{ + EMailFormatterExtensionInterface *interface; + + g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), NULL); + + interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension); + g_return_val_if_fail (interface->get_display_name != NULL, NULL); + + return interface->get_display_name (extension); +} + +/** + * e_mail_formatter_extension_get_description: + * @extension: an #EMailFormatterExtension + * + * A virtual function reimplemented in all formatter extensions. It returns a + * longer description of capabilities of the extension. + * + * Return value: A (localized) string with description of the extension. + */ +const gchar * +e_mail_formatter_extension_get_description (EMailFormatterExtension *extension) +{ + EMailFormatterExtensionInterface *interface; + + g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), NULL); + + interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension); + g_return_val_if_fail (interface->get_description != NULL, NULL); + + return interface->get_description (extension); +} diff --git a/em-format/e-mail-formatter-extension.h b/em-format/e-mail-formatter-extension.h new file mode 100644 index 0000000000..e2c4ee6cf1 --- /dev/null +++ b/em-format/e-mail-formatter-extension.h @@ -0,0 +1,106 @@ +/* + * e-mail-formatter-extension.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 + * + */ + +#ifndef E_MAIL_FORMATTER_EXTENSION_H +#define E_MAIL_FORMATTER_EXTENSION_H + +#include +#include +#include +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_FORMATTER_EXTENSION \ + (e_mail_formatter_extension_get_type ()) +#define E_MAIL_FORMATTER_EXTENSION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_FORMATTER_EXTENSION, EMailFormatterExtension)) +#define E_MAIL_FORMATTER_EXTENSION_INTERFACE(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_FORMATTER_EXTENSION, EMailFormatterExtensionInterface)) +#define E_IS_MAIL_FORMATTER_EXTENSION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_FORMATTER_EXTENSION)) +#define E_IS_MAIL_FORMATTER_EXTENSION_INTERFACE(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_FORMATTER_EXTENSION)) +#define E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE(obj) \ + (G_TYPE_INSTANCE_GET_INTERFACE \ + ((obj), E_TYPE_MAIL_FORMATTER_EXTENSION, EMailFormatterExtensionInterface)) + +#define EMF_EXTENSION_GET_FORMATTER(e) \ + E_MAIL_FORMATTER (e_extension_get_extensible (E_EXTENSION (e))) + +G_BEGIN_DECLS + +typedef struct _EMailFormatterExtension EMailFormatterExtension; +typedef struct _EMailFormatterExtensionInterface EMailFormatterExtensionInterface; + +struct _EMailFormatterExtensionInterface { + EMailExtensionInterface parent_interface; + + gboolean (*format) (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable); + + GtkWidget * (*get_widget) (EMailFormatterExtension *extension, + EMailPartList *context, + EMailPart *part, + GHashTable *params); + + const gchar * (*get_display_name) + (EMailFormatterExtension *extension); + + const gchar * (*get_description) + (EMailFormatterExtension *extension); + +}; + +GType e_mail_formatter_extension_get_type + (void); + +gboolean e_mail_formatter_extension_format + (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable); + +gboolean e_mail_formatter_extension_has_widget + (EMailFormatterExtension *extension); + +GtkWidget * e_mail_formatter_extension_get_widget + (EMailFormatterExtension *extension, + EMailPartList *context, + EMailPart *part, + GHashTable *params); + +const gchar * e_mail_formatter_extension_get_display_name + (EMailFormatterExtension *extension); + +const gchar * e_mail_formatter_extension_get_description + (EMailFormatterExtension *extension); + +G_END_DECLS + +#endif /* E_MAIL_FORMATTER_EXTENSION_H */ diff --git a/em-format/e-mail-formatter-headers.c b/em-format/e-mail-formatter-headers.c new file mode 100644 index 0000000000..24d27139b5 --- /dev/null +++ b/em-format/e-mail-formatter-headers.c @@ -0,0 +1,615 @@ +/* + * e-mail-formatter-headers.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +typedef struct _EMailFormatterHeaders { + GObject parent; +} EMailFormatterHeaders; + +typedef struct _EMailFormatterHeadersClass { + GObjectClass parent_class; +} EMailFormatterHeadersClass; + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.headers", NULL }; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterHeaders, + e_mail_formatter_headers, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)) + +static void +format_short_headers (EMailFormatter *formatter, + GString *buffer, + CamelMedium *part, + guint32 flags, + GCancellable *cancellable) +{ + const gchar *charset; + CamelContentType *ct; + const gchar *hdr_charset; + gchar *evolution_imagesdir; + gchar *subject = NULL; + struct _camel_header_address *addrs = NULL; + struct _camel_header_raw *header; + GString *from; + gboolean is_rtl; + + if (g_cancellable_is_cancelled (cancellable)) + return; + + ct = camel_mime_part_get_content_type ((CamelMimePart *) part); + charset = camel_content_type_param (ct, "charset"); + charset = camel_iconv_charset_name (charset); + hdr_charset = e_mail_formatter_get_charset (formatter) ? + e_mail_formatter_get_charset (formatter) : + e_mail_formatter_get_default_charset (formatter); + + evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL); + from = g_string_new (""); + + g_string_append_printf (buffer, + "", + flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "block" : "none"); + + header = ((CamelMimePart *) part)->headers; + while (header) { + if (!g_ascii_strcasecmp (header->name, "From")) { + GString *tmp; + if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) { + header = header->next; + continue; + } + tmp = g_string_new (""); + e_mail_formatter_format_address ( + formatter, tmp, addrs, header->name, FALSE, + !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE)); + + if (tmp->len) + g_string_printf (from, _("From: %s"), tmp->str); + g_string_free (tmp, TRUE); + + } else if (!g_ascii_strcasecmp (header->name, "Subject")) { + gchar *buf = NULL; + subject = camel_header_unfold (header->value); + buf = camel_header_decode_string (subject, hdr_charset); + g_free (subject); + subject = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0); + g_free (buf); + } + header = header->next; + } + + is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL; + if (is_rtl) { + g_string_append_printf ( + buffer, + "", + from->len ? "(" : "", from->str, from->len ? ")" : "", + subject ? subject : _("(no subject)")); + } else { + g_string_append_printf ( + buffer, + "", + subject ? subject : _("(no subject)"), + from->len ? "(" : "", from->str, from->len ? ")" : ""); + } + + g_string_append (buffer, "
%s%s%s %s
%s %s%s%s
"); + + g_free (subject); + if (addrs) + camel_header_address_list_clear (&addrs); + + g_string_free (from, TRUE); + g_free (evolution_imagesdir); +} + +static void +write_contact_picture (CamelMimePart *part, + gint size, + GString *buffer) +{ + gchar *b64, *content_type; + CamelDataWrapper *dw; + CamelContentType *ct; + GByteArray *ba; + + ba = NULL; + dw = camel_medium_get_content (CAMEL_MEDIUM (part)); + if (dw) { + ba = camel_data_wrapper_get_byte_array (dw); + } + + if (!ba || ba->len == 0) { + + if (camel_mime_part_get_filename (part)) { + + if (size >= 0) { + g_string_append_printf ( + buffer, + "", + size, camel_mime_part_get_filename (part)); + } else { + g_string_append_printf ( + buffer, + "", + camel_mime_part_get_filename (part)); + } + } + + return; + } + + b64 = g_base64_encode (ba->data, ba->len); + ct = camel_mime_part_get_content_type (part); + content_type = camel_content_type_simple (ct); + + if (size >= 0) { + g_string_append_printf ( + buffer, + "", + size, content_type, b64); + } else { + g_string_append_printf ( + buffer, + "", + content_type, b64); + } + + g_free (b64); + g_free (content_type); +} + +static CamelMimePart * +load_picture_from_file (const gchar *mime_type, + const gchar *filename, + GCancellable *cancellable) +{ + CamelMimePart *part; + CamelStream *stream; + CamelDataWrapper *dw; + gchar *basename; + + stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL); + if (stream == NULL) + return NULL; + + dw = camel_data_wrapper_new (); + camel_data_wrapper_construct_from_stream_sync ( + dw, stream, cancellable, NULL); + g_object_unref (stream); + if (mime_type) + camel_data_wrapper_set_mime_type (dw, mime_type); + part = camel_mime_part_new (); + camel_medium_set_content ((CamelMedium *) part, dw); + g_object_unref (dw); + basename = g_path_get_basename (filename); + camel_mime_part_set_filename (part, basename); + g_free (basename); + + return part; +} + +static void +format_full_headers (EMailFormatter *formatter, + GString *buffer, + CamelMedium *part, + guint32 flags, + GCancellable *cancellable) +{ + const gchar *charset; + CamelContentType *ct; + struct _camel_header_raw *header; + gboolean have_icon = FALSE; + const gchar *photo_name = NULL; + CamelInternetAddress *cia = NULL; + EShell *shell; + ESourceRegistry *registry; + gboolean face_decoded = FALSE, contact_has_photo = FALSE; + guchar *face_header_value = NULL; + gsize face_header_len = 0; + gchar *header_sender = NULL, *header_from = NULL, *name; + gboolean mail_from_delegate = FALSE; + const gchar *hdr_charset; + gchar *evolution_imagesdir; + + if (g_cancellable_is_cancelled (cancellable)) + return; + + shell = e_shell_get_default (); + registry = e_shell_get_registry (shell); + + ct = camel_mime_part_get_content_type ((CamelMimePart *) part); + charset = camel_content_type_param (ct, "charset"); + charset = camel_iconv_charset_name (charset); + hdr_charset = e_mail_formatter_get_charset (formatter) ? + e_mail_formatter_get_charset (formatter) : + e_mail_formatter_get_default_charset (formatter); + + evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL); + + g_string_append_printf (buffer, + "", + flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "none" : "block"); + + header = ((CamelMimePart *) part)->headers; + while (header) { + if (!g_ascii_strcasecmp (header->name, "Sender")) { + struct _camel_header_address *addrs; + GString *html; + + if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) + break; + + html = g_string_new(""); + name = e_mail_formatter_format_address ( + formatter, html, addrs, header->name, FALSE, + ~(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE)); + + header_sender = html->str; + camel_header_address_list_clear (&addrs); + + g_string_free (html, FALSE); + g_free (name); + } else if (!g_ascii_strcasecmp (header->name, "From")) { + struct _camel_header_address *addrs; + GString *html; + + if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) + break; + + html = g_string_new(""); + name = e_mail_formatter_format_address ( + formatter, html, addrs, header->name, FALSE, + !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE)); + + header_from = html->str; + camel_header_address_list_clear (&addrs); + + g_string_free (html, FALSE); + g_free (name); + } else if (!g_ascii_strcasecmp (header->name, "X-Evolution-Mail-From-Delegate")) { + mail_from_delegate = TRUE; + } + + header = header->next; + } + + if (header_sender && header_from && mail_from_delegate) { + gchar *bold_sender, *bold_from; + + g_string_append ( + buffer, + ""); + g_free (bold_sender); + g_free (bold_from); + } + + g_free (header_sender); + g_free (header_from); + + g_string_append (buffer, ""); + + if (photo_name) { + CamelMimePart *photopart; + gboolean only_local_photo; + + cia = camel_internet_address_new (); + camel_address_decode ((CamelAddress *) cia, (const gchar *) photo_name); + only_local_photo = e_mail_formatter_get_only_local_photos (formatter); + photopart = em_utils_contact_photo ( + registry, cia, only_local_photo); + + if (photopart) { + g_string_append (buffer, ""); + g_object_unref (photopart); + } + g_object_unref (cia); + } + + if (!contact_has_photo && face_decoded) { + CamelMimePart *part; + + part = camel_mime_part_new (); + camel_mime_part_set_content ( + (CamelMimePart *) part, + (const gchar *) face_header_value, + face_header_len, "image/png"); + + g_string_append (buffer, ""); + + g_object_unref (part); + g_free (face_header_value); + } + + if (have_icon) { + GtkIconInfo *icon_info; + CamelMimePart *iconpart = NULL; + + icon_info = gtk_icon_theme_lookup_icon ( + gtk_icon_theme_get_default (), + "evolution", 16, GTK_ICON_LOOKUP_NO_SVG); + if (icon_info != NULL) { + iconpart = load_picture_from_file ( + "image/png", gtk_icon_info_get_filename (icon_info), + cancellable); + gtk_icon_info_free (icon_info); + } + if (iconpart) { + g_string_append (buffer, ""); + + g_object_unref (iconpart); + } + } + + g_string_append (buffer, "
"); + if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL) + g_string_append ( + buffer, "
"); + else + g_string_append ( + buffer, ""); + bold_sender = g_strconcat ("", header_sender, "", NULL); + bold_from = g_strconcat ("", header_from, "", NULL); + /* Translators: This message suggests to the receipients + * that the sender of the mail is different from the one + * listed in From field. */ + g_string_append_printf ( + buffer, + _("This message was sent by %s on behalf of %s"), + bold_sender, bold_from); + g_string_append (buffer, "
\n"); + + g_free (evolution_imagesdir); + + /* dump selected headers */ + if (flags & E_MAIL_FORMATTER_MODE_ALL_HEADERS) { + header = ((CamelMimePart *) part)->headers; + while (header) { + e_mail_formatter_format_header ( + formatter, buffer, part, header, + E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS, charset); + header = header->next; + } + } else { + GList *link; + gint mailer_shown = FALSE; + + link = g_queue_peek_head_link ( + (GQueue *) e_mail_formatter_get_headers (formatter)); + + while (link != NULL) { + EMailFormatterHeader *h = link->data; + gint mailer, face; + + header = ((CamelMimePart *) part)->headers; + mailer = !g_ascii_strcasecmp (h->name, "X-Evolution-Mailer"); + face = !g_ascii_strcasecmp (h->name, "Face"); + + while (header) { + if (e_mail_formatter_get_show_sender_photo (formatter) && + !photo_name && !g_ascii_strcasecmp (header->name, "From")) + photo_name = header->value; + + if (!mailer_shown && mailer && ( + !g_ascii_strcasecmp (header->name, "X-Mailer") || + !g_ascii_strcasecmp (header->name, "User-Agent") || + !g_ascii_strcasecmp (header->name, "X-Newsreader") || + !g_ascii_strcasecmp (header->name, "X-MimeOLE"))) { + struct _camel_header_raw xmailer, *use_header = NULL; + + if (!g_ascii_strcasecmp (header->name, "X-MimeOLE")) { + for (use_header = header->next; use_header; use_header = use_header->next) { + if (!g_ascii_strcasecmp (use_header->name, "X-Mailer") || + !g_ascii_strcasecmp (use_header->name, "User-Agent") || + !g_ascii_strcasecmp (use_header->name, "X-Newsreader")) { + /* even we have X-MimeOLE, then use rather the standard one, when available */ + break; + } + } + } + + if (!use_header) + use_header = header; + + xmailer.name = (gchar *) "X-Evolution-Mailer"; + xmailer.value = use_header->value; + mailer_shown = TRUE; + + e_mail_formatter_format_header ( + formatter, buffer, part, + &xmailer, h->flags, charset); + if (strstr(use_header->value, "Evolution")) + have_icon = TRUE; + } else if (!face_decoded && face && !g_ascii_strcasecmp (header->name, "Face")) { + gchar *cp = header->value; + + /* Skip over spaces */ + while (*cp == ' ') + cp++; + + face_header_value = g_base64_decode ( + cp, &face_header_len); + face_header_value = g_realloc ( + face_header_value, + face_header_len + 1); + face_header_value[face_header_len] = 0; + face_decoded = TRUE; + /* Showing an encoded "Face" header makes little sense */ + } else if (!g_ascii_strcasecmp (header->name, h->name) && !face) { + e_mail_formatter_format_header ( + formatter, buffer, part, + header, h->flags, charset); + } + + header = header->next; + } + + link = g_list_next (link); + } + } + + g_string_append (buffer, "
"); + write_contact_picture (photopart, -1, buffer); + g_string_append (buffer, ""); + write_contact_picture (part, 48, buffer); + g_string_append (buffer, ""); + write_contact_picture (iconpart, 16, buffer); + g_string_append (buffer, "
"); +} + +static gboolean +emfe_headers_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + GString *buffer; + gint bg_color; + + if (g_cancellable_is_cancelled (cancellable)) + return FALSE; + + if (!part->part) + return FALSE; + + buffer = g_string_new (""); + + if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) { + GdkColor white = { 0, G_MAXUINT16, G_MAXUINT16, G_MAXUINT16 }; + bg_color = e_color_to_value (&white); + } else { + bg_color = e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_BODY)); + } + + g_string_append_printf ( + buffer, + "
" + "\n" + "
\n", + bg_color, + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, + E_MAIL_FORMATTER_COLOR_HEADER))); + + if (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE) { + g_string_append_printf (buffer, + "" + "", + EVOLUTION_IMAGESDIR, + (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED) ? + "plus.png" : "minus.png"); + + format_short_headers (formatter, buffer, + (CamelMedium *) part->part, context->flags, cancellable); + } + + format_full_headers (formatter, buffer, + (CamelMedium *) part->part, context->flags, cancellable); + + g_string_append (buffer, "
"); + + camel_stream_write_string (stream, buffer->str, cancellable, NULL); + + g_string_free (buffer, TRUE); + + return TRUE; +} + +static const gchar * +emfe_headers_get_display_name (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar * +emfe_headers_get_description (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar ** +emfe_headers_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_headers_class_init (EMailFormatterHeadersClass *klass) +{ + e_mail_formatter_headers_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_headers_format; + iface->get_display_name = emfe_headers_get_display_name; + iface->get_description = emfe_headers_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_headers_mime_types; +} + +static void +e_mail_formatter_headers_init (EMailFormatterHeaders *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-image.c b/em-format/e-mail-formatter-image.c new file mode 100644 index 0000000000..890e9f3dcc --- /dev/null +++ b/em-format/e-mail-formatter-image.c @@ -0,0 +1,191 @@ +/* + * image-any.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const gchar *formatter_mime_types[] = { "image/gif", "image/jpeg", + "image/png", "image/x-png", + "image/x-bmp", "image/bmp", + "image/svg", "image/x-cmu-raster", + "image/x-ico", + "image/x-portable-anymap", + "image/x-portable-bitmap", + "image/x-portable-graymap", + "image/x-portable-pixmap", + "image/x-xpixmap", + "image/jpg", "image/pjpeg", + "image/*", NULL }; + +typedef struct _EMailFormatterImage { + GObject parent; +} EMailFormatterImage; + +typedef struct _EMailFormatterImageClass { + GObjectClass parent_class; +} EMailFormatterImageClass; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterImage, + e_mail_formatter_image, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static gboolean +emfe_image_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + gchar *content; + CamelDataWrapper *dw; + GByteArray *ba; + CamelStream *raw_content; + + if (g_cancellable_is_cancelled (cancellable)) + return FALSE; + + dw = camel_medium_get_content (CAMEL_MEDIUM (part->part)); + g_return_val_if_fail (dw, FALSE); + + raw_content = camel_stream_mem_new (); + camel_data_wrapper_decode_to_stream_sync (dw, raw_content, cancellable, NULL); + ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (raw_content)); + + if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { + + if (!e_mail_formatter_get_animate_images (formatter)) { + + gchar *buff; + gsize len; + + e_mail_part_animation_extract_frame (ba, &buff, &len); + + camel_stream_write (stream, buff, len, cancellable, NULL); + + g_free (buff); + + } else { + + camel_stream_write ( + stream, (gchar *) ba->data, + ba->len, cancellable, NULL); + } + + } else { + + gchar *buffer; + + if (!e_mail_formatter_get_animate_images (formatter)) { + + gchar *buff; + gsize len; + + e_mail_part_animation_extract_frame (ba, &buff, &len); + + content = g_base64_encode ((guchar *) buff, len); + g_free (buff); + + } else { + content = g_base64_encode ((guchar *) ba->data, ba->len); + } + + /* The image is already base64-encrypted so we can directly + * paste it to the output */ + buffer = g_strdup_printf ( + "", + part->mime_type ? part->mime_type : "image/*", content); + + camel_stream_write_string (stream, buffer, cancellable, NULL); + g_free (buffer); + g_free (content); + } + + g_object_unref (raw_content); + + return TRUE; +} + +static const gchar * +emfe_image_get_display_name (EMailFormatterExtension *extension) +{ + return _("Regular Image"); +} + +static const gchar * +emfe_image_get_description (EMailFormatterExtension *extension) +{ + return _("Display part as an image"); +} + +static const gchar ** +emfe_image_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_image_class_init (EMailFormatterImageClass *klass) +{ + e_mail_formatter_image_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_image_format; + iface->get_display_name = emfe_image_get_display_name; + iface->get_description = emfe_image_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_image_mime_types; +} + +static void +e_mail_formatter_image_init (EMailFormatterImage *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-message-rfc822.c b/em-format/e-mail-formatter-message-rfc822.c new file mode 100644 index 0000000000..558579b00a --- /dev/null +++ b/em-format/e-mail-formatter-message-rfc822.c @@ -0,0 +1,276 @@ +/* + * e-mail-formatter-message-rfc822.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static const gchar* formatter_mime_types[] = { "message/rfc822", + "application/vnd.evolution.rfc822.end", + NULL }; + +typedef struct _EMailFormatterMessageRFC822 { + GObject parent; +} EMailFormatterMessageRFC822; + +typedef struct _EMailFormatterMessageRFC822Class { + GObjectClass parent_class; +} EMailFormatterMessageRFC822Class; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterMessageRFC822, + e_mail_formatter_message_rfc822, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static gboolean +emfe_message_rfc822_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + if (g_cancellable_is_cancelled (cancellable)) + return FALSE; + + if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { + GSList *iter; + gchar *header, *end; + + header = e_mail_formatter_get_html_header (formatter); + camel_stream_write_string (stream, header, cancellable, NULL); + g_free (header); + + /* Print content of the message normally */ + context->mode = E_MAIL_FORMATTER_MODE_NORMAL; + + iter = e_mail_part_list_get_iter (context->parts, part->id); + + end = g_strconcat (part->id, ".end", NULL); + for (iter = iter->next; iter; iter = g_slist_next (iter)) { + EMailPart * p = iter->data; + if (!p) + continue; + + /* Check for nested rfc822 messages */ + if (g_str_has_suffix (p->id, ".rfc822")) { + gchar *sub_end = g_strconcat (p->id, ".end", NULL); + + while (iter) { + p = iter->data; + if (!p) { + iter = iter->next; + continue; + } + + if (g_strcmp0 (p->id, sub_end) == 0) { + break; + } + + iter = iter->next; + } + g_free (sub_end); + continue; + } + if ((g_strcmp0 (p->id, end) == 0)) + break; + + if (p->is_hidden) + continue; + + e_mail_formatter_format_as ( + formatter, context, p, + stream, NULL, cancellable); + + } + + g_free (end); + + context->mode = E_MAIL_FORMATTER_MODE_RAW; + + camel_stream_write_string (stream, "", cancellable, NULL); + + } else if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) { + + GSList *iter; + gchar *end; + + /* Part is EMailPartAttachment */ + iter = e_mail_part_list_get_iter (context->parts, part->id); + iter = g_slist_next (iter); + + if (!iter || !iter->next || !iter->data) + return FALSE; + + part = iter->data; + end = g_strconcat (part->id, ".end", NULL); + + for (iter = iter->next; iter; iter = g_slist_next (iter)) { + EMailPart * p = iter->data; + if (!p) + continue; + + /* Skip attachment bar */ + if (g_str_has_suffix (part->id, ".attachment-bar")) + continue; + + /* Check for nested rfc822 messages */ + if (g_str_has_suffix (p->id, ".rfc822")) { + gchar *sub_end = g_strconcat (p->id, ".end", NULL); + + while (iter) { + p = iter->data; + if (!p) { + iter = iter->next; + continue; + } + + if (g_strcmp0 (p->id, sub_end) == 0) { + break; + } + + iter = iter->next; + } + g_free (sub_end); + continue; + } + + if ((g_strcmp0 (p->id, end) == 0)) + break; + + if (p->is_hidden) + continue; + + e_mail_formatter_format_as ( + formatter, context, p, + stream, NULL, cancellable); + } + + g_free (end); + + } else { + gchar *str; + gchar *uri; + + EMailPart *p; + GSList *iter; + + iter = e_mail_part_list_get_iter (context->parts, part->id); + if (!iter || !iter->next) + return FALSE; + + p = iter->data; + + uri = e_mail_part_build_uri (context->folder, context->message_uid, + "part_id", G_TYPE_STRING, p->id, + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, + "headers_collapsable", G_TYPE_INT, 0, + NULL); + + str = g_strdup_printf ( + "
\n" + "" + "
", + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_FRAME)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_BODY)), + part->id, uri, part->id); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + g_free (uri); + } + + return TRUE; +} + +static const gchar * +emfe_message_rfc822_get_display_name (EMailFormatterExtension *extension) +{ + return _("RFC822 message"); +} + +static const gchar * +emfe_message_rfc822_get_description (EMailFormatterExtension *extension) +{ + return _("Format part as an RFC822 message"); +} + +static const gchar ** +emfe_message_rfc822_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_message_rfc822_class_init (EMailFormatterMessageRFC822Class *klass) +{ + e_mail_formatter_message_rfc822_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_message_rfc822_format; + iface->get_display_name = emfe_message_rfc822_get_display_name; + iface->get_description = emfe_message_rfc822_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_message_rfc822_mime_types; +} + +static void +e_mail_formatter_message_rfc822_init (EMailFormatterMessageRFC822 *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-print-headers.c b/em-format/e-mail-formatter-print-headers.c new file mode 100644 index 0000000000..86fc85b063 --- /dev/null +++ b/em-format/e-mail-formatter-print-headers.c @@ -0,0 +1,258 @@ +/* + * e-mail-formatter-print-headers.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +typedef struct _EMailFormatterPrintHeaders { + GObject parent; +} EMailFormatterPrintHeaders; + +typedef struct _EMailFormatterPrintHeadersClass { + GObjectClass parent_class; +} EMailFormatterPrintHeadersClass; + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.headers", NULL }; + +static void e_mail_formatter_print_formatter_extension_interface_init + (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_print_mail_extension_interface_init + (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterPrintHeaders, + e_mail_formatter_print_headers, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_print_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_print_formatter_extension_interface_init)) + +static gboolean +emfpe_headers_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + struct _camel_header_raw raw_header; + GString *str, *tmp; + gchar *subject; + const gchar *buf; + GSList *parts_iter; + GList *iter; + gint attachments_count; + gchar *part_id_prefix; + const GQueue *headers; + + buf = camel_medium_get_header (CAMEL_MEDIUM (part->part), "subject"); + subject = camel_header_decode_string (buf, "UTF-8"); + str = g_string_new (""); + g_string_append_printf (str, "

%s

\n", subject); + g_free (subject); + + g_string_append ( + str, + "\n"); + + headers = e_mail_formatter_get_headers (formatter); + for (iter = headers->head; iter; iter = iter->next) { + + EMailFormatterHeader *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; + e_mail_formatter_format_header (formatter, str, + CAMEL_MEDIUM (part->part), &raw_header, + header->flags | E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, + "UTF-8"); + } else { + raw_header.value = g_strdup (camel_medium_get_header ( + CAMEL_MEDIUM (context->message), header->name)); + + if (raw_header.value && *raw_header.value) { + e_mail_formatter_format_header (formatter, str, + CAMEL_MEDIUM (part->part), &raw_header, + header->flags | E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, + "UTF-8"); + } + + if (raw_header.value) + g_free (raw_header.value); + } + } + + /* Get prefix of this PURI */ + part_id_prefix = g_strndup (part->id, g_strrstr (part->id, ".") - part->id); + + /* Add encryption/signature header */ + raw_header.name = _("Security"); + tmp = g_string_new (""); + /* Find first secured part. */ + for (parts_iter = context->parts; parts_iter; parts_iter = parts_iter->next) { + + EMailPart *mail_part = parts_iter->data; + if (mail_part == NULL) + continue; + + if (mail_part->validity_type == 0) + continue; + + if (!g_str_has_prefix (mail_part->id, part_id_prefix)) + continue; + + if ((mail_part->validity_type & E_MAIL_PART_VALIDITY_PGP) && + (mail_part->validity_type & E_MAIL_PART_VALIDITY_SIGNED)) { + g_string_append (tmp, _("GPG signed")); + } + if ((mail_part->validity_type & E_MAIL_PART_VALIDITY_PGP) && + (mail_part->validity_type & E_MAIL_PART_VALIDITY_ENCRYPTED)) { + if (tmp->len > 0) g_string_append (tmp, ", "); + g_string_append (tmp, _("GPG encrpyted")); + } + if ((mail_part->validity_type & E_MAIL_PART_VALIDITY_SMIME) && + (mail_part->validity_type & E_MAIL_PART_VALIDITY_SIGNED)) { + + if (tmp->len > 0) g_string_append (tmp, ", "); + g_string_append (tmp, _("S/MIME signed")); + } + if ((mail_part->validity_type & E_MAIL_PART_VALIDITY_SMIME) && + (mail_part->validity_type & E_MAIL_PART_VALIDITY_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; + e_mail_formatter_format_header ( + formatter, str, CAMEL_MEDIUM (part->part), &raw_header, + E_MAIL_FORMATTER_HEADER_FLAG_BOLD | + E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, "UTF-8"); + } + g_string_free (tmp, TRUE); + + /* Count attachments and display the number as a header */ + attachments_count = 0; + + for (parts_iter = context->parts; parts_iter; parts_iter = parts_iter->next) { + + EMailPart *mail_part = parts_iter->data; + if (!mail_part) + continue; + + if (!g_str_has_prefix (mail_part->id, part_id_prefix)) + continue; + + if (mail_part->is_attachment && !mail_part->cid && + !mail_part->is_hidden) { + attachments_count++; + } + } + + if (attachments_count > 0) { + raw_header.name = _("Attachments"); + raw_header.value = g_strdup_printf ("%d", attachments_count); + e_mail_formatter_format_header ( + formatter, str, CAMEL_MEDIUM (part->part), &raw_header, + E_MAIL_FORMATTER_HEADER_FLAG_BOLD | + E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, "UTF-8"); + g_free (raw_header.value); + } + + g_string_append (str, "
"); + + camel_stream_write_string (stream, str->str, cancellable, NULL); + g_string_free (str, TRUE); + g_free (part_id_prefix); + + return TRUE; +} + +static const gchar * +emfpe_headers_get_display_name (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar * +emfpe_headers_get_description (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar ** +emfpe_headers_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_print_headers_class_init (EMailFormatterPrintHeadersClass *klass) +{ + e_mail_formatter_print_headers_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_print_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfpe_headers_format; + iface->get_display_name = emfpe_headers_get_display_name; + iface->get_description = emfpe_headers_get_description; +} + +static void +e_mail_formatter_print_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfpe_headers_mime_types; +} + +static void +e_mail_formatter_print_headers_init (EMailFormatterPrintHeaders *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-print.c b/em-format/e-mail-formatter-print.c new file mode 100644 index 0000000000..a9109a647e --- /dev/null +++ b/em-format/e-mail-formatter-print.c @@ -0,0 +1,266 @@ +/* + * e-mail-formatter-print.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 + * + */ + +#include "e-mail-formatter-print.h" + +#include + +#include "e-mail-format-extensions.h" +#include "e-mail-part-attachment.h" +#include "e-mail-formatter-extension.h" +#include "e-mail-formatter-utils.h" +#include "e-mail-part.h" + +#include +#include + +static gpointer e_mail_formatter_print_parent_class = 0; + +static void +write_attachments_list (EMailFormatter *formatter, + EMailFormatterContext *context, + GSList *attachments, + CamelStream *stream, + GCancellable *cancellable) +{ + GString *str; + GSList *iter; + + if (!attachments) + return; + + str = g_string_new ( + "\n"); + g_string_append_printf (str, + "\n" + "\n", + _("Attachments"), _("Name"), _("Size")); + + for (iter = attachments; iter; iter = iter->next) { + EMailPartAttachment *part = iter->data; + EAttachment *attachment; + GFileInfo *fi; + gchar *name, *size; + + if (!part) + continue; + + attachment = part->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)); + } + + size = g_format_size (g_file_info_get_size (fi)); + + 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 +mail_formatter_print_run (EMailFormatter *formatter, + EMailFormatterContext *context, + CamelStream *stream, + GCancellable *cancellable) +{ + GSList *iter; + GSList *attachments; + + context->mode = E_MAIL_FORMATTER_MODE_PRINTING; + + camel_stream_write_string (stream, + "\n\n" + "\n\n" + "Evolution Mail Display\n" + "\n" + "\n" + "", + cancellable, NULL); + + attachments = NULL; + for (iter = context->parts; iter; iter = g_slist_next (iter)) { + + EMailPart *part; + gboolean ok; + + if (g_cancellable_is_cancelled (cancellable)) + break; + + part = iter->data; + if (!part) + continue; + + if (part->is_hidden && !part->is_error) { + if (g_str_has_suffix (part->id, ".rfc822")) { + iter = e_mail_formatter_find_rfc822_end_iter (iter); + } + + continue; + } + + if (!part->mime_type) + continue; + + if (part->is_attachment) { + if (part->cid != NULL) + continue; + + attachments = g_slist_append (attachments, part); + } + + ok = e_mail_formatter_format_as ( + formatter, context, part, stream, + part->mime_type, cancellable); + + /* If the written part was message/rfc822 then + * jump to the end of the message, because content + * of the whole message has been formatted by + * message_rfc822 formatter */ + if (ok && g_str_has_suffix (part->id, ".rfc822")) { + iter = e_mail_formatter_find_rfc822_end_iter (iter); + + continue; + } + } + + write_attachments_list (formatter, context, attachments, stream, cancellable); + + camel_stream_write_string (stream, "", cancellable, NULL); +} + +static void +mail_formatter_set_style (EMailFormatter *formatter, + GtkStyle *style, + GtkStateType state) +{ + EMailFormatterClass *formatter_class; + + /* White background */ + GdkColor body_color = { 0, G_MAXUINT16, G_MAXUINT16, G_MAXUINT16 }; + /* Black text */ + GdkColor text_color = { 0, 0, 0, 0 }; + + g_object_freeze_notify (G_OBJECT (formatter)); + + /* Set the other colors */ + formatter_class = E_MAIL_FORMATTER_CLASS (e_mail_formatter_print_parent_class); + formatter_class->set_style (formatter, style, state); + + e_mail_formatter_set_color ( + formatter, E_MAIL_FORMATTER_COLOR_FRAME, &body_color); + e_mail_formatter_set_color ( + formatter, E_MAIL_FORMATTER_COLOR_CONTENT, &body_color); + e_mail_formatter_set_color ( + formatter, E_MAIL_FORMATTER_COLOR_TEXT, &text_color); + + g_object_thaw_notify (G_OBJECT (formatter)); +} + +static void +e_mail_formatter_print_init (EMailFormatterPrint *formatter) +{ + +} + +static void +e_mail_formatter_print_finalize (GObject *object) +{ + /* Chain up to parent's finalize() */ + G_OBJECT_CLASS (e_mail_formatter_print_parent_class)->finalize (object); +} + +static void +e_mail_formatter_print_class_init (EMailFormatterPrintClass *klass) +{ + GObjectClass *object_class; + EMailFormatterClass *formatter_class; + + e_mail_formatter_print_parent_class = g_type_class_peek_parent (klass); + + formatter_class = E_MAIL_FORMATTER_CLASS (klass); + formatter_class->run = mail_formatter_print_run; + formatter_class->set_style = mail_formatter_set_style; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = e_mail_formatter_print_finalize; +} + +static void +e_mail_formatter_print_base_init (EMailFormatterPrintClass *klass) +{ + e_mail_formatter_print_internal_extensions_load ( + E_MAIL_EXTENSION_REGISTRY ( + E_MAIL_FORMATTER_CLASS (klass)->extension_registry)); + + E_MAIL_FORMATTER_CLASS (klass)->text_html_flags = + CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | + CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES; +} + +EMailFormatter * +e_mail_formatter_print_new (void) +{ + return g_object_new (E_TYPE_MAIL_FORMATTER_PRINT, NULL); +} + +GType +e_mail_formatter_print_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EMailFormatterClass), + (GBaseInitFunc) e_mail_formatter_print_base_init, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) e_mail_formatter_print_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMailFormatterPrint), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_mail_formatter_print_init, + NULL /* value_table */ + }; + + type = g_type_register_static (E_TYPE_MAIL_FORMATTER, + "EMailFormatterPrint", &type_info, 0); + } + + return type; +} + diff --git a/em-format/e-mail-formatter-print.h b/em-format/e-mail-formatter-print.h new file mode 100644 index 0000000000..1783cc068a --- /dev/null +++ b/em-format/e-mail-formatter-print.h @@ -0,0 +1,63 @@ +/* + * e-mail-formatter-print.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 + * + */ + +#ifndef E_MAIL_FORMATTER_PRINT_H_ +#define E_MAIL_FORMATTER_PRINT_H_ + +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_FORMATTER_PRINT \ + (e_mail_formatter_print_get_type ()) +#define E_MAIL_FORMATTER_PRINT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_FORMATTER_PRINT, EMailFormatterPrint)) +#define E_MAIL_FORMATTER_PRINT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_FORMATTER_PRINT, EMailFormatterPrintClass)) +#define E_IS_MAIL_FORMATTER_PRINT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_FORMATTER_PRINT)) +#define E_IS_MAIL_FORMATTER_PRINT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_FORMATTER_PRINT)) +#define E_MAIL_FORMATTER_PRINT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_FORMATTER_PRINT, EMailFormatterPrintClass)) + +G_BEGIN_DECLS; + +typedef struct _EMailFormatterPrint EMailFormatterPrint; +typedef struct _EMailFormatterPrintClass EMailFormatterPrintClass; +typedef struct _EMailFormatterPrintContext EMailFormatterPrintContext; + +struct _EMailFormatterPrint { + EMailFormatter parent; +}; + +struct _EMailFormatterPrintClass { + EMailFormatterClass parent_class; +}; + +GType e_mail_formatter_print_get_type (void); + +EMailFormatter * e_mail_formatter_print_new (void); + +G_END_DECLS + +#endif /* E_MAIL_FORMATTER_PRINT_H_ */ diff --git a/em-format/e-mail-formatter-quote-attachment.c b/em-format/e-mail-formatter-quote-attachment.c new file mode 100644 index 0000000000..590f23ee6d --- /dev/null +++ b/em-format/e-mail-formatter-quote-attachment.c @@ -0,0 +1,163 @@ +/* + * e-mail-formatter-qoute-attachment.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" +#include "e-mail-part-attachment.h" + +#include +#include +#include +#include + +#include +#include + +#define d(x) + +typedef struct _EMailFormatterQuoteAttachment { + GObject parent; +} EMailFormatterQuoteAttachment; + +typedef struct _EMailFormatterQuoteAttachmentClass { + GObjectClass parent_class; +} EMailFormatterQuoteAttachmentClass; + +static void e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterQuoteAttachment, + e_mail_formatter_quote_attachment, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_quote_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_quote_formatter_extension_interface_init) +) + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.attachment", + NULL }; + +static gboolean +emfqe_attachment_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + gchar *text, *html; + guint32 text_format_flags; + EMailPartAttachment *empa; + EMailPart *att_part; + GSList *iter; + + empa = E_MAIL_PART_ATTACHMENT (part); + + if (!empa->attachment_view_part_id) + return FALSE; + + iter = e_mail_part_list_get_iter ( + context->parts, empa->attachment_view_part_id); + if (!iter || !iter->data) + return FALSE; + + att_part = iter->data; + + camel_stream_write_string (stream, "

", cancellable, NULL); + + text_format_flags = + e_mail_formatter_get_text_format_flags (formatter); + text = e_mail_part_describe (part->part, + empa ? empa->snoop_mime_type : part->mime_type); + + html = camel_text_to_html ( + text, + text_format_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, + 0); + camel_stream_write_string (stream, html, cancellable, NULL); + camel_stream_write_string (stream, "
", cancellable, NULL); + g_free (html); + g_free (text); + + camel_stream_write_string (stream, + "\n" + "
\n", cancellable, NULL); + + e_mail_formatter_format_as ( + formatter, context, att_part, stream, NULL, cancellable); + + camel_stream_write_string (stream, + "
", + cancellable, NULL); + + return TRUE; +} + +static const gchar * +emfqe_attachment_get_display_name (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar * +emfqe_attachment_get_description (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar ** +emfqe_attachment_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_quote_attachment_class_init (EMailFormatterQuoteAttachmentClass *klass) +{ + e_mail_formatter_quote_attachment_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfqe_attachment_format; + iface->get_display_name = emfqe_attachment_get_display_name; + iface->get_description = emfqe_attachment_get_description; +} + +static void +e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfqe_attachment_mime_types; +} + +static void +e_mail_formatter_quote_attachment_init (EMailFormatterQuoteAttachment *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-quote-headers.c b/em-format/e-mail-formatter-quote-headers.c new file mode 100644 index 0000000000..f1b2b2e61f --- /dev/null +++ b/em-format/e-mail-formatter-quote-headers.c @@ -0,0 +1,162 @@ +/* + * e-mail-formatter-quote-headers.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +typedef struct _EMailFormatterQuoteHeaders { + GObject parent; +} EMailFormatterQuoteHeaders; + +typedef struct _EMailFormatterQuoteHeadersClass { + GObjectClass parent_class; +} EMailFormatterQuoteHeadersClass; + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.headers", NULL }; + +static void e_mail_formatter_quote_formatter_extension_interface_init + (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_quote_mail_extension_interface_init + (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterQuoteHeaders, + e_mail_formatter_quote_headers, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_quote_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_quote_formatter_extension_interface_init)) + +static gboolean +emqfe_headers_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + CamelContentType *ct; + const gchar *charset; + GList *iter; + GString *buffer; + const GQueue *default_headers; + + if (!part) + return FALSE; + + ct = camel_mime_part_get_content_type ((CamelMimePart *) part->part); + charset = camel_content_type_param (ct, "charset"); + charset = camel_iconv_charset_name (charset); + + buffer = g_string_new (""); + + /* dump selected headers */ + default_headers = e_mail_formatter_get_headers (formatter); + for (iter = default_headers->head; iter; iter = iter->next) { + struct _camel_header_raw *raw_header; + EMailFormatterHeader *h = iter->data; + guint32 flags; + + flags = h->flags & ~E_MAIL_FORMATTER_HEADER_FLAG_HTML; + flags |= E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE; + + for (raw_header = part->part->headers; raw_header; raw_header = raw_header->next) { + + if (g_strcmp0 (raw_header->name, h->name) == 0) { + + e_mail_formatter_format_header ( + formatter, buffer, (CamelMedium *) part->part, + raw_header, flags, charset); + + g_string_append (buffer, "
\n"); + break; + } + } + } + g_string_append (buffer, "
\n"); + + camel_stream_write_string (stream, buffer->str, cancellable, NULL); + + g_string_free (buffer, TRUE); + + return TRUE; +} + +static const gchar * +emqfe_headers_get_display_name (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar * +emqfe_headers_get_description (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar ** +emqfe_headers_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_quote_headers_class_init (EMailFormatterQuoteHeadersClass *klass) +{ + e_mail_formatter_quote_headers_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emqfe_headers_format; + iface->get_display_name = emqfe_headers_get_display_name; + iface->get_description = emqfe_headers_get_description; +} + +static void +e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emqfe_headers_mime_types; +} + +static void +e_mail_formatter_quote_headers_init (EMailFormatterQuoteHeaders *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-quote-message-rfc822.c b/em-format/e-mail-formatter-quote-message-rfc822.c new file mode 100644 index 0000000000..847686240f --- /dev/null +++ b/em-format/e-mail-formatter-quote-message-rfc822.c @@ -0,0 +1,188 @@ +/* + * e-mail-formatter-quote-message-rfc822.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static const gchar* formatter_mime_types[] = { "message/rfc822", + "application/vnd.evolution.rfc822.end", + NULL }; + +typedef struct _EMailFormatterQuoteMessageRFC822 { + GObject parent; +} EMailFormatterQuoteMessageRFC822; + +typedef struct _EMailFormatterQuoteMessageRFC822Class { + GObjectClass parent_class; +} EMailFormatterQuoteMessageRFC822Class; + +static void e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterQuoteMessageRFC822, + e_mail_formatter_quote_message_rfc822, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_quote_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_quote_formatter_extension_interface_init)); + +static gboolean +emfqe_message_rfc822_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + GSList *iter; + gchar *header, *end; + EMailFormatterQuoteContext *qc = (EMailFormatterQuoteContext *) context; + + if (g_cancellable_is_cancelled (cancellable)) + return FALSE; + + header = e_mail_formatter_get_html_header (formatter); + camel_stream_write_string (stream, header, cancellable, NULL); + g_free (header); + + iter = e_mail_part_list_get_iter (context->parts, part->id); + + end = g_strconcat (part->id, ".end", NULL); + for (iter = iter->next; iter; iter = iter->next) { + EMailPart * p = iter->data; + if (!p) + continue; + + /* Skip attachment bar */ + if (g_str_has_suffix (p->id, ".attachment-bar")) + continue; + + if (g_str_has_suffix (p->id, ".headers.")) { + if (qc->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS) { + e_mail_formatter_format_as ( + formatter, context, part, stream, + "application/vnd.evolution.headers", + cancellable); + } + + continue; + } + + /* Check for nested rfc822 messages */ + if (g_str_has_suffix (p->id, ".rfc822")) { + gchar *sub_end = g_strconcat (p->id, ".end", NULL); + + while (iter) { + p = iter->data; + if (!p) { + iter = iter->next; + continue; + } + + if (g_strcmp0 (p->id, sub_end) == 0) { + break; + } + + iter = iter->next; + } + g_free (sub_end); + continue; + } + if ((g_strcmp0 (p->id, end) == 0)) + break; + + if (p->is_hidden) + continue; + + e_mail_formatter_format_as ( + formatter, context, p, + stream, NULL, cancellable); + + } + + g_free (end); + + camel_stream_write_string (stream, "", cancellable, NULL); + + return TRUE; +} + +static const gchar * +emfqe_message_rfc822_get_display_name (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar * +emfqe_message_rfc822_get_description (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar ** +emfqe_message_rfc822_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_quote_message_rfc822_class_init (EMailFormatterQuoteMessageRFC822Class *klass) +{ + e_mail_formatter_quote_message_rfc822_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfqe_message_rfc822_format; + iface->get_display_name = emfqe_message_rfc822_get_display_name; + iface->get_description = emfqe_message_rfc822_get_description; +} + +static void +e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfqe_message_rfc822_mime_types; +} + +static void +e_mail_formatter_quote_message_rfc822_init (EMailFormatterQuoteMessageRFC822 *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-quote-text-enriched.c b/em-format/e-mail-formatter-quote-text-enriched.c new file mode 100644 index 0000000000..e48154edd8 --- /dev/null +++ b/em-format/e-mail-formatter-quote-text-enriched.c @@ -0,0 +1,141 @@ +/* + * e-mail-formatter-quote-text-enriched.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include + +#include +#include + +static const gchar *formatter_mime_types[] = { "text/enriched", + "text/richtext", + NULL }; + +typedef struct _EMailFormatterQuoteTextEnriched { + GObject parent; +} EMailFormatterQuoteTextEnriched; + +typedef struct _EMailFormatterQuoteTextEnrichedClass { + GObjectClass parent_class; +} EMailFormatterQuoteTextEnrichedClass; + +static void e_mail_formatter_quote_formatter_extension_interace_init + (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_quote_mail_extension_interface_init + (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterQuoteTextEnriched, + e_mail_formatter_quote_text_enriched, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_quote_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_quote_formatter_extension_interace_init)); + +static gboolean +emqfe_text_enriched_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + CamelStream *filtered_stream; + CamelMimeFilter *enriched; + guint32 camel_flags = 0; + + if (g_strcmp0 (part->mime_type, "text/richtext") == 0) { + camel_flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT; + camel_stream_write_string ( + stream, "\n\n", + cancellable, NULL); + } else { + camel_stream_write_string ( + stream, "\n\n", + cancellable, NULL); + } + + enriched = camel_mime_filter_enriched_new (camel_flags); + filtered_stream = camel_stream_filter_new (stream); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filtered_stream), enriched); + g_object_unref (enriched); + + camel_stream_write_string (stream, "


", cancellable, NULL); + e_mail_formatter_format_text (formatter, part, filtered_stream, cancellable); + camel_stream_flush (filtered_stream, cancellable, NULL); + g_object_unref (filtered_stream); + + return TRUE; +} + +static const gchar * +emqfe_text_enriched_get_display_name (EMailFormatterExtension *extension) +{ + return _("Richtext"); +} + +static const gchar * +emqfe_text_enriched_get_description (EMailFormatterExtension *extension) +{ + return _("Display part as enriched text"); +} + +static const gchar ** +emqfe_text_enriched_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_quote_text_enriched_class_init (EMailFormatterQuoteTextEnrichedClass *klass) +{ + e_mail_formatter_quote_text_enriched_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_quote_formatter_extension_interace_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emqfe_text_enriched_format; + iface->get_display_name = emqfe_text_enriched_get_display_name; + iface->get_description = emqfe_text_enriched_get_description; +} + +static void +e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emqfe_text_enriched_mime_types; +} + +static void +e_mail_formatter_quote_text_enriched_init (EMailFormatterQuoteTextEnriched *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-quote-text-html.c b/em-format/e-mail-formatter-quote-text-html.c new file mode 100644 index 0000000000..d4ef287878 --- /dev/null +++ b/em-format/e-mail-formatter-quote-text-html.c @@ -0,0 +1,143 @@ +/* + * e-mail-formatter-quote-text-html.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +static const gchar *formatter_mime_types[] = { "text/html", NULL }; + +typedef struct _EMailFormatterQuoteTextHTML { + GObject parent; +} EMailFormatterQuoteTextHTML; + +typedef struct _EMailFormatterQuoteTextHTMLClass { + GObjectClass parent_class; +} EMailFormatterQuoteTextHTMLClass; + +static void e_mail_formatter_quote_formatter_extension_interface_init + (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_quote_mail_extension_interface_init + (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterQuoteTextHTML, + e_mail_formatter_quote_text_html, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_quote_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_quote_formatter_extension_interface_init)); + +static gboolean +emqfe_text_html_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + EMailFormatterQuoteContext *qf_context; + + qf_context = (EMailFormatterQuoteContext *) context; + + camel_stream_write_string ( + stream, "\n\n", cancellable, NULL); + + if ((qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG) == 0) { + CamelMimeFilter *sig_strip; + CamelStream *filtered_stream; + + filtered_stream = camel_stream_filter_new (stream); + + sig_strip = e_mail_stripsig_filter_new (FALSE); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filtered_stream), sig_strip); + g_object_unref (sig_strip); + + e_mail_formatter_format_text ( + formatter, part, filtered_stream, cancellable); + camel_stream_flush (filtered_stream, cancellable, NULL); + g_object_unref (filtered_stream); + } else { + e_mail_formatter_format_text ( + formatter, part, stream, cancellable); + } + + return TRUE; +} + +static const gchar * +emqfe_text_html_get_display_name (EMailFormatterExtension *extension) +{ + return _("HTML"); +} + +static const gchar * +emqfe_text_html_get_description (EMailFormatterExtension *extension) +{ + return _("Format part as HTML"); +} + +static const gchar ** +emqfe_text_html_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_quote_text_html_class_init (EMailFormatterQuoteTextHTMLClass *klass) +{ + e_mail_formatter_quote_text_html_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emqfe_text_html_format; + iface->get_display_name = emqfe_text_html_get_display_name; + iface->get_description = emqfe_text_html_get_description; +} + +static void +e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emqfe_text_html_mime_types; +} + +static void +e_mail_formatter_quote_text_html_init (EMailFormatterQuoteTextHTML *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-quote-text-plain.c b/em-format/e-mail-formatter-quote-text-plain.c new file mode 100644 index 0000000000..062e945fea --- /dev/null +++ b/em-format/e-mail-formatter-quote-text-plain.c @@ -0,0 +1,162 @@ +/* + * e-mail-formatter-quote-text-plain.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include +#include + +#include +#include + +static const gchar *formatter_mime_types[] = { "text/plain", NULL }; + +typedef struct _EMailFormatterQuoteTextPlain { + GObject parent; +} EMailFormatterQuoteTextPlain; + +typedef struct _EMailFormatterQuoteTextPlainClass { + GObjectClass parent_class; +} EMailFormatterQuoteTextPlainClass; + +static void e_mail_formatter_quote_formatter_extension_interface_init + (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_quote_mail_extension_interface_init + (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterQuoteTextPlain, + e_mail_formatter_quote_text_plain, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_quote_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_quote_formatter_extension_interface_init)); + +static gboolean +emqfe_text_plain_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + CamelStream *filtered_stream; + CamelMimeFilter *html_filter; + CamelMimeFilter *sig_strip; + CamelContentType *type; + EMailFormatterQuoteContext *qf_context; + const gchar *format; + guint32 rgb = 0x737373, text_flags; + + if (!part->part) + return FALSE; + + qf_context = (EMailFormatterQuoteContext *) context; + + text_flags = CAMEL_MIME_FILTER_TOHTML_PRE | + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | + CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES; + + if (e_mail_formatter_get_mark_citations (formatter)) { + text_flags |= CAMEL_MIME_FILTER_TOHTML_MARK_CITATION; + } + + /* Check for RFC 2646 flowed text. */ + type = camel_mime_part_get_content_type (part->part); + if (camel_content_type_is(type, "text", "plain") + && (format = camel_content_type_param(type, "format")) + && !g_ascii_strcasecmp(format, "flowed")) + text_flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED; + + filtered_stream = camel_stream_filter_new (stream); + + if ((qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG) == 0) { + sig_strip = e_mail_stripsig_filter_new (TRUE); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filtered_stream), sig_strip); + g_object_unref (sig_strip); + } + + html_filter = camel_mime_filter_tohtml_new (text_flags, rgb); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filtered_stream), html_filter); + g_object_unref (html_filter); + + e_mail_formatter_format_text ( + formatter, part, filtered_stream, cancellable); + + camel_stream_flush (filtered_stream, cancellable, NULL); + g_object_unref (filtered_stream); + + return TRUE; +} + +static const gchar * +emqfe_text_plain_get_display_name (EMailFormatterExtension *extension) +{ + return _("Plain Text"); +} + +static const gchar * +emqfe_text_plain_get_description (EMailFormatterExtension *extension) +{ + return _("Format part as plain text"); +} + +static const gchar ** +emqfe_text_plain_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_quote_text_plain_class_init (EMailFormatterQuoteTextPlainClass *klass) +{ + e_mail_formatter_quote_text_plain_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emqfe_text_plain_format; + iface->get_display_name = emqfe_text_plain_get_display_name; + iface->get_description = emqfe_text_plain_get_description; +} + +static void +e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emqfe_text_plain_mime_types; +} + +static void +e_mail_formatter_quote_text_plain_init (EMailFormatterQuoteTextPlain *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-quote.c b/em-format/e-mail-formatter-quote.c new file mode 100644 index 0000000000..e4a221e3d1 --- /dev/null +++ b/em-format/e-mail-formatter-quote.c @@ -0,0 +1,224 @@ +/* + * e-mail-formatter-quote.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 + * + */ + +#include "e-mail-formatter-quote.h" + +#include + +#include "e-mail-formatter-extension.h" +#include "e-mail-format-extensions.h" +#include "e-mail-part.h" +#include "e-mail-part-attachment.h" +#include "e-mail-part-utils.h" + +#include +#include +#include + +struct _EMailFormatterQuotePrivate { + gchar *credits; + EMailFormatterQuoteFlags flags; +}; + +#define E_MAIL_FORMATTER_QUOTE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuotePrivate)) + +static gpointer e_mail_formatter_quote_parent_class = 0; + +static EMailFormatterContext * +mail_formatter_quote_create_context (EMailFormatter *formatter) +{ + return g_malloc0 (sizeof (EMailFormatterQuoteContext)); +} + +static void +mail_formatter_quote_free_context (EMailFormatter *formatter, + EMailFormatterContext *context) +{ + g_free ((EMailFormatterQuoteContext *) context); +} + +static void +mail_formatter_quote_run (EMailFormatter *formatter, + EMailFormatterContext *context, + CamelStream *stream, + GCancellable *cancellable) +{ + EMailFormatterQuote *qf; + EMailFormatterQuoteContext *qf_context; + GSettings *settings; + GSList *iter; + + if (g_cancellable_is_cancelled (cancellable)) + return; + + qf = E_MAIL_FORMATTER_QUOTE (formatter); + + qf_context = (EMailFormatterQuoteContext *) context; + qf_context->qf_flags = qf->priv->flags; + + g_seekable_seek ( + G_SEEKABLE (stream), + 0, G_SEEK_SET, NULL, NULL); + + settings = g_settings_new ("org.gnome.evolution.mail"); + if (g_settings_get_boolean ( + settings, "composer-top-signature")) + camel_stream_write_string ( + stream, "
\n", cancellable, NULL); + g_object_unref (settings); + + if (qf->priv->credits && *qf->priv->credits) { + gchar *credits = g_strdup_printf ("%s
", qf->priv->credits); + camel_stream_write_string (stream, credits, cancellable, NULL); + g_free (credits); + } else { + camel_stream_write_string (stream, "
", cancellable, NULL); + } + + if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) { + camel_stream_write_string (stream, + "\n" + "
\n", cancellable, NULL); + } + + for (iter = context->parts; iter; iter = iter->next) { + EMailPart *part = iter->data; + + if (!part) + continue; + + if (g_str_has_suffix (part->id, ".rfc822")) { + gchar *end = g_strconcat (part->id, ".end", NULL); + + while (iter) { + EMailPart *p = iter->data; + if (!p) { + iter = iter->next; + continue; + } + + if (g_strcmp0 (p->id, end) == 0) + break; + + iter = iter->next; + } + g_free (end); + continue; + } + + if (part->is_hidden) + continue; + + e_mail_formatter_format_as ( + formatter, context, part, stream, + part->mime_type, cancellable); + } + + if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) { + camel_stream_write_string ( + stream, "
", + cancellable, NULL); + } +} + +static void +e_mail_formatter_quote_init (EMailFormatterQuote *formatter) +{ + formatter->priv = E_MAIL_FORMATTER_QUOTE_GET_PRIVATE (formatter); +} + +static void +e_mail_formatter_quote_finalize (GObject *object) +{ + /* Chain up to parent's finalize() */ + G_OBJECT_CLASS (e_mail_formatter_quote_parent_class)->finalize (object); +} + +static void +e_mail_formatter_quote_base_init (EMailFormatterQuoteClass *klass) +{ + e_mail_formatter_quote_internal_extensions_load ( + E_MAIL_EXTENSION_REGISTRY ( + E_MAIL_FORMATTER_CLASS (klass)->extension_registry)); + + E_MAIL_FORMATTER_CLASS (klass)->text_html_flags = + CAMEL_MIME_FILTER_TOHTML_PRE | + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | + CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES; +} + +static void +e_mail_formatter_quote_class_init (EMailFormatterQuoteClass *klass) +{ + GObjectClass *object_class; + EMailFormatterClass *formatter_class; + + e_mail_formatter_quote_parent_class = g_type_class_peek_parent (klass); + g_type_class_add_private (klass, sizeof (EMailFormatterQuotePrivate)); + + formatter_class = E_MAIL_FORMATTER_CLASS (klass); + formatter_class->run = mail_formatter_quote_run; + formatter_class->create_context = mail_formatter_quote_create_context; + formatter_class->free_context = mail_formatter_quote_free_context; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = e_mail_formatter_quote_finalize; +} + +GType +e_mail_formatter_quote_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EMailFormatterClass), + (GBaseInitFunc) e_mail_formatter_quote_base_init, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) e_mail_formatter_quote_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMailFormatterQuote), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_mail_formatter_quote_init, + NULL /* value_table */ + }; + + type = g_type_register_static (E_TYPE_MAIL_FORMATTER, + "EMailFormatterQuote", &type_info, 0); + } + + return type; +} + +EMailFormatter * +e_mail_formatter_quote_new (const gchar *credits, + EMailFormatterQuoteFlags flags) +{ + EMailFormatterQuote *formatter; + formatter = g_object_new (E_TYPE_MAIL_FORMATTER_QUOTE, NULL); + + formatter->priv->credits = g_strdup (credits); + formatter->priv->flags = flags; + + return (EMailFormatter *) formatter; +} diff --git a/em-format/e-mail-formatter-quote.h b/em-format/e-mail-formatter-quote.h new file mode 100644 index 0000000000..fa6730b964 --- /dev/null +++ b/em-format/e-mail-formatter-quote.h @@ -0,0 +1,79 @@ +/* + * e-mail-formatter-quote.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 + * + */ + +#ifndef E_MAIL_FORMATTER_QUOTE_H_ +#define E_MAIL_FORMATTER_QUOTE_H_ + +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_FORMATTER_QUOTE \ + (e_mail_formatter_quote_get_type ()) +#define E_MAIL_FORMATTER_QUOTE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuote)) +#define E_MAIL_FORMATTER_QUOTE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuoteClass)) +#define E_IS_MAIL_FORMATTER_QUOTE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_FORMATTER_QUOTE)) +#define E_IS_MAIL_FORMATTER_QUOTE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_FORMATTER_QUOTE)) +#define E_MAIL_FORMATTER_QUOTE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuoteClass)) + +G_BEGIN_DECLS; + +typedef struct _EMailFormatterQuote EMailFormatterQuote; +typedef struct _EMailFormatterQuoteClass EMailFormatterQuoteClass; +typedef struct _EMailFormatterQuotePrivate EMailFormatterQuotePrivate; +typedef struct _EMailFormatterQuoteContext EMailFormatterQuoteContext; + +typedef enum { + E_MAIL_FORMATTER_QUOTE_FLAG_CITE = 1 << 0, + E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS = 1 << 1, + E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG = 1 << 2 /* do not strip signature */ +} EMailFormatterQuoteFlags; + +struct _EMailFormatterQuoteContext { + EMailFormatterContext parent; + + guint32 qf_flags; +}; + +struct _EMailFormatterQuote { + EMailFormatter parent; + + EMailFormatterQuotePrivate *priv; +}; + +struct _EMailFormatterQuoteClass { + EMailFormatterClass parent_class; +}; + +GType e_mail_formatter_quote_get_type (void); + +EMailFormatter * e_mail_formatter_quote_new (const gchar *credits, + EMailFormatterQuoteFlags flags); + +G_END_DECLS + +#endif /* E_MAIL_FORMATTER_QUOTE_H_ */ diff --git a/em-format/e-mail-formatter-secure-button.c b/em-format/e-mail-formatter-secure-button.c new file mode 100644 index 0000000000..05319ef7fc --- /dev/null +++ b/em-format/e-mail-formatter-secure-button.c @@ -0,0 +1,472 @@ +/* + * evolution-secure-button.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "e-mail-format-extensions.h" + +#include + +#include +#include +#include + +#if defined (HAVE_NSS) && defined (ENABLE_SMIME) +#include "certificate-viewer.h" +#include "e-cert-db.h" +#endif + +#include + +typedef struct _EMailFormatterSecureButton { + GObject parent; +} EMailFormatterSecureButton; + +typedef struct _EMailFormatterSecureButtonClass { + GObjectClass parent_class; +} EMailFormatterSecureButtonClass; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterSecureButton, + e_mail_formatter_secure_button, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.widget.secure-button", NULL }; + +static const struct { + const gchar *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 gchar *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 GdkRGBA smime_sign_colour[5] = { + { 0 }, { 0.53, 0.73, 0.53, 1 }, { 0.73, 0.53, 0.53, 1 }, { 0.91, 0.82, 0.13, 1 }, { 0 }, +}; + +static gboolean +emfe_secure_button_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + gchar *str; + + if ((context->mode != E_MAIL_FORMATTER_MODE_NORMAL) && + (context->mode != E_MAIL_FORMATTER_MODE_RAW)) + return FALSE; + + str = g_strdup_printf ( + "", + part->id, part->id); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + return TRUE; +} + +#if defined (HAVE_NSS) && defined (ENABLE_SMIME) +static void +viewcert_clicked (GtkWidget *button, + GtkWidget *parent) +{ + CamelCipherCertInfo *info = g_object_get_data((GObject *) button, "e-cert-info"); + ECert *ec = NULL; + + if (info->cert_data) + ec = e_cert_new (CERT_DupCertificate (info->cert_data)); + + 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 (gtk_widget_destroy), NULL); + + if (w && parent) + gtk_window_set_transient_for ( + (GtkWindow *) w, (GtkWindow *) parent); + + 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 +info_response (GtkWidget *widget, + guint button, + gpointer user_data) +{ + gtk_widget_destroy (widget); +} + +static void +add_cert_table (GtkWidget *grid, + GQueue *certlist, + gpointer user_data) +{ + GList *head, *link; + GtkTable *table; + gint n = 0; + + table = (GtkTable *) gtk_table_new (certlist->length, 2, FALSE); + + head = g_queue_peek_head_link (certlist); + + for (link = head; link != NULL; link = g_list_next (link)) { + CamelCipherCertInfo *info = link->data; + gchar *la = NULL; + const gchar *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) && defined (ENABLE_SMIME) + 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) && defined (ENABLE_SMIME) + 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 (viewcert_clicked), grid); + + if (info->cert_data) + ec = e_cert_new (CERT_DupCertificate (info->cert_data)); + + 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++; + } + } + + gtk_container_add (GTK_CONTAINER (grid), GTK_WIDGET (table)); +} + +static void +format_cert_infos (GQueue *cert_infos, + GString *output_buffer) +{ + GQueue valid = G_QUEUE_INIT; + GList *head, *link; + + head = g_queue_peek_head_link (cert_infos); + + /* Make sure we have a valid CamelCipherCertInfo before + * appending anything to the output buffer, so we don't + * end up with "()". */ + for (link = head; link != NULL; link = g_list_next (link)) { + CamelCipherCertInfo *cinfo = link->data; + + if ((cinfo->name != NULL && *cinfo->name != '\0') || + (cinfo->email != NULL && *cinfo->email != '\0')) { + g_queue_push_tail (&valid, cinfo); + } + } + + if (g_queue_is_empty (&valid)) + return; + + g_string_append (output_buffer, " ("); + + while (!g_queue_is_empty (&valid)) { + CamelCipherCertInfo *cinfo; + + cinfo = g_queue_pop_head (&valid); + + if (cinfo->name != NULL && *cinfo->name != '\0') { + g_string_append (output_buffer, cinfo->name); + + if (cinfo->email != NULL && *cinfo->email != '\0') { + g_string_append (output_buffer, " <"); + g_string_append (output_buffer, cinfo->email); + g_string_append (output_buffer, ">"); + } + + } else if (cinfo->email != NULL && *cinfo->email != '\0') { + g_string_append (output_buffer, cinfo->email); + } + + if (!g_queue_is_empty (&valid)) + g_string_append (output_buffer, ", "); + } + + g_string_append_c (output_buffer, ')'); +} + +static void +secure_button_clicked_cb (GtkWidget *widget, + EMailPart *part) +{ + GtkBuilder *builder; + GtkWidget *grid, *w; + GtkWidget *dialog; + + builder = gtk_builder_new (); + e_load_ui_builder_definition (builder, "mail-dialogs.ui"); + + dialog = e_builder_get_widget(builder, "message_security_dialog"); + + grid = e_builder_get_widget(builder, "signature_grid"); + w = gtk_label_new (_(smime_sign_table[part->validity->sign.status].description)); + gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5); + gtk_label_set_line_wrap ((GtkLabel *) w, TRUE); + gtk_container_add (GTK_CONTAINER (grid), w); + if (part->validity->sign.description) { + GtkTextBuffer *buffer; + + buffer = gtk_text_buffer_new (NULL); + gtk_text_buffer_set_text ( + buffer, part->validity->sign.description, + strlen (part->validity->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, + "expand", TRUE, + "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_container_add (GTK_CONTAINER (grid), w); + } + + if (!g_queue_is_empty (&part->validity->sign.signers)) + add_cert_table ( + grid, &part->validity->sign.signers, NULL); + + gtk_widget_show_all (grid); + + grid = e_builder_get_widget(builder, "encryption_grid"); + w = gtk_label_new (_(smime_encrypt_table[part->validity->encrypt.status].description)); + gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5); + gtk_label_set_line_wrap ((GtkLabel *) w, TRUE); + gtk_container_add (GTK_CONTAINER (grid), w); + if (part->validity->encrypt.description) { + GtkTextBuffer *buffer; + + buffer = gtk_text_buffer_new (NULL); + gtk_text_buffer_set_text ( + buffer, part->validity->encrypt.description, + strlen (part->validity->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, + "expand", TRUE, + "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_container_add (GTK_CONTAINER (grid), w); + } + + if (!g_queue_is_empty (&part->validity->encrypt.encrypters)) + add_cert_table (grid, &part->validity->encrypt.encrypters, NULL); + + gtk_widget_show_all (grid); + + g_object_unref (builder); + + g_signal_connect ( + dialog, "response", + G_CALLBACK (info_response), NULL); + + gtk_widget_show (dialog); +} + +static GtkWidget * +emfe_secure_button_get_widget (EMailFormatterExtension *extension, + EMailPartList *context, + EMailPart *part, + GHashTable *params) +{ + GtkWidget *box, *button, *layout, *widget; + const gchar *icon_name; + gchar *description; + GString *buffer; + buffer = g_string_new (""); + + if (part->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) { + const gchar *desc; + gint status; + + status = part->validity->sign.status; + desc = smime_sign_table[status].shortdesc; + + g_string_append (buffer, gettext (desc)); + + format_cert_infos (&part->validity->sign.signers, buffer); + } + + if (part->validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) { + const gchar *desc; + gint status; + + if (part->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) + g_string_append (buffer, "\n"); + + status = part->validity->encrypt.status; + desc = smime_encrypt_table[status].shortdesc; + g_string_append (buffer, gettext (desc)); + } + + description = g_string_free (buffer, FALSE); + + /* FIXME: need to have it based on encryption and signing too */ + if (part->validity->sign.status != 0) + icon_name = smime_sign_table[part->validity->sign.status].icon; + else + icon_name = smime_encrypt_table[part->validity->encrypt.status].icon; + + box = gtk_event_box_new (); + if (part->validity->sign.status != 0) + gtk_widget_override_background_color (box, GTK_STATE_FLAG_NORMAL, + &smime_sign_colour[part->validity->sign.status]); + + layout = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); + gtk_container_add (GTK_CONTAINER (box), layout); + + button = gtk_button_new (); + gtk_box_pack_start (GTK_BOX (layout), button, FALSE, FALSE, 0); + g_signal_connect (button, "clicked", + G_CALLBACK (secure_button_clicked_cb), part); + + widget = gtk_image_new_from_icon_name ( + icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_button_set_image (GTK_BUTTON (button), widget); + + widget = gtk_label_new (description); + gtk_box_pack_start (GTK_BOX (layout), widget, FALSE, FALSE, 0); + + gtk_widget_show_all (box); + + g_free (description); + return box; +} + +static const gchar * +emfe_secure_button_get_display_name (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar * +emfe_secure_button_get_description (EMailFormatterExtension *extension) +{ + return NULL; +} + +static const gchar ** +emfe_secure_button_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_secure_button_class_init (EMailFormatterSecureButtonClass *klass) +{ + e_mail_formatter_secure_button_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_secure_button_format; + iface->get_widget = emfe_secure_button_get_widget; + iface->get_display_name = emfe_secure_button_get_display_name; + iface->get_description = emfe_secure_button_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_secure_button_mime_types; +} + +static void +e_mail_formatter_secure_button_init (EMailFormatterSecureButton *extension) +{ + +} diff --git a/em-format/e-mail-formatter-source.c b/em-format/e-mail-formatter-source.c new file mode 100644 index 0000000000..92c3a925f1 --- /dev/null +++ b/em-format/e-mail-formatter-source.c @@ -0,0 +1,178 @@ +/* + * evolution-source.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include + +#include +#include + +typedef struct _EMailFormatterSource { + GObject parent; +} EMailFormatterSource; + +typedef struct _EMailFormatterSourceClass { + GObjectClass parent_class; +} EMailFormatterSourceClass; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterSource, + e_mail_formatter_source, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init) +) + +static const gchar *formatter_mime_types[] = { "application/vnd.evolution.source", NULL }; + +static gboolean +emfe_source_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + GString *buffer; + CamelStream *filtered_stream; + CamelMimeFilter *filter; + CamelDataWrapper *dw = (CamelDataWrapper *) part->part; + + filtered_stream = camel_stream_filter_new (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 ( + CAMEL_STREAM_FILTER (filtered_stream), filter); + g_object_unref (filter); + + buffer = g_string_new (""); + + if (CAMEL_IS_MIME_MESSAGE (part->part)) { + g_string_append_printf ( + buffer, + "
", + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_BODY)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_TEXT))); + } else { + g_string_append_printf ( + buffer, + "
" + "
\n", + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_FRAME)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_BODY)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_TEXT))); + } + + camel_stream_write_string ( + stream, buffer->str, cancellable, NULL); + camel_stream_write_string ( + stream, "", cancellable, NULL); + + camel_data_wrapper_write_to_stream_sync (dw, filtered_stream, + cancellable, NULL); + camel_stream_flush (filtered_stream, cancellable, NULL); + g_object_unref (filtered_stream); + + camel_stream_write_string ( + stream, "", cancellable, NULL); + + g_string_free (buffer, TRUE); + + if (CAMEL_IS_MIME_MESSAGE (part->part)) { + camel_stream_write_string (stream, "
", cancellable, NULL); + } else { + camel_stream_write_string (stream, "
", cancellable, NULL); + } + + return TRUE; +} + +static const gchar * +emfe_source_get_display_name (EMailFormatterExtension *extension) +{ + return _("Source"); +} + +static const gchar * +emfe_source_get_description (EMailFormatterExtension *extension) +{ + return _("Display source of a MIME part"); +} + +static const gchar ** +emfe_source_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_source_class_init (EMailFormatterSourceClass *klass) +{ + e_mail_formatter_source_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_source_format; + iface->get_display_name = emfe_source_get_display_name; + iface->get_description = emfe_source_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_source_mime_types; +} + +static void +e_mail_formatter_source_init (EMailFormatterSource *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-text-enriched.c b/em-format/e-mail-formatter-text-enriched.c new file mode 100644 index 0000000000..fce7b317e2 --- /dev/null +++ b/em-format/e-mail-formatter-text-enriched.c @@ -0,0 +1,154 @@ +/* + * e-mail-formatter-text-enriched.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include + +#include +#include + +static const gchar *formatter_mime_types[] = { "text/enriched", + "text/richtext", + NULL }; + +typedef struct _EMailFormatterTextEnriched { + GObject parent; +} EMailFormatterTextEnriched; + +typedef struct _EMailFormatterTextEnrichedClass { + GObjectClass parent_class; +} EMailFormatterTextEnrichedClass; + +static void e_mail_formatter_formatter_extension_interace_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterTextEnriched, + e_mail_formatter_text_enriched, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interace_init)); + +static gboolean +emfe_text_enriched_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + CamelStream *filtered_stream; + CamelMimeFilter *enriched; + guint32 filter_flags = 0; + GString *buffer; + + if (g_cancellable_is_cancelled (cancellable)) + return FALSE; + + if (!g_strcmp0(part->mime_type, "text/richtext")) { + filter_flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT; + } + + enriched = camel_mime_filter_enriched_new (filter_flags); + filtered_stream = camel_stream_filter_new (stream); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filtered_stream), enriched); + g_object_unref (enriched); + + buffer = g_string_new (""); + + g_string_append_printf (buffer, + "
" + "
\n", + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color (formatter, E_MAIL_FORMATTER_COLOR_FRAME)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color (formatter, E_MAIL_FORMATTER_COLOR_CONTENT)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color (formatter, E_MAIL_FORMATTER_COLOR_TEXT))); + + camel_stream_write_string (stream, buffer->str, cancellable, NULL); + g_string_free (buffer, TRUE); + + e_mail_formatter_format_text ( + formatter, part, filtered_stream, cancellable); + camel_stream_flush (filtered_stream, cancellable, NULL); + g_object_unref (filtered_stream); + + camel_stream_write_string (stream, "
", cancellable, NULL); + + return TRUE; +} + +static const gchar * +emfe_text_enriched_get_display_name (EMailFormatterExtension *extension) +{ + return _("Richtext"); +} + +static const gchar * +emfe_text_enriched_get_description (EMailFormatterExtension *extension) +{ + return _("Display part as enriched text"); +} + +static const gchar ** +emfe_text_enriched_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_text_enriched_class_init (EMailFormatterTextEnrichedClass *klass) +{ + e_mail_formatter_text_enriched_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interace_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_text_enriched_format; + iface->get_display_name = emfe_text_enriched_get_display_name; + iface->get_description = emfe_text_enriched_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_text_enriched_mime_types; +} + +static void +e_mail_formatter_text_enriched_init (EMailFormatterTextEnriched *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-text-html.c b/em-format/e-mail-formatter-text-html.c new file mode 100644 index 0000000000..28fb2644de --- /dev/null +++ b/em-format/e-mail-formatter-text-html.c @@ -0,0 +1,376 @@ +/* + * e-mail-formatter-text-html.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static const gchar *formatter_mime_types[] = { "text/html", NULL }; + +typedef struct _EMailFormatterTextHTML { + GObject parent; +} EMailFormatterTextHTML; + +typedef struct _EMailFormatterTextHTMLClass { + GObjectClass parent_class; +} EMailFormatterTextHTMLClass; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterTextHTML, + e_mail_formatter_text_html, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static gchar * +get_tag (const gchar *utf8_string, + const gchar *tag_name, + gchar *opening, + gchar *closing) +{ + gchar *t; + gunichar c; + gboolean has_end; + + t = g_utf8_find_prev_char (utf8_string, closing); + while (t != opening) { + + c = g_utf8_get_char (t); + if (!g_unichar_isspace (c)) + break; + } + + /* Not a pair tag */ + if (c == '/') + return g_strndup (opening, closing - opening + 1); + + t = closing; + while (t) { + c = g_utf8_get_char (t); + if (c == '<') + break; + + t = g_utf8_find_next_char (t, NULL); + } + + do { + c = g_utf8_get_char (t); + + if (c == '/') { + has_end = TRUE; + break; + } + + if (c == '>') { + has_end = FALSE; + break; + } + + t = g_utf8_find_next_char (t, NULL); + + } while (t); + + /* Broken HTML? */ + if (!has_end) + return g_strndup (opening, closing - opening + 1); + + do { + c = g_utf8_get_char (t); + if ((c != ' ') && (c != '/')) + break; + + t = g_utf8_find_next_char (t, NULL); + } while (t); + + /* tag_name is always ASCII */ + if (g_ascii_strncasecmp (t, tag_name, strlen (tag_name)) == 0) { + + closing = g_utf8_strchr (t, -1, '>'); + + return g_strndup (opening, closing - opening + 1); + } + + /* Broken HTML? */ + return g_strndup (opening, closing - opening + 1); +} + +static gboolean +emfe_text_html_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + if (g_cancellable_is_cancelled (cancellable)) + return FALSE; + + if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { + /* FORMATTER FIXME: Shouldn't we have some extra method for + * BASE64 and QP decoding?? */ + e_mail_formatter_format_text (formatter, part, stream, cancellable); + + } else if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) { + GString *string; + GByteArray *ba; + gchar *pos; + GList *tags, *iter; + gboolean valid; + gchar *tag; + const gchar *document_end; + gint length; + gint i; + CamelStream *decoded_stream; + + decoded_stream = camel_stream_mem_new (); + /* FORMATTER FIXME: See above */ + e_mail_formatter_format_text (formatter, part, decoded_stream, cancellable); + g_seekable_seek (G_SEEKABLE (decoded_stream), 0, G_SEEK_SET, cancellable, NULL); + + ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (decoded_stream)); + string = g_string_new_len ((gchar *) ba->data, ba->len); + + g_object_unref (decoded_stream); + + tags = NULL; + pos = string->str; + valid = FALSE; + + if (!g_utf8_validate (string->str, -1, NULL)) { + /* FIXME - What do we do if the string is not UTF-8 valid? */ + } + + do { + gchar *tmp; + gchar *closing; + gchar *opening; + + tmp = g_utf8_find_next_char (pos, NULL); + pos = g_utf8_strchr (tmp, -1, '<'); + if (!pos) + break; + + opening = pos; + closing = g_utf8_strchr (pos, -1, '>'); + + /* Find where the actual tag name begins */ + tag = g_utf8_find_next_char (pos, NULL); + while ((tag = g_utf8_find_next_char (pos, NULL)) != NULL) { + gunichar c = g_utf8_get_char (tag); + if (!g_unichar_isspace (c)) + break; + + } + + if (g_ascii_strncasecmp (tag, "style", 5) == 0) { + tags = g_list_append ( + tags, + get_tag (string->str, "style", opening, closing)); + } else if (g_ascii_strncasecmp (tag, "script", 6) == 0) { + tags = g_list_append ( + tags, + get_tag (string->str, "script", opening, closing)); + } else if (g_ascii_strncasecmp (tag, "link", 4) == 0) { + tags = g_list_append ( + tags, + get_tag (string->str, "link", opening, closing)); + } else if (g_ascii_strncasecmp (tag, "body", 4) == 0) { + valid = TRUE; + break; + } + + } while (pos); + + if (tags) + printf("\n\n**%s**\n\n", (gchar *) tags->data); + + /* Something's wrong, let's write the entire HTML and hope + * that WebKit can handle it */ + if (!valid) { + EMailFormatterContext c = { + .folder = context->folder, + .message = context->message, + .message_uid = context->message_uid, + .parts = context->parts, + .flags = context->flags, + .mode = E_MAIL_FORMATTER_MODE_RAW, + }; + + emfe_text_html_format ( + extension, formatter, &c, part, stream, cancellable); + return FALSE; + } + + /* include the "body" as well -----v */ + g_string_erase (string, 0, tag - string->str + 4); + g_string_prepend (string, "
next) { + g_string_prepend (string, iter->data); + } + + g_list_free_full (tags, g_free); + + document_end = NULL; + /* We can probably use ASCII functions here */ + if (g_strrstr (string->str, "")) { + document_end = ">ydob/<"; + } + + if (g_strrstr (string->str, "")) { + if (document_end) { + document_end = ">lmth/<>ydob/<"; + } else { + document_end = ">lmth/<"; + } + } + + if (document_end ) { + length = strlen (document_end); + tag = string->str + string->len - 1; + i = 0; + valid = FALSE; + while (i < length - 1) { + gunichar c; + + c = g_utf8_get_char (tag); + if (g_unichar_isspace (c)) { + tag = g_utf8_find_prev_char (string->str, tag); + continue; + } + + c = g_unichar_tolower (c); + + if (c == document_end[i]) { + tag = g_utf8_find_prev_char (string->str, tag); + i++; + valid = TRUE; + continue; + } + + tag = g_utf8_find_prev_char (string->str, tag); + valid = FALSE; + } + } + + if (valid) + g_string_truncate (string, tag - string->str); + + camel_stream_write_string (stream, string->str, cancellable, NULL); + + g_string_free (string, TRUE); + } else { + gchar *uri, *str; + + uri = e_mail_part_build_uri ( + context->folder, context->message_uid, + "part_id", G_TYPE_STRING, part->id, + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, + NULL); + + str = g_strdup_printf ( + "
" + "" + "
", + uri, + part->id, + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_FRAME)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_CONTENT))); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + g_free (uri); + } + + return TRUE; +} + +static const gchar * +emfe_text_html_get_display_name (EMailFormatterExtension *extension) +{ + return _("HTML"); +} + +static const gchar * +emfe_text_html_get_description (EMailFormatterExtension *extension) +{ + return _("Format part as HTML"); +} + +static const gchar ** +emfe_text_html_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_text_html_class_init (EMailFormatterTextHTMLClass *klass) +{ + e_mail_formatter_text_html_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_text_html_format; + iface->get_display_name = emfe_text_html_get_display_name; + iface->get_description = emfe_text_html_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_text_html_mime_types; +} + +static void +e_mail_formatter_text_html_init (EMailFormatterTextHTML *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-text-plain.c b/em-format/e-mail-formatter-text-plain.c new file mode 100644 index 0000000000..631c46a3bc --- /dev/null +++ b/em-format/e-mail-formatter-text-plain.c @@ -0,0 +1,212 @@ +/* + * e-mail-formatter-text-plain.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include +#include + +#include +#include + +static const gchar *formatter_mime_types[] = { "text/plain", "text/*", NULL }; + +typedef struct _EMailFormatterTextPlain { + GObject parent; +} EMailFormatterTextPlain; + +typedef struct _EMailFormatterTextPlainClass { + GObjectClass parent_class; +} EMailFormatterTextPlainClass; + +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailFormatterTextPlain, + e_mail_formatter_text_plain, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static gboolean +emfe_text_plain_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + CamelDataWrapper *dw; + CamelStream *filtered_stream; + CamelMimeFilter *html_filter; + gchar *content; + const gchar *format; + guint32 filter_flags; + guint32 rgb; + + if (g_cancellable_is_cancelled (cancellable)) + return FALSE; + + if ((context->mode == E_MAIL_FORMATTER_MODE_RAW) || + (context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) { + + if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { + gchar *header; + header = e_mail_formatter_get_html_header (formatter); + camel_stream_write_string (stream, header, cancellable, NULL); + g_free (header); + + /* No need for body margins within ", + part->id, uri); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + g_free (uri); + } + + return TRUE; +} + +static const gchar * +emfe_text_plain_get_display_name (EMailFormatterExtension *extension) +{ + return _("Plain Text"); +} + +static const gchar * +emfe_text_plain_get_description (EMailFormatterExtension *extension) +{ + return _("Format part as plain text"); +} + +static const gchar ** +emfe_text_plain_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_text_plain_class_init (EMailFormatterTextPlainClass *klass) +{ + e_mail_formatter_text_plain_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_text_plain_format; + iface->get_display_name = emfe_text_plain_get_display_name; + iface->get_description = emfe_text_plain_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_text_plain_mime_types; +} + +static void +e_mail_formatter_text_plain_init (EMailFormatterTextPlain *formatter) +{ + +} diff --git a/em-format/e-mail-formatter-utils.c b/em-format/e-mail-formatter-utils.c new file mode 100644 index 0000000000..12ee042c90 --- /dev/null +++ b/em-format/e-mail-formatter-utils.c @@ -0,0 +1,434 @@ +/* + * e-mail-formatter-utils.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 + * + */ + +#ifdef HAVE_CONFIG +#include +#endif + +#include "e-mail-formatter-utils.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static const gchar *addrspec_hdrs[] = { + "Sender", "From", "Reply-To", "To", "Cc", "Bcc", + "Resent-Sender", "Resent-From", "Resent-Reply-To", + "Resent-To", "Resent-Cc", "Resent-Bcc", NULL +}; + +void +e_mail_formatter_format_text_header (EMailFormatter *formatter, + GString *buffer, + const gchar *label, + const gchar *value, + guint32 flags) +{ + const gchar *fmt, *html; + gchar *mhtml = NULL; + gboolean is_rtl; + + if (value == NULL) + return; + + while (*value == ' ') + value++; + + if (!(flags & E_MAIL_FORMATTER_HEADER_FLAG_HTML)) + html = mhtml = camel_text_to_html (value, + e_mail_formatter_get_text_format_flags (formatter), 0); + else + html = value; + + is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL; + + if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS) { + if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) { + fmt = "%s: %s"; + } else { + fmt = "%s: %s"; + } + } else if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NODEC) { + if (is_rtl) + fmt = "%2$s%1$s "; + else + fmt = "%s %s"; + } else { + if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) { + if (is_rtl) + fmt = "%2$s%1$s: "; + else + fmt = "%s: %s"; + } else { + if (is_rtl) + fmt = "%2$s%1$s: "; + else + fmt = "%s: %s"; + } + } + + g_string_append_printf (buffer, fmt, + (flags & E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN ? "none" : "table-row"), label, html); + + g_free (mhtml); +} + +gchar * +e_mail_formatter_format_address (EMailFormatter *formatter, + GString *out, + struct _camel_header_address *a, + gchar *field, + gboolean no_links, + gboolean elipsize) +{ + guint32 flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES; + gchar *name, *mailto, *addr; + gint i = 0; + gchar *str = NULL; + gint limit = mail_config_get_address_count (); + + while (a) { + if (a->name) + name = camel_text_to_html (a->name, flags, 0); + else + name = NULL; + + switch (a->type) { + case CAMEL_HEADER_ADDRESS_NAME: + if (name && *name) { + gchar *real, *mailaddr; + + if (strchr (a->name, ',') || strchr (a->name, ';')) + g_string_append_printf (out, ""%s"", name); + else + g_string_append (out, name); + + g_string_append (out, " <"); + + /* rfc2368 for mailto syntax and url encoding extras */ + if ((real = camel_header_encode_phrase ((guchar *) a->name))) { + mailaddr = g_strdup_printf("%s <%s>", real, a->v.addr); + g_free (real); + mailto = camel_url_encode (mailaddr, "?=&()"); + g_free (mailaddr); + } else { + mailto = camel_url_encode (a->v.addr, "?=&()"); + } + } else { + mailto = camel_url_encode (a->v.addr, "?=&()"); + } + addr = camel_text_to_html (a->v.addr, flags, 0); + if (no_links) + g_string_append_printf (out, "%s", addr); + else + g_string_append_printf (out, "%s", mailto, addr); + g_free (mailto); + g_free (addr); + + if (name && *name) + g_string_append (out, ">"); + break; + case CAMEL_HEADER_ADDRESS_GROUP: + g_string_append_printf (out, "%s: ", name); + e_mail_formatter_format_address ( + formatter, out, a->v.members, field, + no_links, elipsize); + g_string_append_printf (out, ";"); + break; + default: + g_warning ("Invalid address type"); + break; + } + + g_free (name); + + i++; + a = a->next; + if (a) + g_string_append (out, ", "); + + if (!elipsize) + continue; + + /* Let us add a '...' if we have more addresses */ + if (limit > 0 && (i == limit - 1)) { + const gchar *id = NULL; + + if (strcmp (field, _("To")) == 0) { + id = "to"; + } else if (strcmp (field, _("Cc")) == 0) { + id = "cc"; + } else if (strcmp (field, _("Bcc")) == 0) { + id = "bcc"; + } + + if (id) { + g_string_append_printf (out, + "", id); + str = g_strdup_printf ( + "", + EVOLUTION_IMAGESDIR, id); + } + } + } + + if (elipsize && str) { + const gchar *id = NULL; + + if (strcmp (field, _("To")) == 0) { + id = "to"; + } else if (strcmp (field, _("Cc")) == 0) { + id = "cc"; + } else if (strcmp (field, _("Bcc")) == 0) { + id = "bcc"; + } + + if (id) { + g_string_append_printf (out, + "" + "...", + id); + } + } + + return str; +} + +void +e_mail_formatter_canon_header_name (gchar *name) +{ + gchar *inptr = name; + + /* canonicalise the header name... first letter is + * capitalised and any letter following a '-' also gets + * capitalised */ + + if (*inptr >= 'a' && *inptr <= 'z') + *inptr -= 0x20; + + inptr++; + + while (*inptr) { + if (inptr[-1] == '-' && *inptr >= 'a' && *inptr <= 'z') + *inptr -= 0x20; + else if (*inptr >= 'A' && *inptr <= 'Z') + *inptr += 0x20; + + inptr++; + } +} + +void +e_mail_formatter_format_header (EMailFormatter *formatter, + GString *buffer, + CamelMedium *part, + struct _camel_header_raw *header, + guint32 flags, + const gchar *charset) +{ + gchar *name, *buf, *value = NULL; + const gchar *label, *txt; + gboolean addrspec = FALSE; + gchar *str_field = NULL; + gint i; + + name = g_alloca (strlen (header->name) + 1); + strcpy (name, header->name); + e_mail_formatter_canon_header_name (name); + + for (i = 0; addrspec_hdrs[i]; i++) { + if (!strcmp (name, addrspec_hdrs[i])) { + addrspec = TRUE; + break; + } + } + + label = _(name); + + if (addrspec) { + struct _camel_header_address *addrs; + GString *html; + gchar *img; + const gchar *charset = e_mail_formatter_get_charset (formatter) ? + e_mail_formatter_get_charset (formatter) : + e_mail_formatter_get_default_charset (formatter); + + buf = camel_header_unfold (header->value); + if (!(addrs = camel_header_address_decode (buf, charset))) { + g_free (buf); + return; + } + + g_free (buf); + + html = g_string_new(""); + img = e_mail_formatter_format_address (formatter, html, addrs, (gchar *) label, + (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS), + !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE)); + + if (img) { + str_field = g_strdup_printf ("%s%s:", img, label); + label = str_field; + flags |= E_MAIL_FORMATTER_HEADER_FLAG_NODEC; + g_free (img); + } + + camel_header_address_list_clear (&addrs); + txt = value = html->str; + g_string_free (html, FALSE); + + flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML | E_MAIL_FORMATTER_HEADER_FLAG_BOLD; + } else if (!strcmp (name, "Subject")) { + buf = camel_header_unfold (header->value); + txt = value = camel_header_decode_string (buf, charset); + g_free (buf); + + flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD; + } else if (!strcmp(name, "X-evolution-mailer")) { + /* pseudo-header */ + label = _("Mailer"); + txt = value = camel_header_format_ctext (header->value, charset); + flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD; + } else if (!strcmp (name, "Date") || !strcmp (name, "Resent-Date")) { + gint msg_offset, local_tz; + time_t msg_date; + struct tm local; + gchar *html; + gboolean hide_real_date; + + hide_real_date = !e_mail_formatter_get_show_real_date (formatter); + + txt = header->value; + while (*txt == ' ' || *txt == '\t') + txt++; + + html = camel_text_to_html (txt, + e_mail_formatter_get_text_format_flags (formatter), 0); + + msg_date = camel_header_decode_date (txt, &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; + + /* value will be freed at the end */ + if (!hide_real_date && !msg_offset) { + /* No timezone difference; just show the real Date: header */ + txt = value = html; + } else { + gchar *date_str; + + date_str = e_datetime_format_format ("mail", "header", + DTFormatKindDateTime, msg_date); + + if (hide_real_date) { + /* Show only the local-formatted date, losing all timezone + * information like Outlook does. Should we attempt to show + * it somehow? */ + txt = value = date_str; + } else { + txt = value = g_strdup_printf ("%s (%s)", html, date_str); + g_free (date_str); + } + g_free (html); + } + flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML | + E_MAIL_FORMATTER_HEADER_FLAG_BOLD; + } else if (!strcmp(name, "Newsgroups")) { + struct _camel_header_newsgroup *ng, *scan; + GString *html; + + buf = camel_header_unfold (header->value); + + if (!(ng = camel_header_newsgroups_decode (buf))) { + g_free (buf); + return; + } + + g_free (buf); + + html = g_string_new(""); + scan = ng; + while (scan) { + if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS) + g_string_append_printf (html, "%s", scan->newsgroup); + else + g_string_append_printf(html, "%s", + scan->newsgroup, scan->newsgroup); + scan = scan->next; + if (scan) + g_string_append_printf(html, ", "); + } + + camel_header_newsgroups_free (ng); + + txt = html->str; + g_string_free (html, FALSE); + flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML | + E_MAIL_FORMATTER_HEADER_FLAG_BOLD; + } else if (!strcmp (name, "Received") || !strncmp (name, "X-", 2)) { + /* don't unfold Received nor extension headers */ + txt = value = camel_header_decode_string (header->value, charset); + } else { + /* don't unfold Received nor extension headers */ + buf = camel_header_unfold (header->value); + txt = value = camel_header_decode_string (buf, charset); + g_free (buf); + } + + e_mail_formatter_format_text_header (formatter, buffer, label, txt, flags); + + g_free (value); + g_free (str_field); +} + +GSList * +e_mail_formatter_find_rfc822_end_iter (GSList *iter) +{ + EMailPart *part; + gchar *end; + + part = iter->data; + end = g_strconcat (part->id, ".end", NULL); + for (; iter != NULL; iter = g_slist_next (iter)) { + part = iter->data; + if (!part) + continue; + + if (g_strcmp0 (part->id, end) == 0) { + g_free (end); + return iter; + } + } + g_free (end); + return iter; +} diff --git a/em-format/e-mail-formatter-utils.h b/em-format/e-mail-formatter-utils.h new file mode 100644 index 0000000000..59d8e43257 --- /dev/null +++ b/em-format/e-mail-formatter-utils.h @@ -0,0 +1,56 @@ +/* + * e-mail-formatter-utils.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 + * + */ + +#ifndef E_MAIL_FORMATTER_UTILS_H_ +#define E_MAIL_FORMATTER_UTILS_H_ + +#include +#include + +G_BEGIN_DECLS + +void e_mail_formatter_format_header (EMailFormatter *formatter, + GString *buffer, + CamelMedium *part, + struct _camel_header_raw *header, + guint32 flags, + const gchar *charset); + +void e_mail_formatter_format_text_header + (EMailFormatter *formatter, + GString *buffer, + const gchar *label, + const gchar *value, + guint32 flags); + +gchar * e_mail_formatter_format_address (EMailFormatter *formatter, + GString *out, + struct _camel_header_address *a, + gchar *field, + gboolean no_links, + gboolean elipsize); + +void e_mail_formatter_canon_header_name + (gchar *name); + +GSList * e_mail_formatter_find_rfc822_end_iter + (GSList *rfc822_start_iter); + +G_END_DECLS + +#endif /* E_MAIL_FORMATTER_UTILS_H_ */ diff --git a/em-format/e-mail-formatter.c b/em-format/e-mail-formatter.c new file mode 100644 index 0000000000..a08504a21f --- /dev/null +++ b/em-format/e-mail-formatter.c @@ -0,0 +1,1510 @@ +/* + * e-mail-formatter.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 + * + */ + +#include "e-mail-formatter.h" + +#include + +#include "e-mail-formatter-extension.h" +#include "e-mail-formatter-utils.h" +#include "e-mail-part.h" + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include + +#define d(x) + +struct _EMailFormatterPrivate { + EMailImageLoadingPolicy image_loading_policy; + + guint only_local_photos : 1; + guint show_sender_photo : 1; + guint show_real_date : 1; + guint animate_images : 1; + + gchar *charset; + gchar *default_charset; + + GQueue *header_list; +}; + +#define E_MAIL_FORMATTER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterPrivate))\ + +static gpointer e_mail_formatter_parent_class = 0; + +enum { + PROP_0, + PROP_BODY_COLOR, + PROP_CITATION_COLOR, + PROP_CONTENT_COLOR, + PROP_FRAME_COLOR, + PROP_HEADER_COLOR, + PROP_TEXT_COLOR, + PROP_IMAGE_LOADING_POLICY, + PROP_FORCE_IMAGE_LOADING, + PROP_MARK_CITATIONS, + PROP_ONLY_LOCAL_PHOTOS, + PROP_SHOW_SENDER_PHOTO, + PROP_SHOW_REAL_DATE, + PROP_ANIMATE_IMAGES, + PROP_CHARSET, + PROP_DEFAULT_CHARSET +}; + +static void +mail_formatter_run (EMailFormatter *formatter, + EMailFormatterContext *context, + CamelStream *stream, + GCancellable *cancellable) +{ + GSList *iter; + gchar *hdr; + + hdr = e_mail_formatter_get_html_header (formatter); + camel_stream_write_string (stream, hdr, cancellable, NULL); + g_free (hdr); + + for (iter = context->parts; iter; iter = iter->next) { + + EMailPart *part; + gboolean ok; + + if (g_cancellable_is_cancelled (cancellable)) + break; + + part = iter->data; + if (!part) + continue; + + if (part->is_hidden && !part->is_error) { + if (g_str_has_suffix (part->id, ".rfc822")) { + iter = e_mail_formatter_find_rfc822_end_iter (iter); + } + + if (!iter) + break; + + continue; + } + + /* Force formatting as source if needed */ + if (context->mode != E_MAIL_FORMATTER_MODE_SOURCE) { + + if (!part->mime_type) + continue; + + ok = e_mail_formatter_format_as ( + formatter, context, part, stream, + part->mime_type, cancellable); + + /* If the written part was message/rfc822 then + * jump to the end of the message, because content + * of the whole message has been formatted by + * message_rfc822 formatter */ + if (ok && g_str_has_suffix (part->id, ".rfc822")) { + iter = e_mail_formatter_find_rfc822_end_iter (iter); + + if (!iter) + break; + + continue; + } + + } else { + ok = FALSE; + } + + if (!ok) { + /* We don't want to source these */ + if (g_str_has_suffix (part->id, ".headers") || + g_str_has_suffix (part->id, "attachment-bar")) + continue; + + e_mail_formatter_format_as ( + formatter, context, part, stream, + "application/vnd.evolution.source", cancellable); + + /* .message is the entire message. There's nothing more + * to be written. */ + if (g_strcmp0 (part->id, ".message") == 0) + break; + + /* If we just wrote source of a rfc822 message, then jump + * behind the message (otherwise source of all parts + * would be rendered twice) */ + if (g_str_has_suffix (part->id, ".rfc822")) { + + do { + part = iter->data; + if (part && g_str_has_suffix (part->id, ".rfc822.end")) + break; + + iter = iter->next; + } while (iter); + } + } + } + + camel_stream_write_string (stream, "", cancellable, NULL); +} + +static EMailFormatterContext * +mail_formatter_create_context (EMailFormatter *formatter) +{ + EMailFormatterClass *formatter_class; + + formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter); + + if (formatter_class->create_context) { + if (!formatter_class->free_context) { + g_warning ("%s implements create_context() but " + "does not implement free_context()!", + G_OBJECT_TYPE_NAME (formatter)); + } + + return formatter_class->create_context (formatter); + } + + return g_new0 (EMailFormatterContext, 1); +} + +static void +mail_formatter_free_context (EMailFormatter *formatter, + EMailFormatterContext *context) +{ + EMailFormatterClass *formatter_class; + + formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter); + + if (formatter_class->free_context) { + formatter_class->free_context (formatter, context); + } else { + g_free (context); + } +} + +static void +mail_formatter_set_style (EMailFormatter *formatter, + GtkStyle *style, + GtkStateType state) +{ + GdkColor *color; + EMailFormatterColorType type; + + g_object_freeze_notify (G_OBJECT (formatter)); + + color = &style->bg[state]; + type = E_MAIL_FORMATTER_COLOR_BODY; + e_mail_formatter_set_color (formatter, type, color); + + color = &style->base[GTK_STATE_NORMAL]; + type = E_MAIL_FORMATTER_COLOR_CONTENT; + e_mail_formatter_set_color (formatter, type, color); + + color = &style->dark[state]; + type = E_MAIL_FORMATTER_COLOR_FRAME; + e_mail_formatter_set_color (formatter, type, color); + + color = &style->fg[state]; + type = E_MAIL_FORMATTER_COLOR_HEADER; + e_mail_formatter_set_color (formatter, type, color); + + color = &style->text[state]; + type = E_MAIL_FORMATTER_COLOR_TEXT; + e_mail_formatter_set_color (formatter, type, color); + + g_object_thaw_notify (G_OBJECT (formatter)); +} + +static void +e_mail_formatter_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_BODY_COLOR: + e_mail_formatter_set_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_BODY, + g_value_get_boxed (value)); + return; + + case PROP_CITATION_COLOR: + e_mail_formatter_set_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_CITATION, + g_value_get_boxed (value)); + return; + + case PROP_CONTENT_COLOR: + e_mail_formatter_set_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_CONTENT, + g_value_get_boxed (value)); + return; + + case PROP_FRAME_COLOR: + e_mail_formatter_set_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_FRAME, + g_value_get_boxed (value)); + return; + + case PROP_HEADER_COLOR: + e_mail_formatter_set_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_HEADER, + g_value_get_boxed (value)); + return; + + case PROP_IMAGE_LOADING_POLICY: + e_mail_formatter_set_image_loading_policy ( + E_MAIL_FORMATTER (object), + g_value_get_int (value)); + return; + + case PROP_MARK_CITATIONS: + e_mail_formatter_set_mark_citations ( + E_MAIL_FORMATTER (object), + g_value_get_boolean (value)); + return; + + case PROP_ONLY_LOCAL_PHOTOS: + e_mail_formatter_set_only_local_photos ( + E_MAIL_FORMATTER (object), + g_value_get_boolean (value)); + return; + + case PROP_SHOW_SENDER_PHOTO: + e_mail_formatter_set_show_sender_photo ( + E_MAIL_FORMATTER (object), + g_value_get_boolean (value)); + return; + + case PROP_SHOW_REAL_DATE: + e_mail_formatter_set_show_real_date ( + E_MAIL_FORMATTER (object), + g_value_get_boolean (value)); + return; + + case PROP_TEXT_COLOR: + e_mail_formatter_set_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_TEXT, + g_value_get_boxed (value)); + return; + + case PROP_ANIMATE_IMAGES: + e_mail_formatter_set_animate_images ( + E_MAIL_FORMATTER (object), + g_value_get_boolean (value)); + return; + + case PROP_CHARSET: + e_mail_formatter_set_charset ( + E_MAIL_FORMATTER (object), + g_value_get_string (value)); + return; + + case PROP_DEFAULT_CHARSET: + e_mail_formatter_set_default_charset ( + E_MAIL_FORMATTER (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +e_mail_formatter_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_BODY_COLOR: + g_value_set_boxed (value, + e_mail_formatter_get_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_BODY)); + return; + + case PROP_CITATION_COLOR: + g_value_set_boxed (value, + e_mail_formatter_get_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_CITATION)); + return; + + case PROP_CONTENT_COLOR: + g_value_set_boxed (value, + e_mail_formatter_get_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_CONTENT)); + return; + + case PROP_FRAME_COLOR: + g_value_set_boxed (value, + e_mail_formatter_get_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_FRAME)); + return; + + case PROP_HEADER_COLOR: + g_value_set_boxed (value, + e_mail_formatter_get_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_HEADER)); + return; + + case PROP_IMAGE_LOADING_POLICY: + g_value_set_int ( + value, + e_mail_formatter_get_image_loading_policy ( + E_MAIL_FORMATTER (object))); + return; + + case PROP_MARK_CITATIONS: + g_value_set_boolean ( + value, e_mail_formatter_get_mark_citations ( + E_MAIL_FORMATTER (object))); + return; + + case PROP_ONLY_LOCAL_PHOTOS: + g_value_set_boolean ( + value, e_mail_formatter_get_only_local_photos ( + E_MAIL_FORMATTER (object))); + return; + + case PROP_SHOW_SENDER_PHOTO: + g_value_set_boolean ( + value, e_mail_formatter_get_show_sender_photo ( + E_MAIL_FORMATTER (object))); + return; + + case PROP_SHOW_REAL_DATE: + g_value_set_boolean ( + value, e_mail_formatter_get_show_real_date ( + E_MAIL_FORMATTER (object))); + return; + + case PROP_TEXT_COLOR: + g_value_set_boxed (value, + e_mail_formatter_get_color ( + E_MAIL_FORMATTER (object), + E_MAIL_FORMATTER_COLOR_TEXT)); + return; + + case PROP_ANIMATE_IMAGES: + g_value_set_boolean ( + value, e_mail_formatter_get_animate_images ( + E_MAIL_FORMATTER (object))); + return; + + case PROP_CHARSET: + g_value_set_string ( + value, e_mail_formatter_get_charset ( + E_MAIL_FORMATTER (object))); + return; + + case PROP_DEFAULT_CHARSET: + g_value_set_string ( + value, e_mail_formatter_get_default_charset ( + E_MAIL_FORMATTER (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +e_mail_formatter_init (EMailFormatter *formatter) +{ + formatter->priv = E_MAIL_FORMATTER_GET_PRIVATE (formatter); + + formatter->priv->header_list = g_queue_new (); + e_mail_formatter_set_default_headers (formatter); +} + +static void +e_mail_formatter_finalize (GObject *object) +{ + EMailFormatterPrivate *priv; + + priv = E_MAIL_FORMATTER (object)->priv; + + if (priv->charset) { + g_free (priv->charset); + priv->charset = NULL; + } + + if (priv->default_charset) { + g_free (priv->default_charset); + priv->default_charset = NULL; + } + + if (priv->header_list) { + e_mail_formatter_clear_headers (E_MAIL_FORMATTER (object)); + g_queue_free (priv->header_list); + priv->header_list = NULL; + } + + /* Chain up to parent's finalize() */ + G_OBJECT_CLASS (e_mail_formatter_parent_class)->finalize (object); +} + +static void +e_mail_formatter_base_init (EMailFormatterClass *klass) +{ + klass->extension_registry = g_object_new ( + E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, NULL); + + e_mail_formatter_internal_extensions_load ( + E_MAIL_EXTENSION_REGISTRY (klass->extension_registry)); + + e_extensible_load_extensions ( + E_EXTENSIBLE (klass->extension_registry)); + + klass->text_html_flags = + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | + CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | + CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES | + CAMEL_MIME_FILTER_TOHTML_MARK_CITATION; +} + +static void +e_mail_formatter_base_finalize (EMailFormatterClass *klass) +{ + g_object_unref (klass->extension_registry); +} + +static void +e_mail_formatter_constructed (GObject *object) +{ + G_OBJECT_CLASS (e_mail_formatter_parent_class)->constructed (object); + + e_extensible_load_extensions (E_EXTENSIBLE (object)); +} + +static void +e_mail_formatter_class_init (EMailFormatterClass *klass) +{ + GObjectClass *object_class; + GdkColor *color; + + e_mail_formatter_parent_class = g_type_class_peek_parent (klass); + g_type_class_add_private (klass, sizeof (EMailFormatterPrivate)); + + klass->run = mail_formatter_run; + + /* EMailFormatter calls these directly */ + klass->create_context = NULL; + klass->free_context = NULL; + klass->set_style = mail_formatter_set_style; + + color = &klass->colors[E_MAIL_FORMATTER_COLOR_BODY]; + gdk_color_parse ("#eeeeee", color); + + color = &klass->colors[E_MAIL_FORMATTER_COLOR_CONTENT]; + gdk_color_parse ("#ffffff", color); + + color = &klass->colors[E_MAIL_FORMATTER_COLOR_FRAME]; + gdk_color_parse ("#3f3f3f", color); + + color = &klass->colors[E_MAIL_FORMATTER_COLOR_HEADER]; + gdk_color_parse ("#eeeeee", color); + + color = &klass->colors[E_MAIL_FORMATTER_COLOR_TEXT]; + gdk_color_parse ("#000000", color); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_formatter_constructed; + object_class->get_property = e_mail_formatter_get_property; + object_class->set_property = e_mail_formatter_set_property; + object_class->finalize = e_mail_formatter_finalize; + + g_object_class_install_property ( + object_class, + PROP_BODY_COLOR, + g_param_spec_boxed ( + "body-color", + "Body Color", + NULL, + GDK_TYPE_COLOR, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_CITATION_COLOR, + g_param_spec_boxed ( + "citation-color", + "Citation Color", + NULL, + GDK_TYPE_COLOR, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_CONTENT_COLOR, + g_param_spec_boxed ( + "content-color", + "Content Color", + NULL, + GDK_TYPE_COLOR, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_FRAME_COLOR, + g_param_spec_boxed ( + "frame-color", + "Frame Color", + NULL, + GDK_TYPE_COLOR, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_HEADER_COLOR, + g_param_spec_boxed ( + "header-color", + "Header Color", + NULL, + GDK_TYPE_COLOR, + G_PARAM_READWRITE)); + + /* FIXME Make this a proper enum property. */ + g_object_class_install_property ( + object_class, + PROP_IMAGE_LOADING_POLICY, + g_param_spec_int ( + "image-loading-policy", + "Image Loading Policy", + NULL, + E_MAIL_IMAGE_LOADING_POLICY_NEVER, + E_MAIL_IMAGE_LOADING_POLICY_ALWAYS, + E_MAIL_IMAGE_LOADING_POLICY_NEVER, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_MARK_CITATIONS, + g_param_spec_boolean ( + "mark-citations", + "Mark Citations", + NULL, + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_ONLY_LOCAL_PHOTOS, + g_param_spec_boolean ( + "only-local-photos", + "Only Local Photos", + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_SHOW_SENDER_PHOTO, + g_param_spec_boolean ( + "show-sender-photo", + "Show Sender Photo", + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_SHOW_REAL_DATE, + g_param_spec_boolean ( + "show-real-date", + "Show real Date header value", + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_TEXT_COLOR, + g_param_spec_boxed ( + "text-color", + "Text Color", + NULL, + GDK_TYPE_COLOR, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_ANIMATE_IMAGES, + g_param_spec_boolean ( + "animate-images", + "Animate images", + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_CHARSET, + g_param_spec_string ( + "charset", + NULL, + NULL, + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_DEFAULT_CHARSET, + g_param_spec_string ( + "default-charset", + NULL, + NULL, + NULL, + G_PARAM_READWRITE)); +} + +static void +e_mail_formatter_extensible_interface_init (EExtensibleInterface *interface) +{ + +} + +EMailFormatter * +e_mail_formatter_new (void) +{ + return g_object_new (E_TYPE_MAIL_FORMATTER, NULL); +} + +GType +e_mail_formatter_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EMailFormatterClass), + (GBaseInitFunc) e_mail_formatter_base_init, + (GBaseFinalizeFunc) e_mail_formatter_base_finalize, + (GClassInitFunc) e_mail_formatter_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMailFormatter), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_mail_formatter_init, + NULL /* value_table */ + }; + + const GInterfaceInfo e_extensible_interface_info = { + (GInterfaceInitFunc) e_mail_formatter_extensible_interface_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "EMailFormatter", &type_info, 0); + + g_type_add_interface_static (type, + E_TYPE_EXTENSIBLE, &e_extensible_interface_info); + } + + return type; +} + +void +e_mail_formatter_format_sync (EMailFormatter *formatter, + EMailPartList *parts, + CamelStream *stream, + guint32 flags, + EMailFormatterMode mode, + GCancellable *cancellable) +{ + EMailFormatterContext *context; + EMailFormatterClass *formatter_class; + + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (CAMEL_IS_STREAM (stream)); + + formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter); + g_return_if_fail (formatter_class->run != NULL); + + context = mail_formatter_create_context (formatter); + context->message = parts->message; + context->folder = parts->folder; + context->message_uid = parts->message_uid; + context->parts = parts->list; + context->flags = flags; + context->mode = mode; + + formatter_class->run ( + formatter, context, stream, cancellable); + + mail_formatter_free_context (formatter, context); +} + +static void +mail_format_async_prepare (GSimpleAsyncResult *result, + GObject *object, + GCancellable *cancellable) +{ + EMailFormatterContext *context; + EMailFormatterClass *formatter_class; + CamelStream *stream; + + context = g_object_get_data (G_OBJECT (result), "context"); + stream = g_object_get_data (G_OBJECT (result), "stream"); + + formatter_class = E_MAIL_FORMATTER_GET_CLASS (object); + formatter_class->run ( + E_MAIL_FORMATTER (object), context, stream, cancellable); +} + +void +e_mail_formatter_format (EMailFormatter *formatter, + EMailPartList *parts, + CamelStream *stream, + guint32 flags, + EMailFormatterMode mode, + GAsyncReadyCallback callback, + GCancellable *cancellable, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + EMailFormatterContext *context; + EMailFormatterClass *formatter_class; + + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (CAMEL_IS_STREAM (stream)); + + formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter); + g_return_if_fail (formatter_class->run != NULL); + + simple = g_simple_async_result_new ( + G_OBJECT (formatter), callback, + user_data, e_mail_formatter_format); + + g_simple_async_result_set_check_cancellable (simple, cancellable); + + if (!parts && callback) { + callback (G_OBJECT (formatter), G_ASYNC_RESULT (simple), user_data); + g_object_unref (simple); + return; + } + + context = mail_formatter_create_context (formatter); + context->message = g_object_ref (parts->message); + context->folder = g_object_ref (parts->folder); + context->message_uid = g_strdup (parts->message_uid); + context->parts = g_slist_copy (parts->list); + g_slist_foreach (context->parts, (GFunc) e_mail_part_ref, NULL); + context->flags = flags; + context->mode = mode; + + g_object_set_data (G_OBJECT (simple), "context", context); + g_object_set_data (G_OBJECT (simple), "stream", stream); + + g_simple_async_result_run_in_thread ( + simple, mail_format_async_prepare, + G_PRIORITY_DEFAULT, cancellable); + + g_object_unref (simple); +} + +CamelStream * +e_mail_formatter_format_finished (EMailFormatter *formatter, + GAsyncResult *result, + GError *error) +{ + EMailFormatterContext *context; + + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + context = g_object_get_data (G_OBJECT (result), "context"); + + g_free (context->message_uid); + g_object_unref (context->message); + g_object_unref (context->folder); + g_slist_foreach (context->parts, (GFunc) e_mail_part_unref, NULL); + g_slist_free (context->parts); + mail_formatter_free_context (formatter, context); + + return g_object_get_data (G_OBJECT (result), "stream"); +} + +/** + * e_mail_formatter_format_as: + * @formatter: an #EMailFormatter + * @context: an #EMailFormatterContext + * @part: an #EMailPart + * @stream: a #CamelStream + * @as_mime_type: (allow-none) mime-type to use for formatting, or %NULL + * @cancellable: (allow-none) an optional #GCancellable + * + * Formats given @part using a @formatter extension for given mime type. When + * the mime type is %NULL, the function will try to lookup the best formatter + * for given @part by it's default mime type. + * + * Return Value: %TRUE on success, %FALSE when no suitable formatter is found or + * when it fails to format the part. + */ +gboolean +e_mail_formatter_format_as (EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + const gchar *as_mime_type, + GCancellable *cancellable) +{ + EMailExtensionRegistry *reg; + GQueue *formatters; + GList *iter; + gboolean ok; + d ( + gint _call_i; + static gint _call = 0; + G_LOCK_DEFINE_STATIC (_call); + G_LOCK (_call); + _call++; + _call_i = _call; + G_UNLOCK (_call) + ); + + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE); + g_return_val_if_fail (part, FALSE); + g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE); + + if (!as_mime_type || !*as_mime_type) + as_mime_type = part->mime_type; + + if (!as_mime_type || !*as_mime_type) + return FALSE; + + reg = e_mail_formatter_get_extension_registry (formatter); + formatters = e_mail_extension_registry_get_for_mime_type ( + reg, as_mime_type); + if (!formatters) { + formatters = e_mail_extension_registry_get_fallback ( + reg, as_mime_type); + } + + ok = FALSE; + + d(printf("(%d) Formatting for part %s of type %s (found %d formatters)\n", + _call_i, part->id, as_mime_type, + formatters ? g_queue_get_length (formatters) : 0)); + + if (formatters) { + for (iter = formatters->head; iter; iter = iter->next) { + + EMailFormatterExtension *extension; + + extension = iter->data; + if (!extension) + continue; + + ok = e_mail_formatter_extension_format ( + extension, formatter, context, + part, stream, cancellable); + + d(printf("\t(%d) trying %s...%s\n", _call_i, + G_OBJECT_TYPE_NAME (extension), + ok ? "OK" : "failed")); + + if (ok) + break; + } + } + + return ok; +} + +/** + * em_format_format_text: + * @part: an #EMailPart to decode + * @formatter: an #EMailFormatter + * @stream: Where to write the converted text + * @cancellable: optional #GCancellable object, or %NULL + * + * Decode/output a part's content to @stream. + **/ +void +e_mail_formatter_format_text (EMailFormatter *formatter, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + CamelStream *filter_stream; + CamelMimeFilter *filter; + const gchar *charset = NULL; + CamelMimeFilterWindows *windows = NULL; + CamelStream *mem_stream = NULL; + CamelDataWrapper *dw; + + if (g_cancellable_is_cancelled (cancellable)) + return; + + dw = CAMEL_DATA_WRAPPER (part->part); + + if (formatter->priv->charset) { + charset = formatter->priv->charset; + } else if (dw->mime_type + && (charset = camel_content_type_param (dw->mime_type, "charset")) + && g_ascii_strncasecmp(charset, "iso-8859-", 9) == 0) { + CamelStream *null; + + /* Since a few Windows mailers like to claim they sent + * out iso-8859-# encoded text when they really sent + * out windows-cp125#, do some simple sanity checking + * before we move on... */ + + null = camel_stream_null_new (); + filter_stream = camel_stream_filter_new (null); + g_object_unref (null); + + windows = (CamelMimeFilterWindows *) camel_mime_filter_windows_new (charset); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filter_stream), + CAMEL_MIME_FILTER (windows)); + + camel_data_wrapper_decode_to_stream_sync ( + dw, (CamelStream *) filter_stream, cancellable, NULL); + camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL); + g_object_unref (filter_stream); + + charset = camel_mime_filter_windows_real_charset (windows); + } else if (charset == NULL) { + charset = formatter->priv->default_charset; + } + + mem_stream = (CamelStream *) camel_stream_mem_new (); + filter_stream = camel_stream_filter_new (mem_stream); + + if ((filter = camel_mime_filter_charset_new (charset, "UTF-8"))) { + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filter_stream), + CAMEL_MIME_FILTER (filter)); + g_object_unref (filter); + } + + camel_data_wrapper_decode_to_stream_sync ( + camel_medium_get_content ((CamelMedium *) dw), + (CamelStream *) filter_stream, cancellable, NULL); + camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL); + g_object_unref (filter_stream); + + g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, NULL, NULL); + + camel_stream_write_to_stream ( + mem_stream, (CamelStream *) stream, cancellable, NULL); + camel_stream_flush ((CamelStream *) mem_stream, cancellable, NULL); + + if (windows) { + g_object_unref (windows); + } + + g_object_unref (mem_stream); +} + +gchar * +e_mail_formatter_get_html_header (EMailFormatter *formatter) +{ + return g_strdup_printf ( + "\n\n" + "\n\n" + "Evolution Mail Display\n" + "\n" + "\n" + "", + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_BODY))); +} + +EMailExtensionRegistry * +e_mail_formatter_get_extension_registry (EMailFormatter *formatter) +{ + EMailFormatterClass * formatter_class; + + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL); + + formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter); + return E_MAIL_EXTENSION_REGISTRY (formatter_class->extension_registry); +} + +guint32 +e_mail_formatter_get_text_format_flags (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), 0); + + return E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags; +} + +const GdkColor * +e_mail_formatter_get_color (EMailFormatter *formatter, + EMailFormatterColorType type) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL); + g_return_val_if_fail (type < E_MAIL_FORMATTER_NUM_COLOR_TYPES, NULL); + + return &E_MAIL_FORMATTER_GET_CLASS (formatter)->colors[type]; +} + +void +e_mail_formatter_set_color (EMailFormatter *formatter, + EMailFormatterColorType type, + const GdkColor *color) +{ + GdkColor *format_color; + const gchar *property_name; + + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (type < E_MAIL_FORMATTER_NUM_COLOR_TYPES); + g_return_if_fail (color != NULL); + + format_color = &E_MAIL_FORMATTER_GET_CLASS (formatter)->colors[type]; + + if (gdk_color_equal (color, format_color)) + return; + + format_color->red = color->red; + format_color->green = color->green; + format_color->blue = color->blue; + + switch (type) { + case E_MAIL_FORMATTER_COLOR_BODY: + property_name = "body-color"; + break; + case E_MAIL_FORMATTER_COLOR_CITATION: + property_name = "citation-color"; + break; + case E_MAIL_FORMATTER_COLOR_CONTENT: + property_name = "content-color"; + break; + case E_MAIL_FORMATTER_COLOR_FRAME: + property_name = "frame-color"; + break; + case E_MAIL_FORMATTER_COLOR_HEADER: + property_name = "header-color"; + break; + case E_MAIL_FORMATTER_COLOR_TEXT: + property_name = "text-color"; + break; + default: + g_return_if_reached (); + } + + g_object_notify (G_OBJECT (formatter), property_name); +} + +void +e_mail_formatter_set_style (EMailFormatter *formatter, + GtkStyle *style, + GtkStateType state) +{ + EMailFormatterClass *formatter_class; + + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (GTK_IS_STYLE (style)); + + formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter); + g_return_if_fail (formatter_class->set_style != NULL); + + formatter_class->set_style (formatter, style, state); +} + +EMailImageLoadingPolicy +e_mail_formatter_get_image_loading_policy (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), 0); + + return formatter->priv->image_loading_policy; +} + +void +e_mail_formatter_set_image_loading_policy (EMailFormatter *formatter, + EMailImageLoadingPolicy policy) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + if (policy == formatter->priv->image_loading_policy) + return; + + formatter->priv->image_loading_policy = policy; + + g_object_notify (G_OBJECT (formatter), "image-loading-policy"); +} + +gboolean +e_mail_formatter_get_mark_citations (EMailFormatter *formatter) +{ + guint32 flags; + + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE); + + flags = E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags; + + return ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0); +} + +void +e_mail_formatter_set_mark_citations (EMailFormatter *formatter, + gboolean mark_citations) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + if (mark_citations) + E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags |= + CAMEL_MIME_FILTER_TOHTML_MARK_CITATION; + else + E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags &= + ~CAMEL_MIME_FILTER_TOHTML_MARK_CITATION; + + g_object_notify (G_OBJECT (formatter), "mark-citations"); +} + +gboolean +e_mail_formatter_get_only_local_photos (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE); + + return formatter->priv->only_local_photos; +} + +void +e_mail_formatter_set_only_local_photos (EMailFormatter *formatter, + gboolean only_local_photos) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + formatter->priv->only_local_photos = only_local_photos; + + g_object_notify (G_OBJECT (formatter), "only-local-photos"); +} + +gboolean +e_mail_formatter_get_show_sender_photo (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE); + + return formatter->priv->show_sender_photo; +} + +void +e_mail_formatter_set_show_sender_photo (EMailFormatter *formatter, + gboolean show_sender_photo) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + formatter->priv->show_sender_photo = show_sender_photo; + + g_object_notify (G_OBJECT (formatter), "show-sender-photo"); +} + +gboolean +e_mail_formatter_get_show_real_date (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE); + + return formatter->priv->show_real_date; +} + +void +e_mail_formatter_set_show_real_date (EMailFormatter *formatter, + gboolean show_real_date) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + formatter->priv->show_real_date = show_real_date; + + g_object_notify (G_OBJECT (formatter), "show-real-date"); +} + +gboolean +e_mail_formatter_get_animate_images (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE); + + return formatter->priv->animate_images; +} + +void +e_mail_formatter_set_animate_images (EMailFormatter *formatter, + gboolean animate_images) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + formatter->priv->animate_images = animate_images; + + g_object_notify (G_OBJECT (formatter), "animate-images"); +} + +const gchar * +e_mail_formatter_get_charset (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL); + + return formatter->priv->charset; +} + +void +e_mail_formatter_set_charset (EMailFormatter *formatter, + const gchar *charset) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (charset && *charset); + + if (formatter->priv->charset) + g_free (formatter->priv->charset); + + formatter->priv->charset = g_strdup (charset); + + g_object_notify (G_OBJECT (formatter), "charset"); +} + +const gchar * +e_mail_formatter_get_default_charset (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL); + + return formatter->priv->default_charset; +} + +void +e_mail_formatter_set_default_charset (EMailFormatter *formatter, + const gchar *default_charset) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (default_charset && *default_charset); + + if (formatter->priv->default_charset) + g_free (formatter->priv->default_charset); + + formatter->priv->default_charset = g_strdup (default_charset); + + g_object_notify (G_OBJECT (formatter), "default-charset"); +} + +/* note: also copied in em-mailer-prefs.c */ +static const struct { + const gchar *name; + guint32 flags; +} default_headers[] = { + { N_("From"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD }, + { N_("Reply-To"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD }, + { N_("To"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD }, + { N_("Cc"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD }, + { N_("Bcc"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD }, + { N_("Subject"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD }, + { N_("Date"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD }, + { N_("Newsgroups"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD }, + { N_("Face"), 0 }, +}; + +/** + * e_mail_formatter_get_headers: + * @formatter: an #EMailFormatter + * + * Returns list of currently set headers. + * + * Return Value: A #GQueue of headers which you should not modify or unref + */ +const GQueue * +e_mail_formatter_get_headers (EMailFormatter *formatter) +{ + g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL); + + return formatter->priv->header_list; +} + +/** + * e_mail_formatter_clear_headers: + * @formatter: an #EMailFormatter + * + * Clear the list of headers to be displayed. This will force all headers to + * be shown. + **/ +void +e_mail_formatter_clear_headers (EMailFormatter *formatter) +{ + EMailFormatterHeader *header; + + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + while ((header = g_queue_pop_head (formatter->priv->header_list)) != NULL) { + e_mail_formatter_header_free (header); + } +} + +/** + * e_mail_formatter_set_default_headers: + * @formatter: an #EMailFormatter + * + * Clear the list of headers and sets the default ones, e.g. "To", "From", "Cc" + * "Subject", etc... + */ +void +e_mail_formatter_set_default_headers (EMailFormatter *formatter) +{ + gint ii; + + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + /* Set the default headers */ + e_mail_formatter_clear_headers (formatter); + for (ii = 0; ii < G_N_ELEMENTS (default_headers); ii++) { + e_mail_formatter_add_header ( + formatter, default_headers[ii].name, NULL, + default_headers[ii].flags); + } +} + +/** + * e_mail_formatter_add_header: + * @formatter: + * @name: The name of the header, as it will appear during output. + * @value: Value of the header. Can be %NULL. + * @flags: EM_FORMAT_HEAD_* defines to control display attributes. + * + * Add a specific header to show. If any headers are set, they will + * be displayed in the order set by this function. Certain known + * headers included in this list will be shown using special + * formatting routines. + **/ +void +e_mail_formatter_add_header (EMailFormatter *formatter, + const gchar *name, + const gchar *value, + guint32 flags) +{ + EMailFormatterHeader *h; + + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (name && *name); + + h = e_mail_formatter_header_new (name, value); + h->flags = flags; + g_queue_push_tail (formatter->priv->header_list, h); +} + +void +e_mail_formatter_add_header_struct (EMailFormatter *formatter, + const EMailFormatterHeader *header) +{ + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (header && header->name); + + e_mail_formatter_add_header (formatter, header->name, header->value, header->flags); +} + +void e_mail_formatter_remove_header (EMailFormatter *formatter, + const gchar *name, + const gchar *value) +{ + GList *iter = NULL; + + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + g_return_if_fail (name && *name); + + iter = g_queue_peek_head_link (formatter->priv->header_list); + while (iter) { + EMailFormatterHeader *header = iter->data; + + if (!header->value || !*header->value) { + GList *next = iter->next; + if (g_strcmp0 (name, header->name) == 0) + g_queue_delete_link (formatter->priv->header_list, iter); + + iter = next; + continue; + } + + if (value && *value) { + if ((g_strcmp0 (name, header->name) == 0) && + (g_strcmp0 (value, header->value) == 0)) + break; + } else { + if (g_strcmp0 (name, header->name) == 0) + break; + } + + iter = iter->next; + } + + if (iter) { + e_mail_formatter_header_free (iter->data); + g_queue_delete_link (formatter->priv->header_list, iter); + } +} + +void +e_mail_formatter_remove_header_struct (EMailFormatter *formatter, + const EMailFormatterHeader *header) +{ + g_return_if_fail (header != NULL); + + e_mail_formatter_remove_header (formatter, header->name, header->value); +} + +EMailFormatterHeader * +e_mail_formatter_header_new (const gchar *name, + const gchar *value) +{ + EMailFormatterHeader *header; + + g_return_val_if_fail (name && *name, NULL); + + header = g_new0 (EMailFormatterHeader, 1); + header->name = g_strdup (name); + if (value && *value) + header->value = g_strdup (value); + + return header; +} + +void +e_mail_formatter_header_free (EMailFormatterHeader *header) +{ + g_return_if_fail (header); + + if (header->name) { + g_free (header->name); + header->name = NULL; + } + + if (header->value) { + g_free (header->value); + header->value = NULL; + } + + g_free (header); +} diff --git a/em-format/e-mail-formatter.h b/em-format/e-mail-formatter.h new file mode 100644 index 0000000000..aea18439b2 --- /dev/null +++ b/em-format/e-mail-formatter.h @@ -0,0 +1,266 @@ +/* + * e-mail-formatter.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 + * + */ + +#ifndef E_MAIL_FORMATTER_H_ +#define E_MAIL_FORMATTER_H_ + +#include +#include +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_FORMATTER \ + (e_mail_formatter_get_type ()) +#define E_MAIL_FORMATTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_FORMATTER, EMailFormatter)) +#define E_MAIL_FORMATTER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_FORMATTER, EMailFormatterClass)) +#define E_IS_MAIL_FORMATTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_FORMATTER)) +#define E_IS_MAIL_FORMATTER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_FORMATTER)) +#define E_MAIL_FORMATTER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterClass)) + +G_BEGIN_DECLS; + +typedef enum { + E_MAIL_FORMATTER_MODE_INVALID = -1, + E_MAIL_FORMATTER_MODE_NORMAL = 0, + E_MAIL_FORMATTER_MODE_SOURCE, + E_MAIL_FORMATTER_MODE_RAW, + E_MAIL_FORMATTER_MODE_PRINTING, + E_MAIL_FORMATTER_MODE_ALL_HEADERS +} EMailFormatterMode; + +typedef enum { + E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE = 1 << 0, + E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED = 1 << 1, + E_MAIL_FORMATTER_HEADER_FLAG_HTML = 1 << 2, + E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS = 1 << 3, + E_MAIL_FORMATTER_HEADER_FLAG_BOLD = 1 << 4, + E_MAIL_FORMATTER_HEADER_FLAG_NODEC = 1 << 5, + E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN = 1 << 6, + E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS = 1 << 7, + E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE = 1 << 8 +} EMailFormatterHeaderFlags; + +typedef enum { + E_MAIL_FORMATTER_COLOR_BODY, /* header area background */ + E_MAIL_FORMATTER_COLOR_CITATION, /* citation font color */ + E_MAIL_FORMATTER_COLOR_CONTENT, /* message area background */ + E_MAIL_FORMATTER_COLOR_FRAME, /* frame around message area */ + E_MAIL_FORMATTER_COLOR_HEADER, /* header font color */ + E_MAIL_FORMATTER_COLOR_TEXT, /* message font color */ + E_MAIL_FORMATTER_NUM_COLOR_TYPES +} EMailFormatterColorType; + +typedef struct _EMailFormatter EMailFormatter; +typedef struct _EMailFormatterClass EMailFormatterClass; +typedef struct _EMailFormatterPrivate EMailFormatterPrivate; +typedef struct _EMailFormatterHeader EMailFormatterHeader; +typedef struct _EMailFormatterContext EMailFormatterContext; + +struct _EMailFormatterHeader { + guint32 flags; /* E_MAIL_FORMATTER_HEADER_FLAG_ * */ + gchar *name; + gchar *value; +}; + +struct _EMailFormatterContext { + CamelMimeMessage *message; + CamelFolder *folder; + gchar *message_uid; + GSList *parts; + + EMailFormatterMode mode; + guint32 flags; +}; + +struct _EMailFormatter { + GObject parent; + EMailFormatterPrivate *priv; +}; + +struct _EMailFormatterClass { + GObjectClass parent_class; + + EMailFormatterExtensionRegistry *extension_registry; + guint32 text_html_flags; + + /* Colors should apply globally */ + GdkColor colors[E_MAIL_FORMATTER_NUM_COLOR_TYPES]; + + void (*run) (EMailFormatter *formatter, + EMailFormatterContext *context, + CamelStream *stream, + GCancellable *cancellable); + + EMailFormatterContext * (*create_context) (EMailFormatter *formatter); + + void (*free_context) (EMailFormatter *formatter, + EMailFormatterContext *context); + + void (*set_style) (EMailFormatter *formatter, + GtkStyle *style, + GtkStateType state); + +}; + +GType e_mail_formatter_get_type (void); + +EMailFormatter * + e_mail_formatter_new (void); + +void e_mail_formatter_format_sync (EMailFormatter *formatter, + EMailPartList *parts_list, + CamelStream *stream, + guint32 flags, + EMailFormatterMode mode, + GCancellable *cancellable); + +void e_mail_formatter_format (EMailFormatter *formatter, + EMailPartList *parts_list, + CamelStream *stream, + guint32 flags, + EMailFormatterMode mode, + GAsyncReadyCallback callback, + GCancellable *cancellable, + gpointer user_data); + +CamelStream * e_mail_formatter_format_finished + (EMailFormatter *formatter, + GAsyncResult *result, + GError *error); + +gboolean e_mail_formatter_format_as (EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + const gchar *as_mime_type, + GCancellable *cancellable); + +void e_mail_formatter_format_text (EMailFormatter *formatter, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable); +gchar * e_mail_formatter_get_html_header + (EMailFormatter *formatter); +EMailExtensionRegistry * + e_mail_formatter_get_extension_registry + (EMailFormatter *formatter); + +guint32 e_mail_formatter_get_text_format_flags + (EMailFormatter *formatter); + +const GdkColor * + e_mail_formatter_get_color (EMailFormatter *formatter, + EMailFormatterColorType type); +void e_mail_formatter_set_color (EMailFormatter *efh, + EMailFormatterColorType type, + const GdkColor *color); +void e_mail_formatter_set_style (EMailFormatter *formatter, + GtkStyle *style, + GtkStateType state); + +EMailImageLoadingPolicy + e_mail_formatter_get_image_loading_policy + (EMailFormatter *formatter); +void e_mail_formatter_set_image_loading_policy + (EMailFormatter *formatter, + EMailImageLoadingPolicy policy); + +gboolean e_mail_formatter_get_mark_citations + (EMailFormatter *formatter); +void e_mail_formatter_set_mark_citations + (EMailFormatter *formatter, + gboolean mark_citations); + +gboolean e_mail_formatter_get_only_local_photos + (EMailFormatter *formatter); +void e_mail_formatter_set_only_local_photos + (EMailFormatter *formatter, + gboolean only_local_photos); + +gboolean e_mail_formatter_get_show_sender_photo + (EMailFormatter *formatter); +void e_mail_formatter_set_show_sender_photo + (EMailFormatter *formatter, + gboolean show_sender_photo); + +gboolean e_mail_formatter_get_animate_images + (EMailFormatter *formatter); +void e_mail_formatter_set_animate_images + (EMailFormatter *formatter, + gboolean animate_images); + +gboolean e_mail_formatter_get_show_real_date + (EMailFormatter *formatter); +void e_mail_formatter_set_show_real_date + (EMailFormatter *formatter, + gboolean show_real_date); + +const gchar * e_mail_formatter_get_charset (EMailFormatter *formatter); +void e_mail_formatter_set_charset (EMailFormatter *formatter, + const gchar *charset); + +const gchar * e_mail_formatter_get_default_charset + (EMailFormatter *formatter); +void e_mail_formatter_set_default_charset + (EMailFormatter *formatter, + const gchar *charset); + +const GQueue * e_mail_formatter_get_headers (EMailFormatter *formatter); + +void e_mail_formatter_clear_headers (EMailFormatter *formatter); + +void e_mail_formatter_set_default_headers + (EMailFormatter *formatter); + +void e_mail_formatter_add_header (EMailFormatter *formatter, + const gchar *name, + const gchar *value, + guint32 flags); + +void e_mail_formatter_add_header_struct + (EMailFormatter *formatter, + const EMailFormatterHeader *header); + +void e_mail_formatter_remove_header (EMailFormatter *formatter, + const gchar *name, + const gchar *value); + +void e_mail_formatter_remove_header_struct + (EMailFormatter *formatter, + const EMailFormatterHeader *header); + +EMailFormatterHeader * + e_mail_formatter_header_new (const gchar *name, + const gchar *value); + +void e_mail_formatter_header_free (EMailFormatterHeader *header); + +G_END_DECLS + +#endif /* E_MAIL_FORMATTER_H_ */ diff --git a/em-format/e-mail-inline-filter.c b/em-format/e-mail-inline-filter.c new file mode 100644 index 0000000000..aa65708f7e --- /dev/null +++ b/em-format/e-mail-inline-filter.c @@ -0,0 +1,462 @@ +/* + * 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: + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "e-mail-inline-filter.h" +#include "e-mail-part-utils.h" + +#define d(x) + +G_DEFINE_TYPE (EMailInlineFilter, e_mail_inline_filter, CAMEL_TYPE_MIME_FILTER) + +enum { + EMIF_PLAIN, + EMIF_BINHEX, + EMIF_POSTSCRIPT, + EMIF_PGPSIGNED, + EMIF_PGPENCRYPTED +}; + +static const struct { + const gchar *type; + const gchar *subtype; + CamelTransferEncoding encoding; + guint plain : 1; +} emif_types[] = { + { "text", "plain", + CAMEL_TRANSFER_ENCODING_DEFAULT, 1 }, + + { "application", "mac-binhex40", + CAMEL_TRANSFER_ENCODING_7BIT, 0 }, + + { "application", "postscript", + CAMEL_TRANSFER_ENCODING_7BIT, 0 }, + + { "application", "x-inlinepgp-signed", + CAMEL_TRANSFER_ENCODING_DEFAULT, 0 }, + + { "application", "x-inlinepgp-encrypted", + CAMEL_TRANSFER_ENCODING_DEFAULT, 0 } +}; + +static CamelMimePart * +construct_part_from_stream (CamelStream *mem, + const GByteArray *data) +{ + CamelMimePart *part = NULL; + CamelMimeParser *parser; + + g_return_val_if_fail (mem != NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); + + if (data->len <= 13 || g_ascii_strncasecmp ((const gchar *) data->data, "Content-Type:", 13) != 0) + return NULL; + + parser = camel_mime_parser_new (); + camel_mime_parser_scan_from (parser, FALSE); + camel_mime_parser_scan_pre_from (parser, FALSE); + + if (camel_mime_parser_init_with_stream (parser, mem, NULL) != -1) { + part = camel_mime_part_new (); + if (!camel_mime_part_construct_from_parser_sync (part, parser, NULL, NULL)) { + g_object_unref (part); + part = NULL; + } + } + + g_object_unref (parser); + + return part; +} + +static void +inline_filter_add_part (EMailInlineFilter *emif, + const gchar *data, + gint len) +{ + CamelTransferEncoding encoding; + CamelContentType *content_type; + CamelDataWrapper *dw; + const gchar *mimetype; + CamelMimePart *part; + CamelStream *mem; + gchar *type; + + if (emif->state == EMIF_PLAIN || emif->state == EMIF_PGPSIGNED || emif->state == EMIF_PGPENCRYPTED) + encoding = emif->base_encoding; + else + encoding = emif_types[emif->state].encoding; + + g_byte_array_append (emif->data, (guchar *) data, len); + /* check the part will actually have content */ + if (emif->data->len <= 0) { + return; + } + + mem = camel_stream_mem_new_with_byte_array (emif->data); + part = construct_part_from_stream (mem, emif->data); + if (part) { + g_object_unref (mem); + emif->data = g_byte_array_new (); + g_free (emif->filename); + emif->filename = NULL; + + emif->parts = g_slist_append (emif->parts, part); + emif->found_any = TRUE; + + return; + } + + emif->data = g_byte_array_new (); + g_seekable_seek (G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL); + + dw = camel_data_wrapper_new (); + if (encoding == emif->base_encoding && (encoding == CAMEL_TRANSFER_ENCODING_BASE64 || encoding == CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE)) { + CamelMimeFilter *enc_filter = camel_mime_filter_basic_new (encoding == CAMEL_TRANSFER_ENCODING_BASE64 ? CAMEL_MIME_FILTER_BASIC_BASE64_ENC : CAMEL_MIME_FILTER_BASIC_QP_ENC); + CamelStream *filter_stream; + + filter_stream = camel_stream_filter_new (mem); + camel_stream_filter_add (CAMEL_STREAM_FILTER (filter_stream), enc_filter); + + /* properly encode content */ + camel_data_wrapper_construct_from_stream_sync ( + dw, filter_stream, NULL, NULL); + + g_object_unref (enc_filter); + g_object_unref (filter_stream); + } else { + camel_data_wrapper_construct_from_stream_sync ( + dw, mem, NULL, NULL); + } + g_object_unref (mem); + + if (emif_types[emif->state].plain && emif->base_type) { + /* create a copy */ + type = camel_content_type_format (emif->base_type); + content_type = camel_content_type_decode (type); + g_free (type); + } else { + /* we want to preserve all params */ + type = camel_content_type_format (emif->base_type); + content_type = camel_content_type_decode (type); + g_free (type); + + g_free (content_type->type); + g_free (content_type->subtype); + content_type->type = g_strdup (emif_types[emif->state].type); + content_type->subtype = g_strdup (emif_types[emif->state].subtype); + } + + camel_data_wrapper_set_mime_type_field (dw, content_type); + camel_content_type_unref (content_type); + dw->encoding = encoding; + + part = camel_mime_part_new (); + camel_medium_set_content ((CamelMedium *) part, dw); + camel_mime_part_set_encoding (part, encoding); + g_object_unref (dw); + + if (emif->filename) + camel_mime_part_set_filename (part, emif->filename); + + /* pre-snoop the mime type of unknown objects, and poke and hack it into place */ + if (camel_content_type_is(dw->mime_type, "application", "octet-stream") + && (mimetype = e_mail_part_snoop_type (part)) + && strcmp(mimetype, "application/octet-stream") != 0) { + camel_data_wrapper_set_mime_type (dw, mimetype); + camel_mime_part_set_content_type (part, mimetype); + if (emif->filename) + camel_mime_part_set_filename (part, emif->filename); + } + + g_free (emif->filename); + emif->filename = NULL; + + emif->parts = g_slist_append (emif->parts, part); +} + +static gint +inline_filter_scan (CamelMimeFilter *f, + gchar *in, + gsize len, + gint final) +{ + EMailInlineFilter *emif = (EMailInlineFilter *) f; + gchar *inptr = in, *inend = in + len; + gchar *data_start = in; + gchar *start = in; + + while (inptr < inend) { + gint rest_len; + gboolean set_null_byte = FALSE; + + start = inptr; + + while (inptr < inend && *inptr != '\n') + inptr++; + + if (inptr == inend && start == inptr) { + if (!final) { + camel_mime_filter_backup (f, start, inend - start); + inend = start; + } + break; + } + + rest_len = inend - start; + if (inptr < inend) { + *inptr++ = 0; + set_null_byte = TRUE; + } + + #define restore_inptr() G_STMT_START { if (set_null_byte) inptr[-1] = '\n'; } G_STMT_END + + switch (emif->state) { + case EMIF_PLAIN: + if (rest_len >= 45 && strncmp (start, "(This file must be converted with BinHex 4.0)", 45) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, start - data_start); + data_start = start; + emif->state = EMIF_BINHEX; + } else if (rest_len >= 11 && strncmp (start, "%!PS-Adobe-", 11) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, start - data_start); + data_start = start; + emif->state = EMIF_POSTSCRIPT; + } else if (rest_len >= 34 && strncmp (start, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, start - data_start); + data_start = start; + emif->state = EMIF_PGPSIGNED; + } else if (rest_len >= 27 && strncmp (start, "-----BEGIN PGP MESSAGE-----", 27) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, start - data_start); + data_start = start; + emif->state = EMIF_PGPENCRYPTED; + } + + break; + case EMIF_BINHEX: + if (inptr > (start + 1) && inptr[-2] == ':') { + restore_inptr (); + inline_filter_add_part (emif, data_start, inptr - data_start); + data_start = inptr; + emif->state = EMIF_PLAIN; + emif->found_any = TRUE; + } + break; + case EMIF_POSTSCRIPT: + if (rest_len >= 5 && strncmp (start, "%%EOF", 5) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, inptr - data_start); + data_start = inptr; + emif->state = EMIF_PLAIN; + emif->found_any = TRUE; + } + break; + case EMIF_PGPSIGNED: + if (rest_len >= 27 && strncmp (start, "-----END PGP SIGNATURE-----", 27) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, inptr - data_start); + data_start = inptr; + emif->state = EMIF_PLAIN; + emif->found_any = TRUE; + } + break; + case EMIF_PGPENCRYPTED: + if (rest_len >= 25 && strncmp (start, "-----END PGP MESSAGE-----", 25) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, inptr - data_start); + data_start = inptr; + emif->state = EMIF_PLAIN; + emif->found_any = TRUE; + } + break; + } + + restore_inptr (); + + #undef restore_inptr + } + + if (final) { + /* always stop as plain, especially when not read those tags fully */ + emif->state = EMIF_PLAIN; + + inline_filter_add_part (emif, data_start, inend - data_start); + } else if (start > data_start) { + /* backup the last line, in case the tag is divided within buffers */ + camel_mime_filter_backup (f, start, inend - start); + g_byte_array_append (emif->data, (guchar *) data_start, start - data_start); + } else { + g_byte_array_append (emif->data, (guchar *) data_start, inend - data_start); + } + + return 0; +} + +static void +inline_filter_finalize (GObject *object) +{ + EMailInlineFilter *emif = E_MAIL_INLINE_FILTER (object); + + if (emif->base_type) + camel_content_type_unref (emif->base_type); + + camel_mime_filter_reset (CAMEL_MIME_FILTER (object)); + g_byte_array_free (emif->data, TRUE); + g_free (emif->filename); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_mail_inline_filter_parent_class)->finalize (object); +} + +static void +inline_filter_filter (CamelMimeFilter *filter, + const gchar *in, + gsize len, + gsize prespace, + gchar **out, + gsize *outlen, + gsize *outprespace) +{ + inline_filter_scan (filter, (gchar *) in, len, FALSE); + + *out = (gchar *)in; + *outlen = len; + *outprespace = prespace; +} + +static void +inline_filter_complete (CamelMimeFilter *filter, + const gchar *in, + gsize len, + gsize prespace, + gchar **out, + gsize *outlen, + gsize *outprespace) +{ + inline_filter_scan (filter, (gchar *) in, len, TRUE); + + *out = (gchar *)in; + *outlen = len; + *outprespace = prespace; +} + +static void +inline_filter_reset (CamelMimeFilter *filter) +{ + EMailInlineFilter *emif = E_MAIL_INLINE_FILTER (filter); + GSList *l; + + l = emif->parts; + while (l) { + GSList *n = l->next; + + g_object_unref (l->data); + g_slist_free_1 (l); + + l = n; + } + emif->parts = NULL; + g_byte_array_set_size (emif->data, 0); + emif->found_any = FALSE; +} + +static void +e_mail_inline_filter_class_init (EMailInlineFilterClass *class) +{ + GObjectClass *object_class; + CamelMimeFilterClass *mime_filter_class; + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = inline_filter_finalize; + + mime_filter_class = CAMEL_MIME_FILTER_CLASS (class); + mime_filter_class->filter = inline_filter_filter; + mime_filter_class->complete = inline_filter_complete; + mime_filter_class->reset = inline_filter_reset; +} + +static void +e_mail_inline_filter_init (EMailInlineFilter *emif) +{ + emif->data = g_byte_array_new (); + emif->found_any = FALSE; +} + +/** + * em_inline_filter_new: + * @base_encoding: The base transfer-encoding of the + * raw data being processed. + * @base_type: The base content-type of the raw data, should always be + * text/plain. + * + * Create a filter which will scan a (text) stream for + * embedded parts. You can then retrieve the contents + * as a CamelMultipart object. + * + * Return value: + **/ +EMailInlineFilter * +e_mail_inline_filter_new (CamelTransferEncoding base_encoding, + CamelContentType *base_type) +{ + EMailInlineFilter *emif; + + emif = g_object_new (E_TYPE_MAIL_INLINE_FILTER, NULL); + emif->base_encoding = base_encoding; + if (base_type) { + emif->base_type = base_type; + camel_content_type_ref (emif->base_type); + } + + return emif; +} + +CamelMultipart * +e_mail_inline_filter_get_multipart (EMailInlineFilter *emif) +{ + GSList *l = emif->parts; + CamelMultipart *mp; + + mp = camel_multipart_new (); + while (l) { + camel_multipart_add_part (mp, l->data); + l = l->next; + } + + return mp; +} + +gboolean +e_mail_inline_filter_found_any (EMailInlineFilter *emif) +{ + g_return_val_if_fail (emif != NULL, FALSE); + + return emif->found_any; +} diff --git a/em-format/e-mail-inline-filter.h b/em-format/e-mail-inline-filter.h new file mode 100644 index 0000000000..ff8248c681 --- /dev/null +++ b/em-format/e-mail-inline-filter.h @@ -0,0 +1,82 @@ +/* + * + * 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: + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_INLINE_FILTER_H +#define E_MAIL_INLINE_FILTER_H + +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_INLINE_FILTER \ + (e_mail_inline_filter_get_type ()) +#define E_MAIL_INLINE_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_INLINE_FILTER, EMailInlineFilter)) +#define E_MAIL_INLINE_FILTER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_INLINE_FILTER, EMailInlineFilterClass)) +#define E_MAIL_IS_INLINE_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_INLINE_FILTER)) +#define E_MAIL_IS_INLINE_FILTER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_INLINE_FILTER)) +#define E_MAIL_INLINE_FILTER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_INLINE_FILTER, EMailInlineFilterClass)) + +G_BEGIN_DECLS + +typedef struct _EMailInlineFilter EMailInlineFilter; +typedef struct _EMailInlineFilterClass EMailInlineFilterClass; + +struct _EMailInlineFilter { + CamelMimeFilter filter; + + gint state; + + CamelTransferEncoding base_encoding; + CamelContentType *base_type; + + GByteArray *data; + gchar *filename; + GSList *parts; + + gboolean found_any; +}; + +struct _EMailInlineFilterClass { + CamelMimeFilterClass filter_class; +}; + +GType e_mail_inline_filter_get_type (void); +EMailInlineFilter * + e_mail_inline_filter_new (CamelTransferEncoding base_encoding, + CamelContentType *type); +CamelMultipart *e_mail_inline_filter_get_multipart + (EMailInlineFilter *emif); +gboolean e_mail_inline_filter_found_any (EMailInlineFilter *emif); + +G_END_DECLS + +#endif /* E_MAIL_INLINE_FILTER_H */ diff --git a/em-format/e-mail-parser-application-mbox.c b/em-format/e-mail-parser-application-mbox.c new file mode 100644 index 0000000000..c396c48416 --- /dev/null +++ b/em-format/e-mail-parser-application-mbox.c @@ -0,0 +1,213 @@ +/* + * e-mail-parser-application-mbox.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +typedef struct _EMailParserApplicationMBox { + GObject parent; +} EMailParserApplicationMBox; + +typedef struct _EMailParserApplicationMBoxClass { + GObjectClass parent_class; +} EMailParserApplicationMBoxClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserApplicationMBox, + e_mail_parser_application_mbox, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "application/mbox", + NULL }; + +static GSList * +empe_app_mbox_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + CamelMimeParser *mime_parser; + CamelStream *mem_stream; + camel_mime_parser_state_t state; + gint old_len; + gint messages; + GSList *parts; + GError *error; + + if (g_cancellable_is_cancelled (cancellable)) + return NULL; + + /* Extract messages from the application/mbox part and + * render them as a flat list of messages. */ + + /* XXX If the mbox has multiple messages, maybe render them + * as a multipart/digest so each message can be expanded + * or collapsed individually. + * + * See attachment_handler_mail_x_uid_list() for example. */ + + /* XXX This is based on em_utils_read_messages_from_stream(). + * Perhaps refactor that function to return an array of + * messages instead of assuming we want to append them + * to a folder? */ + + mime_parser = camel_mime_parser_new (); + camel_mime_parser_scan_from (mime_parser, TRUE); + + mem_stream = camel_stream_mem_new (); + camel_data_wrapper_decode_to_stream_sync ( + camel_medium_get_content (CAMEL_MEDIUM (part)), + mem_stream, NULL, NULL); + g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, cancellable, NULL); + + error = NULL; + camel_mime_parser_init_with_stream (mime_parser, mem_stream, &error); + if (error) { + parts = e_mail_parser_error (parser, cancellable, + _("Error parsing MBOX part: %s"), + error->message ? + error->message : + _("Unknown error")); + g_clear_error (&error); + g_object_unref (mem_stream); + g_object_unref (mime_parser); + return parts; + } + + g_object_unref (mem_stream); + + old_len = part_id->len; + + /* Extract messages from the mbox. */ + messages = 0; + state = camel_mime_parser_step (mime_parser, NULL, NULL); + + parts = NULL; + while (state == CAMEL_MIME_PARSER_STATE_FROM) { + CamelMimeMessage *message; + CamelMimePart *opart; + GSList *new_parts; + + message = camel_mime_message_new (); + opart = CAMEL_MIME_PART (message); + + if (!camel_mime_part_construct_from_parser_sync ( + opart, mime_parser, NULL, NULL)) { + g_object_unref (message); + break; + } + + g_string_append_printf (part_id, ".mbox.%d", messages); + + new_parts = e_mail_parser_parse_part_as ( + parser, CAMEL_MIME_PART (message), + part_id, "message/rfc822", cancellable); + + /* Wrap every message as attachment */ + new_parts = e_mail_parser_wrap_as_attachment ( + parser, CAMEL_MIME_PART (message), + new_parts, part_id, cancellable); + + /* Inline all messages in mbox */ + if (new_parts && new_parts->data) { + EMailPart *p = new_parts->data; + + p->force_inline = TRUE; + } + + parts = g_slist_concat (parts, new_parts); + + g_string_truncate (part_id, old_len); + + g_object_unref (message); + + /* Skip past CAMEL_MIME_PARSER_STATE_FROM_END. */ + camel_mime_parser_step (mime_parser, NULL, NULL); + + state = camel_mime_parser_step (mime_parser, NULL, NULL); + + messages++; + } + + g_object_unref (mime_parser); + + return parts; +} + +static guint32 +empe_app_mbox_get_flags (EMailParserExtension *extension) +{ + return E_MAIL_PARSER_EXTENSION_INLINE | + E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE; +} + +static const gchar ** +empe_app_mbox_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_application_mbox_class_init (EMailParserApplicationMBoxClass *klass) +{ + e_mail_parser_application_mbox_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *interface) +{ + interface->parse = empe_app_mbox_parse; + interface->get_flags = empe_app_mbox_get_flags; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *interface) +{ + interface->mime_types = empe_app_mbox_mime_types; +} + +static void +e_mail_parser_application_mbox_init (EMailParserApplicationMBox *self) +{ +} diff --git a/em-format/e-mail-parser-application-smime.c b/em-format/e-mail-parser-application-smime.c new file mode 100644 index 0000000000..12bce2fa56 --- /dev/null +++ b/em-format/e-mail-parser-application-smime.c @@ -0,0 +1,199 @@ +/* + * e-mail-parser-application-xpkcs7mime.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +typedef struct _EMailParserApplicationSMIME { + GObject parent; +} EMailParserApplicationSMIME; + +typedef struct _EMailParserAppplicationSMIMEClass { + GObjectClass parent_class; +} EMailParserApplicationSMIMEClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserApplicationSMIME, + e_mail_parser_application_smime, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "application/xpkcs7mime", + "application/x-pkcs7-mime", + "application/pkcs7-mime", + "application/pkcs7-signature", + "application/xpkcs7-signature", + NULL }; + +static GSList * +empe_app_smime_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + CamelCipherContext *context; + CamelMimePart *opart; + CamelCipherValidity *valid; + GError *local_error = NULL; + GSList *parts, *iter; + CamelContentType *ct; + + if (g_cancellable_is_cancelled (cancellable)) + return NULL; + + ct = camel_mime_part_get_content_type (part); + if (camel_content_type_is (ct, "application", "pkcs7-signature") || + camel_content_type_is (ct, "application", "xpkcs7-signature")) { + return g_slist_alloc (); + } + + context = camel_smime_context_new (e_mail_parser_get_session (parser)); + + opart = camel_mime_part_new (); + valid = camel_cipher_context_decrypt_sync ( + context, part, opart, + cancellable, &local_error); + + e_mail_part_preserve_charset_in_content_type (part, opart); + + if (valid == NULL) { + parts = e_mail_parser_error ( + parser, cancellable, + _("Could not parse S/MIME message: %s"), + local_error->message ? + local_error->message : + _("Unknown error")); + g_clear_error (&local_error); + } else { + gint len = part_id->len; + + g_string_append (part_id, ".encrypted"); + + parts = e_mail_parser_parse_part ( + parser, opart, part_id, cancellable); + + g_string_truncate (part_id, len); + + /* Update validity flags of all the involved subp-arts */ + for (iter = parts; iter; iter = iter->next) { + + EMailPart *mail_part = iter->data; + if (!mail_part) + continue; + + e_mail_part_update_validity (mail_part, valid, + E_MAIL_PART_VALIDITY_ENCRYPTED | + E_MAIL_PART_VALIDITY_SMIME); + + } + + /* Add a widget with details about the encryption, but only when + * the encrypted isn't itself secured, in that case it has created + * the button itself */ + if (!e_mail_part_is_secured (opart)) { + GSList *button; + EMailPart *mail_part; + g_string_append (part_id, ".encrypted.button"); + + button = e_mail_parser_parse_part_as ( + parser, part, part_id, + "application/vnd.evolution.widget.secure-button", + cancellable); + if (button && button->data) { + mail_part = button->data; + + e_mail_part_update_validity (mail_part, valid, + E_MAIL_PART_VALIDITY_ENCRYPTED | + E_MAIL_PART_VALIDITY_SMIME); + } + + parts = g_slist_concat (parts, button); + + g_string_truncate (part_id, len); + } + + camel_cipher_validity_free (valid); + } + + g_object_unref (opart); + g_object_unref (context); + + return parts; +} + +static guint32 +empe_app_smime_get_flags (EMailParserExtension *extension) +{ + return E_MAIL_PARSER_EXTENSION_INLINE; +} + +static const gchar ** +empe_application_smime_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_application_smime_class_init (EMailParserApplicationSMIMEClass *klass) +{ + e_mail_parser_application_smime_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *interface) +{ + interface->parse = empe_app_smime_parse; + interface->get_flags = empe_app_smime_get_flags; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *interface) +{ + interface->mime_types = empe_application_smime_mime_types; +} + +static void +e_mail_parser_application_smime_init (EMailParserApplicationSMIME *parser) +{ + +} diff --git a/em-format/e-mail-parser-attachment-bar.c b/em-format/e-mail-parser-attachment-bar.c new file mode 100644 index 0000000000..009869d43c --- /dev/null +++ b/em-format/e-mail-parser-attachment-bar.c @@ -0,0 +1,120 @@ +/* + * e-mail-parser-attachment-bar.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "e-mail-format-extensions.h" + +#include +#include "e-mail-part-attachment-bar.h" + +#include +#include +#include + +#include + +#include + +static void +mail_part_attachment_bar_free (EMailPart *part) +{ + EMailPartAttachmentBar *empab = (EMailPartAttachmentBar *) part; + + g_clear_object (&empab->store); +} + +/******************************************************************************/ + +typedef struct _EMailParserAttachmentBar { + GObject parent; +} EMailParserAttachmentBar; + +typedef struct _EMailParserAttachmentBarClass { + GObjectClass parent_class; +} EMailParserAttachmentBarClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserAttachmentBar, + e_mail_parser_attachment_bar, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)) + +static const gchar *parser_mime_types[] = { "application/vnd.evolution.widget.attachment-bar", NULL }; + +static GSList * +empe_attachment_bar_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EMailPartAttachmentBar *empab; + gint len; + + len = part_id->len; + g_string_append (part_id, ".attachment-bar"); + empab = (EMailPartAttachmentBar *) e_mail_part_subclass_new ( + part, part_id->str, sizeof (EMailPartAttachmentBar), + (GFreeFunc) mail_part_attachment_bar_free); + empab->parent.mime_type = g_strdup ("application/vnd.evolution.widget.attachment-bar"); + empab->store = E_ATTACHMENT_STORE (e_attachment_store_new ()); + g_string_truncate (part_id, len); + + return g_slist_append (NULL, empab); +} + +static const gchar ** +empe_attachment_bar_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_attachment_bar_class_init (EMailParserAttachmentBarClass *klass) +{ + e_mail_parser_attachment_bar_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_attachment_bar_parse; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_attachment_bar_mime_types; +} + +static void +e_mail_parser_attachment_bar_init (EMailParserAttachmentBar *parser) +{ + +} diff --git a/em-format/e-mail-parser-extension.c b/em-format/e-mail-parser-extension.c new file mode 100644 index 0000000000..589fae31f7 --- /dev/null +++ b/em-format/e-mail-parser-extension.c @@ -0,0 +1,101 @@ +/* + * e-mail-parser-extension.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 + * + */ + +#include + +#include "e-mail-parser-extension.h" + +G_DEFINE_INTERFACE ( + EMailParserExtension, + e_mail_parser_extension, + E_TYPE_MAIL_EXTENSION) + +/** + * EMailParserExtension: + * + * The #EMailParserExtension is an abstract interface for all extensions for + * #EMailParser. + */ + +static void +e_mail_parser_extension_default_init (EMailParserExtensionInterface *iface) +{ + +} + +/** + * e_mail_parser_extension_parse + * @extension: an #EMailParserExtension + * @parser: a #EMailParser + * @mime_part: (allow-none) a #CamelMimePart to parse + * @part_id: a #GString to which parser will append ID of the parsed part. + * @flags: #EMailParserFlags + * @cancellable: (allow-none) A #GCancellable + * + * A virtual function reimplemented in all mail parser extensions. The function + * decodes and parses the @mime_part, creating one or more #EMailParts. + * + * When the function is unable to parse the @mime_part (either because it's broken + * or because it is a different mimetype then the extension is specialized for), the + * function will return @NULL indicating the #EMailParser, that it should pick + * another extension. + * + * When the @mime_part contains for example multipart/mixed of one RFC822 message + * with an attachment and of one image, then parser must make sure that the + * returned #GSList is correctly ordered: + * + * part1.rfc822.plain_text + * part1.rfc822.attachment + * part2.image + * + * Implementation of this function must be thread-safe. + * + * Return value: Returns #GSList of #EMailParts when the part was succesfully + * parsed, returns @NULL when the parser is not able to parse the part. + */ +GSList * +e_mail_parser_extension_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *mime_part, + GString *part_id, + GCancellable *cancellable) +{ + EMailParserExtensionInterface *interface; + + g_return_val_if_fail (E_IS_MAIL_PARSER_EXTENSION (extension), NULL); + g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL); + + interface = E_MAIL_PARSER_EXTENSION_GET_INTERFACE (extension); + g_return_val_if_fail (interface->parse != NULL, NULL); + + return interface->parse (extension, parser, mime_part, part_id, cancellable); +} + +guint32 +e_mail_parser_extension_get_flags (EMailParserExtension *extension) +{ + EMailParserExtensionInterface *interface; + + g_return_val_if_fail (E_IS_MAIL_PARSER_EXTENSION (extension), 0); + + interface = E_MAIL_PARSER_EXTENSION_GET_INTERFACE (extension); + if (interface->get_flags == NULL) + return 0; + + return interface->get_flags (extension); +} diff --git a/em-format/e-mail-parser-extension.h b/em-format/e-mail-parser-extension.h new file mode 100644 index 0000000000..0dcff76212 --- /dev/null +++ b/em-format/e-mail-parser-extension.h @@ -0,0 +1,86 @@ +/* + * e-mail-parser-extension.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 + * + */ + +#ifndef E_MAIL_PARSER_EXTENSION_H +#define E_MAIL_PARSER_EXTENSION_H + +#include +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_PARSER_EXTENSION \ + (e_mail_parser_extension_get_type ()) +#define E_MAIL_PARSER_EXTENSION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_PARSER_EXTENSION, EMailParserExtension)) +#define E_MAIL_PARSER_EXTENSION_INTERFACE(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_PARSER_EXTENSION, EMailParserExtensionInterface)) +#define E_IS_MAIL_PARSER_EXTENSION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_PARSER_EXTENSION)) +#define E_IS_MAIL_PARSER_EXTENSION_INTERFACE(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_PARSER_EXTENSION)) +#define E_MAIL_PARSER_EXTENSION_GET_INTERFACE(obj) \ + (G_TYPE_INSTANCE_GET_INTERFACE \ + ((obj), E_TYPE_MAIL_PARSER_EXTENSION, EMailParserExtensionInterface)) + +#define EMP_EXTENSION_GET_PARSER(e) \ + E_MAIL_PARSER (e_extension_get_extensible (E_EXTENSION (e))) + +G_BEGIN_DECLS + +typedef struct _EMailParserExtension EMailParserExtension; +typedef struct _EMailParserExtensionInterface EMailParserExtensionInterface; + +typedef enum { + E_MAIL_PARSER_EXTENSION_INLINE = 1 << 0, /* Don't parse as attachment */ + E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION = 1 << 1, /* Always expand */ + E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE = 1 << 2 /* Always check what's inside */ +} EMailParserExtensionFlags; + +struct _EMailParserExtensionInterface { + EMailExtensionInterface parent_interface; + + GSList * (*parse) (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *mime_part, + GString *part_id, + GCancellable *cancellable); + + guint32 (*get_flags) (EMailParserExtension *extension); + +}; + +GType e_mail_parser_extension_get_type + (void); + +GSList * e_mail_parser_extension_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *mime_part, + GString *part_id, + GCancellable *cancellable); + +guint32 e_mail_parser_extension_get_flags + (EMailParserExtension *extension); + +G_END_DECLS + +#endif /* E_MAIL_PARSER_EXTENSION_H */ diff --git a/em-format/e-mail-parser-headers.c b/em-format/e-mail-parser-headers.c new file mode 100644 index 0000000000..06f28746f0 --- /dev/null +++ b/em-format/e-mail-parser-headers.c @@ -0,0 +1,112 @@ +/* + * e-mail-parser-headers.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include + +#include +#include +#include +#include + +#include + +#include + +typedef struct _EMailParserHeaders { + GObject parent; +} EMailParserHeaders; + +typedef struct _EMailParserHeadersClass { + GObjectClass parent_class; +} EMailParserHeadersClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserHeaders, + e_mail_parser_headers, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar *parser_mime_types[] = { "application/vnd.evolution.headers", NULL }; + +static GSList * +empe_headers_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EMailPart *mail_part; + gint len; + + if (g_cancellable_is_cancelled (cancellable)) + return NULL; + + len = part_id->len; + g_string_append (part_id, ".headers"); + + mail_part = e_mail_part_new (part, part_id->str); + mail_part->mime_type = g_strdup ("application/vnd.evolution.headers"); + g_string_truncate (part_id, len); + + return g_slist_append (NULL, mail_part); +} + +static const gchar ** +empe_headers_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_headers_class_init (EMailParserHeadersClass *klass) +{ + e_mail_parser_headers_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_headers_parse; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_headers_mime_types; +} + +static void +e_mail_parser_headers_init (EMailParserHeaders *parser) +{ + +} diff --git a/em-format/e-mail-parser-image.c b/em-format/e-mail-parser-image.c new file mode 100644 index 0000000000..2fb1fdff2f --- /dev/null +++ b/em-format/e-mail-parser-image.c @@ -0,0 +1,147 @@ +/* + * e-mail-parser-image.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include + +#include +#include + +typedef struct _EMailParserImage { + GObject parent; +} EMailParserImage; + +typedef struct _EMailParserImageClass { + GObjectClass parent_class; +} EMailParserImageClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserImage, + e_mail_parser_image, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar *parser_mime_types[] = { "image/gif", + "image/jpeg", + "image/png", + "image/x-png", + "image/x-bmp", + "image/bmp", + "image/svg", + "image/x-cmu-raster", + "image/x-ico", + "image/x-portable-anymap", + "image/x-portable-bitmap", + "image/x-portable-graymap", + "image/x-portable-pixmap", + "image/x-xpixmap", + "image/jpg", + "image/pjpeg", + NULL }; + +static GSList * +empe_image_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EMailPart *mail_part; + const gchar *tmp; + gchar *cid; + gint len; + CamelContentType *ct; + + if (g_cancellable_is_cancelled (cancellable)) + return NULL; + + tmp = camel_mime_part_get_content_id (part); + if (tmp) { + cid = g_strdup_printf ("cid:%s", tmp); + } else { + cid = NULL; + } + + len = part_id->len; + g_string_append (part_id, ".image"); + + ct = camel_mime_part_get_content_type (part); + + mail_part = e_mail_part_new (part, part_id->str); + mail_part->is_attachment = TRUE; + mail_part->cid = cid; + mail_part->mime_type = ct ? camel_content_type_simple (ct) : g_strdup ("image/*"); + mail_part->is_hidden = (cid != NULL); + + g_string_truncate (part_id, len); + + if (!cid) { + return e_mail_parser_wrap_as_attachment ( + parser, part, g_slist_append (NULL, mail_part), + part_id, cancellable); + } + + return g_slist_append (NULL, mail_part); +} + +static const gchar ** +empe_image_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_image_class_init (EMailParserImageClass *klass) +{ + e_mail_parser_image_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_image_parse; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_image_mime_types; +} + +static void +e_mail_parser_image_init (EMailParserImage *parser) +{ + +} diff --git a/em-format/e-mail-parser-inlinepgp-encrypted.c b/em-format/e-mail-parser-inlinepgp-encrypted.c new file mode 100644 index 0000000000..5395b7be7e --- /dev/null +++ b/em-format/e-mail-parser-inlinepgp-encrypted.c @@ -0,0 +1,205 @@ +/* + * e-mail-parser-inlinepgp-encrypted.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include + +#include +#include + +#include + +typedef struct _EMailParserInlinePGPEncrypted { + GObject parent; +} EMailParserInlinePGPEncrypted; + +typedef struct _EMailParserInlinePGPEncryptedClass { + GObjectClass parent_class; +} EMailParserInlinePGPEncryptedClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserInlinePGPEncrypted, + e_mail_parser_inline_pgp_encrypted, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "application/x-inlinepgp-encrypted", + NULL }; + +static GSList * +empe_inlinepgp_encrypted_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + CamelCipherContext *cipher; + CamelCipherValidity *valid; + CamelMimePart *opart; + CamelDataWrapper *dw; + gchar *mime_type; + gint len; + GError *local_error = NULL; + GSList *parts, *iter; + + if (g_cancellable_is_cancelled (cancellable)) + return NULL; + + cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); + + opart = camel_mime_part_new (); + + /* Decrypt the message */ + valid = camel_cipher_context_decrypt_sync ( + cipher, part, opart, cancellable, &local_error); + + if (!valid) { + parts = e_mail_parser_error ( + parser, cancellable, + _("Could not parse PGP message: %s"), + local_error->message ? + local_error->message : + _("Unknown error")); + g_clear_error (&local_error); + + parts = g_slist_concat (parts, + e_mail_parser_parse_part_as (parser, + part, part_id, + "application/vnd.evolution.source", + cancellable)); + + g_object_unref (cipher); + g_object_unref (opart); + return parts; + } + + dw = camel_medium_get_content ((CamelMedium *) opart); + mime_type = camel_data_wrapper_get_mime_type (dw); + + /* this ensures to show the 'opart' as inlined, if possible */ + if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) { + const gchar *snoop = e_mail_part_snoop_type (opart); + + if (snoop) + camel_data_wrapper_set_mime_type (dw, snoop); + } + + e_mail_part_preserve_charset_in_content_type (part, opart); + g_free (mime_type); + + /* Pass it off to the real formatter */ + len = part_id->len; + g_string_append (part_id, ".inlinepgp_encrypted"); + + parts = e_mail_parser_parse_part_as ( + parser, opart, part_id, + camel_data_wrapper_get_mime_type (dw), cancellable); + + g_string_truncate (part_id, len); + + for (iter = parts; iter; iter = iter->next) { + EMailPart *mail_part; + + mail_part = iter->data; + if (!mail_part) + continue; + + e_mail_part_update_validity (mail_part, valid, + E_MAIL_PART_VALIDITY_ENCRYPTED | + E_MAIL_PART_VALIDITY_PGP); + } + + /* Add a widget with details about the encryption, but only when + * the encrypted isn't itself secured, in that case it has created + * the button itself */ + if (!e_mail_part_is_secured (opart)) { + GSList *button; + EMailPart *mail_part; + g_string_append (part_id, ".inlinepgp_encrypted.button"); + + button = e_mail_parser_parse_part_as ( + parser, part, part_id, + "application/vnd.evolution.widget.secure-button", + cancellable); + if (button && button->data) { + mail_part = button->data; + + e_mail_part_update_validity (mail_part, valid, + E_MAIL_PART_VALIDITY_ENCRYPTED | + E_MAIL_PART_VALIDITY_PGP); + } + + parts = g_slist_concat (parts, button); + + g_string_truncate (part_id, len); + } + + /* Clean Up */ + camel_cipher_validity_free (valid); + g_object_unref (opart); + g_object_unref (cipher); + + return parts; +} + +static const gchar ** +empe_inlinepgp_encrypted_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_inline_pgp_encrypted_class_init (EMailParserInlinePGPEncryptedClass *klass) +{ + e_mail_parser_inline_pgp_encrypted_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_inlinepgp_encrypted_parse; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_inlinepgp_encrypted_mime_types; +} + +static void +e_mail_parser_inline_pgp_encrypted_init (EMailParserInlinePGPEncrypted *parser) +{ + +} diff --git a/em-format/e-mail-parser-inlinepgp-signed.c b/em-format/e-mail-parser-inlinepgp-signed.c new file mode 100644 index 0000000000..d90dcddd2e --- /dev/null +++ b/em-format/e-mail-parser-inlinepgp-signed.c @@ -0,0 +1,230 @@ +/* + * e-mail-parser-inlinepgp-signed.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include +#include + +#include +#include + +#include + +typedef struct _EMailParserInlinePGPSigned { + GObject parent; +} EMailParserInlinePGPSigned; + +typedef struct _EMailParserInlinePGPSignedClass { + GObjectClass parent_class; +} EMailParserInlinePGPSignedClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserInlinePGPSigned, + e_mail_parser_inline_pgp_signed, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "application/x-inlinepgp-signed", + NULL }; + +static GSList * +empe_inlinepgp_signed_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + CamelStream *filtered_stream; + CamelMimeFilterPgp *pgp_filter; + CamelContentType *content_type; + CamelCipherContext *cipher; + CamelCipherValidity *valid; + CamelDataWrapper *dw; + CamelMimePart *opart; + CamelStream *ostream; + gchar *type; + gint len; + GError *local_error = NULL; + GByteArray *ba; + GSList *parts, *iter; + + if (g_cancellable_is_cancelled (cancellable)) + return NULL; + + cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); + + /* Verify the signature of the message */ + valid = camel_cipher_context_verify_sync ( + cipher, part, cancellable, &local_error); + if (!valid) { + parts = e_mail_parser_error ( + parser, cancellable, + _("Error verifying signature: %s"), + local_error->message ? + local_error->message : + _("Unknown error")); + + g_clear_error (&local_error); + + parts = g_slist_concat (parts, + e_mail_parser_parse_part_as ( + parser, part, part_id, + "application/vnd.evolution.source", + cancellable)); + + g_object_unref (cipher); + return parts; + } + + /* Setup output stream */ + ostream = camel_stream_mem_new (); + filtered_stream = camel_stream_filter_new (ostream); + + /* Add PGP header / footer filter */ + pgp_filter = (CamelMimeFilterPgp *) camel_mime_filter_pgp_new (); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filtered_stream), + CAMEL_MIME_FILTER (pgp_filter)); + g_object_unref (pgp_filter); + + /* Pass through the filters that have been setup */ + dw = camel_medium_get_content ((CamelMedium *) part); + camel_data_wrapper_decode_to_stream_sync ( + dw, (CamelStream *) filtered_stream, cancellable, NULL); + camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL); + g_object_unref (filtered_stream); + + /* Create a new text/plain MIME part containing the signed + * content preserving the original part's Content-Type params. */ + content_type = camel_mime_part_get_content_type (part); + type = camel_content_type_format (content_type); + content_type = camel_content_type_decode (type); + g_free (type); + + g_free (content_type->type); + content_type->type = g_strdup ("text"); + g_free (content_type->subtype); + content_type->subtype = g_strdup ("plain"); + type = camel_content_type_format (content_type); + camel_content_type_unref (content_type); + + ba = camel_stream_mem_get_byte_array ((CamelStreamMem *) ostream); + opart = camel_mime_part_new (); + camel_mime_part_set_content (opart, (gchar *) ba->data, ba->len, type); + g_free (type); + + len = part_id->len; + g_string_append (part_id, ".inlinepgp_signed"); + + parts = e_mail_parser_parse_part ( + parser, opart, part_id, cancellable); + + for (iter = parts; iter; iter = iter->next) { + EMailPart *mail_part; + + mail_part = iter->data; + if (!mail_part) + continue; + + e_mail_part_update_validity (mail_part, valid, + E_MAIL_PART_VALIDITY_SIGNED | + E_MAIL_PART_VALIDITY_PGP); + } + + g_string_truncate (part_id, len); + + /* Add a widget with details about the encryption, but only when + * the encrypted isn't itself secured, in that case it has created + * the button itself */ + if (!e_mail_part_is_secured (opart)) { + GSList *button; + EMailPart *mail_part; + g_string_append (part_id, ".inlinepgp_signed.button"); + + button = e_mail_parser_parse_part_as ( + parser, part, part_id, + "application/vnd.evolution.widget.secure-button", + cancellable); + if (button && button->data) { + mail_part = button->data; + + e_mail_part_update_validity (mail_part, valid, + E_MAIL_PART_VALIDITY_SIGNED | + E_MAIL_PART_VALIDITY_PGP); + } + + parts = g_slist_concat (parts, button); + + g_string_truncate (part_id, len); + } + + /* Clean Up */ + camel_cipher_validity_free (valid); + g_object_unref (dw); + g_object_unref (opart); + g_object_unref (ostream); + g_object_unref (cipher); + + return parts; +} + +static const gchar ** +empe_inlinepgp_signed_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_inline_pgp_signed_class_init (EMailParserInlinePGPSignedClass *klass) +{ + e_mail_parser_inline_pgp_signed_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_inlinepgp_signed_parse; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_inlinepgp_signed_mime_types; +} + +static void +e_mail_parser_inline_pgp_signed_init (EMailParserInlinePGPSigned *parser) +{ + +} diff --git a/em-format/e-mail-parser-message-deliverystatus.c b/em-format/e-mail-parser-message-deliverystatus.c new file mode 100644 index 0000000000..feae7c2cf5 --- /dev/null +++ b/em-format/e-mail-parser-message-deliverystatus.c @@ -0,0 +1,116 @@ +/* + * e-mail-parser-message-deliverystatus.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include + +#include +#include +#include + +#include + +#include + +typedef struct _EMailParserMessageDeliveryStatus { + GObject parent; +} EMailParserMessageDeliveryStatus; + +typedef struct _EMailParserMessageDeliveryStatusClass { + GObjectClass parent_class; +} EMailParserMessageDeliveryStatusClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserMessageDeliveryStatus, + e_mail_parser_message_delivery_status, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "message/delivery-status", + NULL }; + +static GSList * +empe_msg_deliverystatus_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EMailPart *mail_part; + gsize len; + + if (g_cancellable_is_cancelled (cancellable)) + return NULL; + + len = part_id->len; + g_string_append (part_id, ".delivery-status"); + mail_part = e_mail_part_new (part, part_id->str); + mail_part->mime_type = g_strdup ("text/plain"); + + g_string_truncate (part_id, len); + + /* The only reason for having a separate parser for + * message/delivery-status is to display the part as an attachment */ + return e_mail_parser_wrap_as_attachment ( + parser, part, g_slist_append (NULL, mail_part), + part_id, cancellable); +} + +static const gchar ** +empe_msg_deliverystatus_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_message_delivery_status_class_init (EMailParserMessageDeliveryStatusClass *klass) +{ + e_mail_parser_message_delivery_status_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_msg_deliverystatus_parse; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_msg_deliverystatus_mime_types; +} + +static void +e_mail_parser_message_delivery_status_init (EMailParserMessageDeliveryStatus *parser) +{ + +} diff --git a/em-format/e-mail-parser-message-external.c b/em-format/e-mail-parser-message-external.c new file mode 100644 index 0000000000..8c02a3ef3b --- /dev/null +++ b/em-format/e-mail-parser-message-external.c @@ -0,0 +1,211 @@ +/* + * e-mail-parser-message-external.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include +#include + +#include +#include + +#include +#include + +typedef struct _EMailParserMessageExternal { + GObject parent; +} EMailParserMessageExternal; + +typedef struct _EMailParserMessageExternalClass { + GObjectClass parent_class; +} EMailParserMessageExternalClass; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserMessageExternal, + e_mail_parser_message_external, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "message/external-body", + NULL }; + +static GSList * +empe_msg_external_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EMailPart *mail_part; + CamelMimePart *newpart; + CamelContentType *type; + const gchar *access_type; + gchar *url = NULL, *desc = NULL; + gchar *content; + gint len; + gchar *mime_type; + + if (g_cancellable_is_cancelled (cancellable)) + return NULL; + + newpart = camel_mime_part_new (); + + /* needs to be cleaner */ + type = camel_mime_part_get_content_type (part); + access_type = camel_content_type_param (type, "access-type"); + if (!access_type) { + const gchar *msg = _("Malformed external-body part"); + mime_type = g_strdup ("text/plain"); + camel_mime_part_set_content (newpart, msg, strlen (msg), mime_type); + goto addPart; + } + + if (!g_ascii_strcasecmp(access_type, "ftp") || + !g_ascii_strcasecmp(access_type, "anon-ftp")) { + const gchar *name, *site, *dir, *mode; + gchar *path; + gchar 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 gchar *name, *site; + + name = camel_content_type_param (type, "name"); + site = camel_content_type_param (type, "site"); + if (name == NULL) + goto fail; + + url = g_filename_to_uri (name, NULL, NULL); + 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 gchar *urlparam; + gchar *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) { + if (!isspace ((guchar) * s)) + *d++ = *s; + s++; + } + *d = 0; + desc = g_strdup_printf (_("Pointer to remote data (%s)"), url); + } else { + goto fail; + } + + mime_type = g_strdup ("text/html"); + content = g_strdup_printf ("%s", url, desc); + camel_mime_part_set_content (newpart, content, strlen (content), mime_type); + g_free (content); + + g_free (url); + g_free (desc); + + goto addPart; + +fail: + content = g_strdup_printf ( + _("Pointer to unknown external data (\"%s\" type)"), + access_type); + mime_type = g_strdup ("text/plain"); + camel_mime_part_set_content (newpart, content, strlen (content), mime_type); + g_free (content); + +addPart: + len = part_id->len; + g_string_append (part_id, ".msg_external"); + mail_part = e_mail_part_new (part, part_id->str); + mail_part->mime_type = mime_type; + g_string_truncate (part_id, len); + + return g_slist_append (NULL, mail_part); +} + +static const gchar ** +empe_msg_external_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +static void +e_mail_parser_message_external_class_init (EMailParserMessageExternalClass *klass) +{ + e_mail_parser_message_external_parent_class = g_type_class_peek_parent (klass); +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_msg_external_parse; +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_msg_external_mime_types; +} + +static void +e_mail_parser_message_external_init (EMailParserMessageExternal *parser) +{ + +} diff --git a/em-format/e-mail-parser-message-rfc822.c b/em-format/e-mail-parser-message-rfc822.c new file mode 100644 index 0000000000..75b0306d84 --- /dev/null +++ b/em-format/e-mail-parser-message-rfc822.c @@ -0,0 +1,174 @@ +/* + * e-mail-parser-message-rfc822.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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-format-extensions.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +typedef struct _EMailParserMessageRFC822 { + GObject parent; +} EMailParserMessageRFC822; + +typedef struct _EMailParserMessageRFC822Class { + GObjectClass parent_class; +} EMailParserMessageRFC822Class; + +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_TYPE_EXTENDED ( + EMailParserMessageRFC822, + e_mail_parser_message_rfc822, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "message/rfc822", + "message/news", + "message/*", + NULL }; + +static GSList * +empe_msg_rfc822_parse (EMailParserExtension *extension, + EMailParser *eparser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + GSList *parts = NULL; + EMailPart *mail_part; + gint len; + CamelMimePart *message; + CamelDataWrapper *dw; + CamelStream *new_stream; + CamelMimeParser *mime_parser; + CamelContentType *ct; + + len = part_id->len; + g_string_append (part_id, ".rfc822"); + + /* Create an empty PURI that will represent start of the RFC message */ + mail_part = e_mail_part_new (part, part_id->str); + mail_part->mime_type = g_strdup ("message/rfc822"); + parts = g_slist_append (NULL, mail_part); + + /* Sometime the _actual_ message is encapsulated in another CamelMimePart, + * sometimes the CamelMimePart actually represents the RFC822 message */ + ct = camel_mime_part_get_content_type (part); + if (camel_content_type_is (ct, "message", "rfc822")) { + new_stream = camel_stream_mem_new (); + mime_parser = camel_mime_parser_new (); + message = (CamelMimePart *) camel_mime_message_new (); + + dw = camel_medium_get_content (CAMEL_MEDIUM (part)); + camel_data_wrapper_decode_to_stream_sync ( + dw, new_stream, cancellable, NULL); + g_seekable_seek ( + G_SEEKABLE (new_stream), 0, G_SEEK_SET, cancellable, NULL); + camel_mime_parser_init_with_stream ( + mime_parser, new_stream, NULL); + camel_mime_part_construct_from_parser_sync ( + message, mime_parser, cancellable, NULL); + + g_object_unref (mime_parser); + g_object_unref (new_stream); + } else { + message = g_object_ref (part); + } + + parts = g_slist_concat (parts, e_mail_parser_parse_part_as ( + eparser, message, part_id, + "application/vnd.evolution.message", + cancellable)); + + g_object_unref (message); + + /* Add another generic EMailPart that represents end of the RFC message. + * The em_format_write() function will skip all parts between the ".rfc822" + * part and ".rfc822.end" part as they will be rendered in an " - "
", - uri, - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME]), - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT])); - - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); - g_free (uri); - } -} - -static void -efh_write_source (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - EMFormatHTML *efh = (EMFormatHTML *) emf; - GString *buffer; - CamelStream *filtered_stream; - CamelMimeFilter *filter; - CamelDataWrapper *dw = (CamelDataWrapper *) puri->part; - - filtered_stream = camel_stream_filter_new (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 ( - CAMEL_STREAM_FILTER (filtered_stream), filter); - g_object_unref (filter); - - buffer = g_string_new (""); - - g_string_append_printf ( - buffer, "
", - e_color_to_value ( - &efh->priv->colors[ - EM_FORMAT_HTML_COLOR_BODY]), - e_color_to_value ( - &efh->priv->colors[ - EM_FORMAT_HTML_COLOR_TEXT])); - - camel_stream_write_string ( - stream, buffer->str, cancellable, NULL); - camel_stream_write_string ( - stream, "", cancellable, NULL); - camel_data_wrapper_write_to_stream_sync (dw, filtered_stream, - cancellable, NULL); - camel_stream_write_string ( - stream, "", cancellable, NULL); - - g_object_unref (filtered_stream); - g_string_free (buffer, TRUE); -} - -static void -efh_write_headers (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - GString *buffer; - EMFormatHTML *efh = (EMFormatHTML *) emf; - gint bg_color; - - if (!puri->part) - return; - - buffer = g_string_new (""); - - if (info->mode & EM_FORMAT_WRITE_MODE_PRINTING) { - GdkColor white = { 0, G_MAXUINT16, G_MAXUINT16, G_MAXUINT16 }; - bg_color = e_color_to_value (&white); - } else { - bg_color = e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY]); - } - - g_string_append_printf ( - buffer, - "
" - "\n" - "
\n", - bg_color, - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_HEADER])); - - if (info->headers_collapsable) { - g_string_append_printf (buffer, - "" - "", - EVOLUTION_IMAGESDIR, - (info->headers_collapsed) ? "plus.png" : "minus.png"); - - efh_format_short_headers (efh, buffer, (CamelMedium *) puri->part, - info->headers_collapsed, - cancellable); - } - - efh_format_full_headers (efh, buffer, (CamelMedium *) puri->part, - (info->mode == EM_FORMAT_WRITE_MODE_ALL_HEADERS), - !info->headers_collapsed, - cancellable); - - g_string_append (buffer, "
"); - - camel_stream_write_string (stream, buffer->str, cancellable, NULL); - - g_string_free (buffer, true); -} - -static void -efh_write_error (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - CamelStream *filtered_stream; - CamelMimeFilter *filter; - CamelDataWrapper *dw; - - dw = camel_medium_get_content ((CamelMedium *) puri->part); - - camel_stream_write_string (stream, "", cancellable, NULL); - - filtered_stream = camel_stream_filter_new (stream); - filter = camel_mime_filter_tohtml_new (CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | - CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); - camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered_stream), filter); - g_object_unref (filter); - - camel_data_wrapper_decode_to_stream_sync (dw, filtered_stream, cancellable, NULL); - - g_object_unref (filtered_stream); - - camel_stream_write_string (stream, "
", cancellable, NULL); -} - -static void -efh_write_message_rfc822 (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - if (info->mode == EM_FORMAT_WRITE_MODE_RAW) { - - GList *puris; - GList *iter; - EMFormatWriterInfo msgInfo = *info; - msgInfo.mode = EM_FORMAT_WRITE_MODE_NORMAL; - - /* Create a new fake list of PURIs which will contain only - * PURIs from this message. */ - iter = g_hash_table_lookup (emf->mail_part_table, puri->uri); - if (!iter || !iter->next) - return; - - iter = iter->next; - puris = NULL; - while (iter) { - - EMFormatPURI *p; - p = iter->data; - - if (g_str_has_suffix (p->uri, ".rfc822.end")) - break; - - puris = g_list_append (puris, p); - iter = iter->next; - - }; - - efh_write_message (emf, puris, stream, &msgInfo, cancellable); - - g_list_free (puris); - - } else if (info->mode == EM_FORMAT_WRITE_MODE_PRINTING) { - - GList *iter; - gboolean can_write = FALSE; - - iter = g_hash_table_lookup (emf->mail_part_table, puri->uri); - if (!iter || !iter->next) - return; - - /* Skip everything before attachment bar, inclusive */\ - iter = iter->next; - while (iter) { - - EMFormatPURI *p = iter->data; - - /* EMFormatHTMLPrint has registered a special writer - * for headers, try to find it and use it. */ - if (g_str_has_suffix (p->uri, ".headers")) { - - const EMFormatHandler *handler; - - handler = em_format_find_handler ( - emf, "x-evolution/message/headers"); - if (handler && handler->write_func) - handler->write_func (emf, p, stream, info, cancellable); - - iter = iter->next; - continue; - } - - if (g_str_has_suffix (p->uri, ".rfc822.end")) - break; - - if (g_str_has_suffix (p->uri, ".attachment-bar")) - can_write = TRUE; - - if (can_write && p->write_func) { - p->write_func ( - emf, p, stream, info, cancellable); - } - - iter = iter->next; - } - - } else { - gchar *str; - gchar *uri; - - EMFormatHTML *efh = (EMFormatHTML *) emf; - EMFormatPURI *p; - GList *iter; - - iter = g_hash_table_lookup (emf->mail_part_table, puri->uri); - if (!iter || !iter->next) - return; - - iter = iter->next; - p = iter->data; - - uri = em_format_build_mail_uri (emf->folder, emf->message_uid, - "part_id", G_TYPE_STRING, p->uri, - "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, - NULL); - - str = g_strdup_printf ( - "
" - "
\n" - "" - "
", - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME]), - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT]), - uri, puri->uri); - - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); - g_free (uri); - } - -} - -/*****************************************************************************/ - -/* Notes: - * - * image/tiff is omitted because it's a multi-page image format, but - * gdk-pixbuf unconditionally renders the first page only, and doesn't - * even indicate through meta-data whether multiple pages are present - * (see bug 335959). Therefore, make no attempt to render TIFF images - * inline and defer to an application that can handle multi-page TIFF - * files properly like Evince or Gimp. Once the referenced bug is - * fixed we can reevaluate this policy. - */ -static EMFormatHandler type_builtin_table[] = { - { (gchar *) "image/gif", efh_parse_image, efh_write_image, }, - { (gchar *) "image/jpeg", efh_parse_image, efh_write_image, }, - { (gchar *) "image/png", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-png", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-bmp", efh_parse_image, efh_write_image, }, - { (gchar *) "image/bmp", efh_parse_image, efh_write_image, }, - { (gchar *) "image/svg", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-cmu-raster", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-ico", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-portable-anymap", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-portable-bitmap", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-portable-graymap", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-portable-pixmap", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-xpixmap", efh_parse_image, efh_write_image, }, - { (gchar *) "text/enriched", efh_parse_text_enriched, efh_write_text_enriched, }, - { (gchar *) "text/plain", efh_parse_text_plain, efh_write_text_plain, }, - { (gchar *) "text/html", efh_parse_text_html, efh_write_text_html, }, - { (gchar *) "text/richtext", efh_parse_text_enriched, efh_write_text_enriched, }, - { (gchar *) "text/*", efh_parse_text_plain, efh_write_text_plain, }, - { (gchar *) "message/rfc822", efh_parse_message_rfc822, efh_write_message_rfc822, EM_FORMAT_HANDLER_INLINE | EM_FORMAT_HANDLER_COMPOUND_TYPE }, - { (gchar *) "message/news", efh_parse_message_rfc822, 0, EM_FORMAT_HANDLER_INLINE | EM_FORMAT_HANDLER_COMPOUND_TYPE }, - { (gchar *) "message/delivery-status", efh_parse_message_deliverystatus, efh_write_text_plain, }, - { (gchar *) "message/external-body", efh_parse_message_external, efh_write_text_plain, }, - { (gchar *) "message/*", efh_parse_message_rfc822, 0, EM_FORMAT_HANDLER_INLINE }, - - /* 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. */ - { (gchar *) "image/jpg", efh_parse_image, efh_write_image, }, - { (gchar *) "image/pjpeg", efh_parse_image, efh_write_image, }, - - /* special internal types */ - { (gchar *) "x-evolution/message/rfc822", 0, efh_write_text_plain, }, - { (gchar *) "x-evolution/message/headers", 0, efh_write_headers, }, - { (gchar *) "x-evolution/message/source", 0, efh_write_source, }, - { (gchar *) "x-evolution/message/attachment", 0, efh_write_attachment, }, - { (gchar *) "x-evolution/message/error", 0, efh_write_error, }, -}; - -static void -efh_builtin_init (EMFormatHTMLClass *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 -efh_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_BODY_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_BODY, - g_value_get_boxed (value)); - return; - - case PROP_CITATION_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_CITATION, - g_value_get_boxed (value)); - return; - - case PROP_CONTENT_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_CONTENT, - g_value_get_boxed (value)); - return; - - case PROP_FRAME_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_FRAME, - g_value_get_boxed (value)); - return; - - case PROP_HEADER_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_HEADER, - g_value_get_boxed (value)); - return; - - case PROP_IMAGE_LOADING_POLICY: - em_format_html_set_image_loading_policy ( - EM_FORMAT_HTML (object), - g_value_get_enum (value)); - return; - - case PROP_MARK_CITATIONS: - em_format_html_set_mark_citations ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - - case PROP_ONLY_LOCAL_PHOTOS: - em_format_html_set_only_local_photos ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - - case PROP_SHOW_SENDER_PHOTO: - em_format_html_set_show_sender_photo ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - - case PROP_SHOW_REAL_DATE: - em_format_html_set_show_real_date ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - - case PROP_TEXT_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_TEXT, - g_value_get_boxed (value)); - return; - - case PROP_ANIMATE_IMAGES: - em_format_html_set_animate_images ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -efh_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GdkColor color; - - switch (property_id) { - case PROP_BODY_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_BODY, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_CITATION_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_CITATION, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_CONTENT_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_CONTENT, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_FRAME_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_FRAME, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_HEADER_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_HEADER, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_IMAGE_LOADING_POLICY: - g_value_set_enum ( - value, - em_format_html_get_image_loading_policy ( - EM_FORMAT_HTML (object))); - return; - - case PROP_MARK_CITATIONS: - g_value_set_boolean ( - value, em_format_html_get_mark_citations ( - EM_FORMAT_HTML (object))); - return; - - case PROP_ONLY_LOCAL_PHOTOS: - g_value_set_boolean ( - value, em_format_html_get_only_local_photos ( - EM_FORMAT_HTML (object))); - return; - - case PROP_SHOW_SENDER_PHOTO: - g_value_set_boolean ( - value, em_format_html_get_show_sender_photo ( - EM_FORMAT_HTML (object))); - return; - - case PROP_SHOW_REAL_DATE: - g_value_set_boolean ( - value, em_format_html_get_show_real_date ( - EM_FORMAT_HTML (object))); - return; - - case PROP_TEXT_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_TEXT, - &color); - g_value_set_boxed (value, &color); - return; - case PROP_ANIMATE_IMAGES: - g_value_set_boolean ( - value, em_format_html_get_animate_images ( - EM_FORMAT_HTML (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -efh_finalize (GObject *object) -{ - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -efh_constructed (GObject *object) -{ - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (parent_class)->constructed (object); - - e_extensible_load_extensions (E_EXTENSIBLE (object)); -} - -static void -efh_write_attachment (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - gchar *text, *html; - CamelContentType *ct; - gchar *mime_type; - const EMFormatHandler *handler; - - /* we display all inlined attachments only */ - - /* this could probably be cleaned up ... */ - camel_stream_write_string ( - stream, - "" - "
" - "" - "
" - "
\n", - cancellable, NULL); - - ct = camel_mime_part_get_content_type (puri->part); - mime_type = camel_content_type_simple (ct); - - /* output some info about it */ - text = em_format_describe_part (puri->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, cancellable, NULL); - g_free (html); - g_free (text); - - camel_stream_write_string ( - stream, "
", cancellable, NULL); - - handler = em_format_find_handler (emf, mime_type); - if (handler && handler->write_func && handler->write_func != efh_write_attachment) { - if (em_format_is_inline (emf, puri->uri, puri->part, handler)) - handler->write_func (emf, puri, stream, info, cancellable); - } - - g_free (mime_type); -} - -static void -efh_preparse (EMFormat *emf) -{ - EMFormatHTML *efh = EM_FORMAT_HTML (emf); - CamelInternetAddress *addr; - CamelSession *session; - ESourceRegistry *registry; - - if (!emf->message) { - efh->priv->can_load_images = FALSE; - return; - } - - session = em_format_get_session (emf); - registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); - - addr = camel_mime_message_get_from (emf->message); - efh->priv->can_load_images = em_utils_in_addressbook ( - registry, addr, FALSE); -} - -static void -efh_write_message (EMFormat *emf, - GList *puris, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - GList *iter; - EMFormatHTML *efh; - gchar *header; - - efh = (EMFormatHTML *) emf; - - header = g_strdup_printf ( - "\n\n" - "\n\n" - "Evolution Mail Display\n" - "\n" - "\n" - "", - e_color_to_value (&efh->priv->colors[ - EM_FORMAT_HTML_COLOR_BODY])); - - camel_stream_write_string (stream, header, cancellable, NULL); - g_free (header); - - if (info->mode == EM_FORMAT_WRITE_MODE_SOURCE) { - - efh_write_source (emf, emf->mail_part_list->data, - stream, info, cancellable); - - camel_stream_write_string (stream, "", cancellable, NULL); - return; - } - - for (iter = puris; iter; iter = iter->next) { - - EMFormatPURI *puri = iter->data; - - if (!puri) - continue; - - /* If current PURI has suffix .rfc822 then iterate through all - * subsequent PURIs until PURI with suffix .rfc822.end is found. - * These skipped PURIs contain entire RFC message which will - * be written in