aboutsummaryrefslogtreecommitdiffstats
path: root/em-format
diff options
context:
space:
mode:
Diffstat (limited to 'em-format')
-rw-r--r--em-format/Makefile.am147
-rw-r--r--em-format/e-mail-extension-registry.c335
-rw-r--r--em-format/e-mail-extension-registry.h156
-rw-r--r--em-format/e-mail-formatter-attachment-bar.c104
-rw-r--r--em-format/e-mail-formatter-attachment.c408
-rw-r--r--em-format/e-mail-formatter-enums.h90
-rw-r--r--em-format/e-mail-formatter-error.c121
-rw-r--r--em-format/e-mail-formatter-extension.c141
-rw-r--r--em-format/e-mail-formatter-extension.h112
-rw-r--r--em-format/e-mail-formatter-headers.c595
-rw-r--r--em-format/e-mail-formatter-image.c162
-rw-r--r--em-format/e-mail-formatter-message-rfc822.c262
-rw-r--r--em-format/e-mail-formatter-print-headers.c235
-rw-r--r--em-format/e-mail-formatter-print.c295
-rw-r--r--em-format/e-mail-formatter-print.h93
-rw-r--r--em-format/e-mail-formatter-quote-attachment.c126
-rw-r--r--em-format/e-mail-formatter-quote-headers.c279
-rw-r--r--em-format/e-mail-formatter-quote-message-rfc822.c154
-rw-r--r--em-format/e-mail-formatter-quote-text-enriched.c101
-rw-r--r--em-format/e-mail-formatter-quote-text-html.c100
-rw-r--r--em-format/e-mail-formatter-quote-text-plain.c125
-rw-r--r--em-format/e-mail-formatter-quote.c250
-rw-r--r--em-format/e-mail-formatter-quote.h103
-rw-r--r--em-format/e-mail-formatter-secure-button.c479
-rw-r--r--em-format/e-mail-formatter-source.c140
-rw-r--r--em-format/e-mail-formatter-text-enriched.c114
-rw-r--r--em-format/e-mail-formatter-text-html.c363
-rw-r--r--em-format/e-mail-formatter-text-plain.c204
-rw-r--r--em-format/e-mail-formatter-utils.c541
-rw-r--r--em-format/e-mail-formatter-utils.h60
-rw-r--r--em-format/e-mail-formatter.c1435
-rw-r--r--em-format/e-mail-formatter.h192
-rw-r--r--em-format/e-mail-inline-filter.c496
-rw-r--r--em-format/e-mail-inline-filter.h83
-rw-r--r--em-format/e-mail-parser-application-mbox.c173
-rw-r--r--em-format/e-mail-parser-application-smime.c161
-rw-r--r--em-format/e-mail-parser-attachment-bar.c79
-rw-r--r--em-format/e-mail-parser-extension.c93
-rw-r--r--em-format/e-mail-parser-extension.h96
-rw-r--r--em-format/e-mail-parser-headers.c80
-rw-r--r--em-format/e-mail-parser-image.c102
-rw-r--r--em-format/e-mail-parser-inlinepgp-encrypted.c188
-rw-r--r--em-format/e-mail-parser-inlinepgp-signed.c201
-rw-r--r--em-format/e-mail-parser-message-deliverystatus.c87
-rw-r--r--em-format/e-mail-parser-message-external.c182
-rw-r--r--em-format/e-mail-parser-message-rfc822.c136
-rw-r--r--em-format/e-mail-parser-message.c130
-rw-r--r--em-format/e-mail-parser-multipart-alternative.c158
-rw-r--r--em-format/e-mail-parser-multipart-appledouble.c95
-rw-r--r--em-format/e-mail-parser-multipart-digest.c135
-rw-r--r--em-format/e-mail-parser-multipart-encrypted.c183
-rw-r--r--em-format/e-mail-parser-multipart-mixed.c133
-rw-r--r--em-format/e-mail-parser-multipart-related.c155
-rw-r--r--em-format/e-mail-parser-multipart-signed.c217
-rw-r--r--em-format/e-mail-parser-secure-button.c77
-rw-r--r--em-format/e-mail-parser-source.c78
-rw-r--r--em-format/e-mail-parser-text-enriched.c109
-rw-r--r--em-format/e-mail-parser-text-html.c110
-rw-r--r--em-format/e-mail-parser-text-plain.c241
-rw-r--r--em-format/e-mail-parser.c776
-rw-r--r--em-format/e-mail-parser.h115
-rw-r--r--em-format/e-mail-part-attachment-bar.c89
-rw-r--r--em-format/e-mail-part-attachment-bar.h71
-rw-r--r--em-format/e-mail-part-attachment.c170
-rw-r--r--em-format/e-mail-part-attachment.h75
-rw-r--r--em-format/e-mail-part-headers.c382
-rw-r--r--em-format/e-mail-part-headers.h84
-rw-r--r--em-format/e-mail-part-image.c100
-rw-r--r--em-format/e-mail-part-image.h65
-rw-r--r--em-format/e-mail-part-list.c417
-rw-r--r--em-format/e-mail-part-list.h81
-rw-r--r--em-format/e-mail-part-utils.c582
-rw-r--r--em-format/e-mail-part-utils.h60
-rw-r--r--em-format/e-mail-part.c613
-rw-r--r--em-format/e-mail-part.h132
-rw-r--r--em-format/e-mail-stripsig-filter.c165
-rw-r--r--em-format/e-mail-stripsig-filter.h69
77 files changed, 16046 insertions, 0 deletions
diff --git a/em-format/Makefile.am b/em-format/Makefile.am
new file mode 100644
index 0000000000..2983eb0ecf
--- /dev/null
+++ b/em-format/Makefile.am
@@ -0,0 +1,147 @@
+privsolib_LTLIBRARIES = libevolution-mail-formatter.la
+
+evolution_mail_formatter_includedir = $(privincludedir)/em-format
+
+ENUM_TYPES = e-mail-formatter-enums.h
+
+e-mail-formatter-enumtypes.h: $(top_srcdir)/enumtypes.h.template $(ENUM_TYPES)
+ $(AM_V_GEN) $(GLIB_MKENUMS) --template $(top_srcdir)/enumtypes.h.template \
+ --fhead "#ifndef E_MAIL_FORMATTER_ENUMTYPES_H\n#define E_MAIL_FORMATTER_ENUMTYPES_H\n" \
+ --ftail "#endif /* E_MAIL_FORMATTER_ENUMTYPES_H */\n" \
+ $(addprefix $(srcdir)/,$(ENUM_TYPES)) > $@
+
+e-mail-formatter-enumtypes.c: $(top_srcdir)/enumtypes.c.template $(ENUM_TYPES)
+ $(AM_V_GEN) $(GLIB_MKENUMS) --template $(top_srcdir)/enumtypes.c.template \
+ --fhead "#include \"e-mail-formatter-enumtypes.h\"" \
+ $(addprefix $(srcdir)/,$(ENUM_TYPES)) > $@
+
+ENUM_GENERATED = \
+ e-mail-formatter-enumtypes.c \
+ e-mail-formatter-enumtypes.h \
+ $(NULL)
+
+evolution_mail_formatter_include_HEADERS = \
+ e-mail-extension-registry.h \
+ e-mail-formatter-extension.h \
+ e-mail-formatter.h \
+ e-mail-formatter-enums.h \
+ e-mail-formatter-enumtypes.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-headers.h \
+ e-mail-part-image.h \
+ e-mail-part-list.h \
+ e-mail-part-utils.h \
+ e-mail-stripsig-filter.h
+
+libevolution_mail_formatter_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/em-format \
+ -I$(top_srcdir)/smime/lib \
+ -I$(top_srcdir)/smime/gui \
+ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
+ -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(GTKHTML_CFLAGS) \
+ $(LIBSOUP_CFLAGS)
+
+if ENABLE_SMIME
+SMIME_EXTENSIONS = e-mail-parser-application-smime.c
+endif
+
+libevolution_mail_formatter_la_SOURCES = \
+ $(evolution_mail_formatter_include_HEADERS) \
+ e-mail-extension-registry.c \
+ e-mail-inline-filter.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-enumtypes.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-attachment-bar.c \
+ e-mail-part-headers.c \
+ e-mail-part-image.c \
+ e-mail-part-list.c \
+ e-mail-part-utils.c \
+ e-mail-stripsig-filter.c \
+ $(SMIME_EXTENSIONS)
+
+libevolution_mail_formatter_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
+
+libevolution_mail_formatter_la_LIBADD = \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(top_builddir)/shell/libevolution-shell.la \
+ $(top_builddir)/libemail-engine/libemail-engine.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(GTKHTML_LIBS) \
+ $(LIBSOUP_LIBS) \
+ $(SMIME_LIBS)
+
+BUILT_SOURCES = \
+ $(ENUM_GENERATED) \
+ $(NULL)
+
+CLEANFILES = $(BUILT_SOURCES)
+
+-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..d5beb2f64b
--- /dev/null
+++ b/em-format/e-mail-extension-registry.c
@@ -0,0 +1,335 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-extension-registry.h"
+
+#include <string.h>
+
+#include <libebackend/libebackend.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-parser-extension.h"
+
+#define E_MAIL_EXTENSION_REGISTRY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistryPrivate))
+
+struct _EMailExtensionRegistryPrivate {
+ GHashTable *table;
+};
+
+G_DEFINE_ABSTRACT_TYPE (
+ EMailExtensionRegistry,
+ e_mail_extension_registry,
+ G_TYPE_OBJECT)
+
+/**
+ * EMailExtensionRegistry:
+ *
+ * The #EMailExtensionRegistry is an abstract class representing a registry
+ * for #EMailExtension<!-//>s.
+ *
+ * #EMailParser and #EMailFormatter both have internally a registry object
+ * based on the #EMailExtensionRegistry.
+ *
+ * One extension can registry itself for more mime-types.
+ */
+
+static void
+destroy_queue (GQueue *queue)
+{
+ g_queue_free_full (queue, g_object_unref);
+}
+
+static void
+mail_extension_registry_add_extension (EMailExtensionRegistry *registry,
+ const gchar **mime_types,
+ GType extension_type,
+ GCompareDataFunc compare_func)
+{
+ GObject *extension;
+ gint ii;
+
+ if (mime_types == NULL) {
+ g_critical (
+ "%s does not define any MIME types",
+ g_type_name (extension_type));
+ return;
+ }
+
+ extension = g_object_new (extension_type, NULL);
+
+ for (ii = 0; mime_types[ii] != NULL; ii++) {
+ GQueue *queue;
+
+ queue = g_hash_table_lookup (
+ registry->priv->table, mime_types[ii]);
+ if (queue == NULL) {
+ queue = g_queue_new ();
+ g_hash_table_insert (
+ registry->priv->table,
+ (gpointer) mime_types[ii],
+ queue);
+ }
+
+ g_queue_insert_sorted (
+ queue, g_object_ref (extension),
+ compare_func, NULL);
+
+ if (camel_debug ("emformat:registry")) {
+ printf (
+ "Added extension '%s' for type '%s'\n",
+ g_type_name (extension_type),
+ mime_types[ii]);
+ }
+ }
+
+ g_object_unref (extension);
+}
+
+static void
+mail_extension_registry_finalize (GObject *object)
+{
+ EMailExtensionRegistryPrivate *priv;
+
+ priv = E_MAIL_EXTENSION_REGISTRY_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->table);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_extension_registry_parent_class)->
+ finalize (object);
+}
+
+void
+e_mail_extension_registry_class_init (EMailExtensionRegistryClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (
+ class, sizeof (EMailExtensionRegistryPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = mail_extension_registry_finalize;
+}
+
+void
+e_mail_extension_registry_init (EMailExtensionRegistry *registry)
+{
+ registry->priv = E_MAIL_EXTENSION_REGISTRY_GET_PRIVATE (registry);
+
+ registry->priv->table = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) destroy_queue);
+}
+
+/**
+ * e_mail_extension_registry_get_for_mime_type:
+ * @registry: An #EMailExtensionRegistry
+ * @mime_type: A string with mime-type to look up
+ *
+ * Tries to lookup list of #EMailExtension<!-//>s that has registryed themselves
+ * as handlers for the @mime_type.
+ *
+ * Return value: Returns #GQueue of #EMailExtension<!-//>s or %NULL when there
+ * are no extension registryed for given @mime_type.
+ */
+GQueue *
+e_mail_extension_registry_get_for_mime_type (EMailExtensionRegistry *registry,
+ const gchar *mime_type)
+{
+ g_return_val_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (registry), NULL);
+ g_return_val_if_fail (mime_type && *mime_type, NULL);
+
+ return g_hash_table_lookup (registry->priv->table, mime_type);
+}
+
+/**
+ * e_mail_extension_registry_get_fallback:
+ * @registry: 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 *registry,
+ const gchar *mime_type)
+{
+ gchar *s, *type;
+ gsize len;
+ GQueue *parsers;
+
+ g_return_val_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (registry), NULL);
+ g_return_val_if_fail (mime_type && *mime_type, NULL);
+
+ s = strchr (mime_type, '/');
+ if (!s)
+ return NULL;
+
+ 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 (registry->priv->table, s);
+
+ g_free (type);
+ g_free (s);
+
+ return parsers;
+}
+
+/******************************************************************************/
+
+G_DEFINE_TYPE_WITH_CODE (
+ EMailParserExtensionRegistry,
+ e_mail_parser_extension_registry,
+ E_TYPE_MAIL_EXTENSION_REGISTRY,
+ G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
+
+static void
+e_mail_parser_extension_registry_class_init (EMailParserExtensionRegistryClass *class)
+{
+}
+
+static void
+e_mail_parser_extension_registry_init (EMailParserExtensionRegistry *registry)
+{
+}
+
+static gint
+mail_parser_extension_registry_compare (gconstpointer extension1,
+ gconstpointer extension2,
+ gpointer user_data)
+{
+ EMailParserExtensionClass *class1;
+ EMailParserExtensionClass *class2;
+
+ class1 = E_MAIL_PARSER_EXTENSION_GET_CLASS (extension1);
+ class2 = E_MAIL_PARSER_EXTENSION_GET_CLASS (extension2);
+
+ if (class1->priority == class2->priority)
+ return 0;
+
+ return (class1->priority < class2->priority) ? -1 : 1;
+}
+
+void
+e_mail_parser_extension_registry_load (EMailParserExtensionRegistry *registry)
+{
+ GType *children;
+ GType base_extension_type;
+ guint ii, n_children;
+
+ g_return_if_fail (E_IS_MAIL_PARSER_EXTENSION_REGISTRY (registry));
+
+ base_extension_type = E_TYPE_MAIL_PARSER_EXTENSION;
+ children = g_type_children (base_extension_type, &n_children);
+
+ for (ii = 0; ii < n_children; ii++) {
+ EMailParserExtensionClass *class;
+
+ if (G_TYPE_IS_ABSTRACT (children[ii]))
+ continue;
+
+ class = g_type_class_ref (children[ii]);
+
+ mail_extension_registry_add_extension (
+ E_MAIL_EXTENSION_REGISTRY (registry),
+ class->mime_types, children[ii],
+ mail_parser_extension_registry_compare);
+
+ g_type_class_unref (class);
+ }
+
+ g_free (children);
+}
+
+/******************************************************************************/
+
+G_DEFINE_TYPE_WITH_CODE (
+ EMailFormatterExtensionRegistry,
+ e_mail_formatter_extension_registry,
+ E_TYPE_MAIL_EXTENSION_REGISTRY,
+ G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
+
+static void
+e_mail_formatter_extension_registry_class_init (EMailFormatterExtensionRegistryClass *class)
+{
+}
+
+static void
+e_mail_formatter_extension_registry_init (EMailFormatterExtensionRegistry *registry)
+{
+}
+
+static gint
+mail_formatter_extension_registry_compare (gconstpointer extension1,
+ gconstpointer extension2,
+ gpointer user_data)
+{
+ EMailFormatterExtensionClass *class1;
+ EMailFormatterExtensionClass *class2;
+
+ class1 = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension1);
+ class2 = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension2);
+
+ if (class1->priority == class2->priority)
+ return 0;
+
+ return (class1->priority < class2->priority) ? -1 : 1;
+}
+
+void
+e_mail_formatter_extension_registry_load (EMailFormatterExtensionRegistry *registry,
+ GType base_extension_type)
+{
+ GType *children;
+ guint ii, n_children;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER_EXTENSION_REGISTRY (registry));
+
+ children = g_type_children (base_extension_type, &n_children);
+
+ for (ii = 0; ii < n_children; ii++) {
+ EMailFormatterExtensionClass *class;
+
+ if (G_TYPE_IS_ABSTRACT (children[ii]))
+ continue;
+
+ class = g_type_class_ref (children[ii]);
+
+ mail_extension_registry_add_extension (
+ E_MAIL_EXTENSION_REGISTRY (registry),
+ class->mime_types, children[ii],
+ mail_formatter_extension_registry_compare);
+
+ g_type_class_unref (class);
+ }
+
+ g_free (children);
+}
+
diff --git a/em-format/e-mail-extension-registry.h b/em-format/e-mail-extension-registry.h
new file mode 100644
index 0000000000..7002eb0385
--- /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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_EXTENSION_REGISTRY_H
+#define E_MAIL_EXTENSION_REGISTRY_H
+
+#include <glib-object.h>
+
+/* 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 _EMailExtensionRegistry {
+ GObject parent;
+ EMailExtensionRegistryPrivate *priv;
+};
+
+struct _EMailExtensionRegistryClass {
+ GObjectClass parent_class;
+};
+
+GType e_mail_extension_registry_get_type
+ (void) G_GNUC_CONST;
+GQueue * e_mail_extension_registry_get_for_mime_type
+ (EMailExtensionRegistry *registry,
+ const gchar *mime_type);
+GQueue * e_mail_extension_registry_get_fallback
+ (EMailExtensionRegistry *registry,
+ 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 _EMailParserExtensionRegistry {
+ EMailExtensionRegistry parent;
+ EMailParserExtensionRegistryPrivate *priv;
+};
+
+struct _EMailParserExtensionRegistryClass {
+ EMailExtensionRegistryClass parent_class;
+};
+
+GType e_mail_parser_extension_registry_get_type
+ (void) G_GNUC_CONST;
+void e_mail_parser_extension_registry_load
+ (EMailParserExtensionRegistry *registry);
+
+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 _EMailFormatterExtensionRegistry {
+ EMailExtensionRegistry parent;
+ EMailFormatterExtensionRegistryPrivate *priv;
+};
+
+struct _EMailFormatterExtensionRegistryClass {
+ EMailExtensionRegistryClass parent_class;
+};
+
+GType e_mail_formatter_extension_registry_get_type
+ (void) G_GNUC_CONST;
+void e_mail_formatter_extension_registry_load
+ (EMailFormatterExtensionRegistry *registry,
+ GType base_extension_type);
+
+G_END_DECLS
+
+#endif /* E_MAIL_EXTENSION_REGISTRY_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..89378b8b16
--- /dev/null
+++ b/em-format/e-mail-formatter-attachment-bar.c
@@ -0,0 +1,104 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-part-attachment-bar.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "e-mail-formatter-extension.h"
+
+typedef EMailFormatterExtension EMailFormatterAttachmentBar;
+typedef EMailFormatterExtensionClass EMailFormatterAttachmentBarClass;
+
+GType e_mail_formatter_attachment_bar_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterAttachmentBar,
+ e_mail_formatter_attachment_bar,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+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) &&
+ (context->mode != E_MAIL_FORMATTER_MODE_ALL_HEADERS))
+ return FALSE;
+
+ str = g_strdup_printf (
+ "<object type=\"application/vnd.evolution.widget.attachment-bar\" "
+ "height=\"0\" width=\"100%%\" data=\"%s\" id=\"%s\"></object>",
+ e_mail_part_get_id (part),
+ e_mail_part_get_id (part));
+
+ camel_stream_write_string (stream, str, cancellable, NULL);
+
+ g_free (str);
+
+ return TRUE;
+}
+
+static GtkWidget *
+emfe_attachment_bar_get_widget (EMailFormatterExtension *extension,
+ EMailPartList *context,
+ EMailPart *part,
+ GHashTable *params)
+{
+ EAttachmentStore *store;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT_BAR (part), NULL);
+
+ store = e_mail_part_attachment_bar_get_store (
+ E_MAIL_PART_ATTACHMENT_BAR (part));
+
+ widget = e_attachment_bar_new (store);
+ g_object_set_data (G_OBJECT (store), "attachment-bar", widget);
+
+ return widget;
+}
+
+static void
+e_mail_formatter_attachment_bar_class_init (EMailFormatterExtensionClass *class)
+{
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_attachment_bar_format;
+ class->get_widget = emfe_attachment_bar_get_widget;
+}
+
+static void
+e_mail_formatter_attachment_bar_init (EMailFormatterExtension *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..9e44901fce
--- /dev/null
+++ b/em-format/e-mail-formatter-attachment.c
@@ -0,0 +1,408 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <shell/e-shell.h>
+#include <shell/e-shell-window.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-inline-filter.h"
+#include "e-mail-part-attachment-bar.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-utils.h"
+
+#define d(x)
+
+typedef EMailFormatterExtension EMailFormatterAttachment;
+typedef EMailFormatterExtensionClass EMailFormatterAttachmentClass;
+
+GType e_mail_formatter_attachment_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterAttachment,
+ e_mail_formatter_attachment,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ E_MAIL_PART_ATTACHMENT_MIME_TYPE,
+ "application/vnd.evolution.widget.attachment-button",
+ NULL
+};
+
+static EAttachmentStore *
+find_attachment_store (EMailPartList *part_list,
+ EMailPart *start)
+{
+ EAttachmentStore *store = NULL;
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+ const gchar *start_id;
+ gchar *tmp, *pos;
+ EMailPart *part;
+ gchar *id;
+
+ start_id = e_mail_part_get_id (start);
+
+ e_mail_part_list_queue_parts (part_list, NULL, &queue);
+
+ head = g_queue_peek_head_link (&queue);
+
+ id = g_strconcat (start_id, ".attachment-bar", NULL);
+ tmp = g_strdup (id);
+ part = NULL;
+ do {
+ d (printf ("Looking up attachment bar as %s\n", id));
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *p = link->data;
+ const gchar *p_id;
+
+ p_id = e_mail_part_get_id (p);
+
+ 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 != NULL)
+ store = e_mail_part_attachment_bar_get_store (
+ E_MAIL_PART_ATTACHMENT_BAR (part));
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ return store;
+}
+
+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 *registry;
+ GQueue *extensions;
+ EMailPartAttachment *empa;
+ CamelMimePart *mime_part;
+ CamelMimeFilterToHTMLFlags flags;
+ const gchar *attachment_part_id;
+ const gchar *part_id;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT (part), FALSE);
+
+ empa = (EMailPartAttachment *) part;
+ part_id = e_mail_part_get_id (part);
+
+ if ((context->mode == E_MAIL_FORMATTER_MODE_NORMAL) ||
+ (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) ||
+ (context->mode == E_MAIL_FORMATTER_MODE_ALL_HEADERS)) {
+ EAttachment *attachment;
+ GList *head, *link;
+
+ attachment = e_mail_part_attachment_ref_attachment (
+ E_MAIL_PART_ATTACHMENT (part));
+
+ head = g_queue_peek_head_link (&part->validities);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+
+ if (pair == NULL)
+ continue;
+
+ if ((pair->validity_type & E_MAIL_PART_VALIDITY_SIGNED) != 0)
+ e_attachment_set_signed (
+ attachment,
+ pair->validity->sign.status);
+
+ if ((pair->validity_type & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0)
+ e_attachment_set_encrypted (
+ attachment,
+ pair->validity->encrypt.status);
+ }
+
+ store = find_attachment_store (context->part_list, part);
+ if (store) {
+ GList *attachments = e_attachment_store_get_attachments (store);
+ if (!g_list_find (attachments, attachment)) {
+ e_attachment_store_add_attachment (
+ store, attachment);
+ }
+ g_list_free (attachments);
+ } else {
+ g_warning ("Failed to locate attachment-bar for %s", part_id);
+ }
+
+ g_object_unref (attachment);
+ }
+
+ registry = e_mail_formatter_get_extension_registry (formatter);
+
+ extensions = e_mail_extension_registry_get_for_mime_type (
+ registry, empa->snoop_mime_type);
+ if (extensions == NULL)
+ extensions = e_mail_extension_registry_get_fallback (
+ registry, empa->snoop_mime_type);
+
+ /* 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)) {
+ GList *head, *link;
+ gboolean success = FALSE;
+
+ if (extensions == NULL)
+ return FALSE;
+
+ if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
+ gchar *name;
+ EAttachment *attachment;
+ GFileInfo *file_info;
+ const gchar *display_name;
+ gchar *description;
+
+ attachment = e_mail_part_attachment_ref_attachment (
+ E_MAIL_PART_ATTACHMENT (part));
+
+ file_info = e_attachment_ref_file_info (attachment);
+ display_name = g_file_info_get_display_name (file_info);
+
+ description = e_attachment_dup_description (attachment);
+ if (description != NULL && *description != '\0') {
+ name = g_strdup_printf (
+ "<h2>Attachment: %s (%s)</h2>\n",
+ description, display_name);
+ } else {
+ name = g_strdup_printf (
+ "<h2>Attachment: %s</h2>\n",
+ display_name);
+ }
+
+ camel_stream_write_string (
+ stream, name, cancellable, NULL);
+
+ g_free (description);
+ g_free (name);
+
+ g_object_unref (attachment);
+ g_object_unref (file_info);
+ }
+
+ head = g_queue_peek_head_link (extensions);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ success = e_mail_formatter_extension_format (
+ E_MAIL_FORMATTER_EXTENSION (link->data),
+ formatter, context, part, stream, cancellable);
+ if (success)
+ break;
+ }
+
+ return success;
+ }
+
+ /* E_MAIL_FORMATTER_MODE_NORMAL: */
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ text = e_mail_part_describe (mime_part, empa->snoop_mime_type);
+ flags = e_mail_formatter_get_text_format_flags (formatter);
+ html = camel_text_to_html (
+ text, flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+ g_free (text);
+ g_object_unref (mime_part);
+
+ 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 (
+ "<div class=\"attachment\">"
+ "<table width=\"100%%\" border=\"0\">"
+ "<tr valign=\"middle\">"
+ "<td align=\"left\" width=\"100\">"
+ "<object type=\"application/vnd.evolution.widget.attachment-button\" "
+ "height=\"20\" width=\"100\" data=\"%s\" id=\"%s\"></object>"
+ "</td>"
+ "<td align=\"left\">%s</td>"
+ "</tr>", 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 != NULL) {
+ CamelStream *content_stream;
+ gboolean success = FALSE;
+
+ content_stream = camel_stream_mem_new ();
+ if (empa->attachment_view_part_id != NULL) {
+ EMailPart *attachment_view_part;
+
+ attachment_view_part = e_mail_part_list_ref_part (
+ context->part_list,
+ empa->attachment_view_part_id);
+
+ /* Avoid recursion. */
+ if (attachment_view_part == part)
+ g_clear_object (&attachment_view_part);
+
+ if (attachment_view_part != NULL) {
+ success = e_mail_formatter_format_as (
+ formatter, context,
+ attachment_view_part,
+ content_stream, NULL,
+ cancellable);
+ g_object_unref (attachment_view_part);
+ }
+
+ } else {
+ GList *head, *link;
+
+ head = g_queue_peek_head_link (extensions);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ success = e_mail_formatter_extension_format (
+ E_MAIL_FORMATTER_EXTENSION (link->data),
+ formatter, context,
+ part, content_stream,
+ cancellable);
+ if (success)
+ break;
+ }
+ }
+
+ if (success) {
+ gchar *wrapper_element_id;
+
+ wrapper_element_id = g_strconcat (
+ attachment_part_id, ".wrapper", NULL);
+
+ str = g_strdup_printf (
+ "<tr><td colspan=\"2\">"
+ "<div class=\"attachment-wrapper\" id=\"%s\">",
+ wrapper_element_id);
+
+ camel_stream_write_string (
+ stream, str, cancellable, NULL);
+
+ 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, "</div></td></tr>", cancellable, NULL);
+
+ g_free (wrapper_element_id);
+ g_free (str);
+ }
+
+ g_object_unref (content_stream);
+ }
+
+ camel_stream_write_string (stream, "</table></div>", cancellable, NULL);
+
+ return TRUE;
+}
+
+static GtkWidget *
+emfe_attachment_get_widget (EMailFormatterExtension *extension,
+ EMailPartList *context,
+ EMailPart *part,
+ GHashTable *params)
+{
+ EAttachment *attachment;
+ EAttachmentStore *store;
+ EAttachmentView *view;
+ GtkWidget *widget;
+ const gchar *part_id;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT (part), NULL);
+
+ attachment = e_mail_part_attachment_ref_attachment (
+ E_MAIL_PART_ATTACHMENT (part));
+
+ part_id = e_mail_part_get_id (part);
+
+ store = find_attachment_store (context, part);
+ widget = e_attachment_button_new ();
+ g_object_set_data_full (
+ G_OBJECT (widget),
+ "uri", g_strdup (part_id),
+ (GDestroyNotify) g_free);
+ e_attachment_button_set_attachment (
+ E_ATTACHMENT_BUTTON (widget), attachment);
+
+ view = g_object_get_data (G_OBJECT (store), "attachment-bar");
+ if (view != NULL)
+ e_attachment_button_set_view (
+ E_ATTACHMENT_BUTTON (widget), view);
+
+ gtk_widget_set_can_focus (widget, TRUE);
+ gtk_widget_show (widget);
+
+ g_object_unref (attachment);
+
+ return widget;
+}
+
+static void
+e_mail_formatter_attachment_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("Attachment");
+ class->description = _("Display as attachment");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_attachment_format;
+ class->get_widget = emfe_attachment_get_widget;
+}
+
+static void
+e_mail_formatter_attachment_init (EMailFormatterExtension *extension)
+{
+}
diff --git a/em-format/e-mail-formatter-enums.h b/em-format/e-mail-formatter-enums.h
new file mode 100644
index 0000000000..e1b41d6cf6
--- /dev/null
+++ b/em-format/e-mail-formatter-enums.h
@@ -0,0 +1,90 @@
+/*
+ * e-mail-formatter-enums.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_ENUMS_H
+#define E_MAIL_FORMATTER_ENUMS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+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 /*< skip >*/
+} EMailFormatterColor;
+
+typedef enum { /*< flags >*/
+ 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_MODE_INVALID = -1,
+ E_MAIL_FORMATTER_MODE_NORMAL = 0,
+ E_MAIL_FORMATTER_MODE_SOURCE,
+ E_MAIL_FORMATTER_MODE_RAW,
+ E_MAIL_FORMATTER_MODE_CID,
+ E_MAIL_FORMATTER_MODE_PRINTING,
+ E_MAIL_FORMATTER_MODE_ALL_HEADERS
+} EMailFormatterMode;
+
+typedef enum { /*< flags >*/
+ 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;
+
+/**
+ * EMailParserExtensionFlags:
+ * @E_MAIL_PARSER_EXTENSION_INLINE:
+ * Don't parse as attachment.
+ * @E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION:
+ * Always expand.
+ * @E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE:
+ * Always check what's inside.
+ **/
+typedef enum { /*< flags >*/
+ E_MAIL_PARSER_EXTENSION_INLINE = 1 << 0,
+ E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION = 1 << 1,
+ E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE = 1 << 2
+} EMailParserExtensionFlags;
+
+typedef enum { /*< flags >*/
+ E_MAIL_PART_VALIDITY_NONE = 0,
+ E_MAIL_PART_VALIDITY_PGP = 1 << 0,
+ E_MAIL_PART_VALIDITY_SMIME = 1 << 1,
+ E_MAIL_PART_VALIDITY_SIGNED = 1 << 2,
+ E_MAIL_PART_VALIDITY_ENCRYPTED = 1 << 3
+} EMailPartValidityFlags;
+
+G_END_DECLS
+
+#endif /* E_MAIL_FORMATTER_ENUMS_H */
+
diff --git a/em-format/e-mail-formatter-error.c b/em-format/e-mail-formatter-error.c
new file mode 100644
index 0000000000..8669c11ced
--- /dev/null
+++ b/em-format/e-mail-formatter-error.c
@@ -0,0 +1,121 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-extension.h"
+
+typedef EMailFormatterExtension EMailFormatterError;
+typedef EMailFormatterExtensionClass EMailFormatterErrorClass;
+
+GType e_mail_formatter_error_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterError,
+ e_mail_formatter_error,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+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;
+ CamelMimePart *mime_part;
+ CamelDataWrapper *dw;
+ gchar *html;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+
+ html = g_strdup_printf (
+ "<div class=\"part-container\" style=\""
+ "border-color: #%06x;"
+ "background-color: #%06x; color: #%06x;\">"
+ "<div class=\"part-container-inner-margin pre\">\n"
+ "<table border=\"0\" cellspacing=\"10\" "
+ "cellpadding=\"0\" width=\"100%%\">\n"
+ "<tr valign=\"top\"><td width=50>"
+ "<img src=\"gtk-stock://%s/?size=%d\" /></td>\n"
+ "<td style=\"color: red;\">",
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_BODY)),
+ e_rgba_to_value (
+ 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,
+ "</td>\n"
+ "</tr>\n"
+ "</table>\n"
+ "</div>\n"
+ "</div>",
+ cancellable, NULL);
+
+ g_object_unref (mime_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_error_class_init (EMailFormatterExtensionClass *class)
+{
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_error_format;
+}
+
+static void
+e_mail_formatter_error_init (EMailFormatterExtension *extension)
+{
+}
diff --git a/em-format/e-mail-formatter-extension.c b/em-format/e-mail-formatter-extension.c
new file mode 100644
index 0000000000..bbac4069c8
--- /dev/null
+++ b/em-format/e-mail-formatter-extension.c
@@ -0,0 +1,141 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter-extension.h"
+
+G_DEFINE_ABSTRACT_TYPE (
+ EMailFormatterExtension,
+ e_mail_formatter_extension,
+ G_TYPE_OBJECT)
+
+static void
+e_mail_formatter_extension_class_init (EMailFormatterExtensionClass *class)
+{
+ class->priority = G_PRIORITY_DEFAULT;
+}
+
+static void
+e_mail_formatter_extension_init (EMailFormatterExtension *extension)
+{
+}
+
+/**
+ * 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.
+ *
+ * Returns: 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)
+{
+ EMailFormatterExtensionClass *class;
+
+ 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);
+
+ class = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension);
+ g_return_val_if_fail (class->format != NULL, FALSE);
+
+ return class->format (extension, formatter, context, part, stream, cancellable);
+}
+
+/**
+ * e_mail_formatter_extension_has_widget:
+ * @extension: an #EMailFormatterExtension
+ *
+ * Returns whether the extension can provide a GtkWidget.
+ *
+ * Returns: Returns %TRUE when @extension reimplements get_widget(), %FALSE
+ * otherwise.
+ */
+gboolean
+e_mail_formatter_extension_has_widget (EMailFormatterExtension *extension)
+{
+ EMailFormatterExtensionClass *class;
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), FALSE);
+
+ class = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension);
+
+ return (class->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 &lt;object&gt; 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.
+ *
+ * Returns: 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)
+{
+ EMailFormatterExtensionClass *class;
+ GtkWidget *widget = NULL;
+
+ 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);
+
+ class = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension);
+
+ if (class->get_widget != NULL)
+ widget = class->get_widget (extension, context, part, params);
+
+ return widget;
+}
+
diff --git a/em-format/e-mail-formatter-extension.h b/em-format/e-mail-formatter-extension.h
new file mode 100644
index 0000000000..1da4069ec8
--- /dev/null
+++ b/em-format/e-mail-formatter-extension.h
@@ -0,0 +1,112 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_EXTENSION_H
+#define E_MAIL_FORMATTER_EXTENSION_H
+
+#include <gtk/gtk.h>
+#include <camel/camel.h>
+#include <em-format/e-mail-part.h>
+#include <em-format/e-mail-formatter.h>
+
+/* 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_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_FORMATTER_EXTENSION, EMailFormatterExtensionClass))
+#define E_IS_MAIL_FORMATTER_EXTENSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_FORMATTER_EXTENSION))
+#define E_IS_MAIL_FORMATTER_EXTENSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_FORMATTER_EXTENSION))
+#define E_MAIL_FORMATTER_EXTENSION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_FORMATTER_EXTENSION, EMailFormatterExtensionClass))
+
+G_BEGIN_DECLS
+
+/**
+ * EMailFormatterExtension:
+ *
+ * The #EMailFormatterExtension is an abstract class for all extensions for
+ * #EMailFormatter.
+ */
+typedef struct _EMailFormatterExtension EMailFormatterExtension;
+typedef struct _EMailFormatterExtensionClass EMailFormatterExtensionClass;
+typedef struct _EMailFormatterExtensionPrivate EMailFormatterExtensionPrivate;
+
+struct _EMailFormatterExtension {
+ GObject parent;
+ EMailFormatterExtensionPrivate *priv;
+};
+
+struct _EMailFormatterExtensionClass {
+ GObjectClass parent_class;
+
+ /* This is a short name for the extension (optional). */
+ const gchar *display_name;
+
+ /* This is a longer description of the extension (optional). */
+ const gchar *description;
+
+ /* This is a NULL-terminated array of supported MIME types.
+ * The MIME types can be exact (e.g. "text/plain") or use a
+ * wildcard (e.g. "text/ *"). */
+ const gchar **mime_types;
+
+ /* This is used to prioritize extensions with identical MIME
+ * types. Lower values win. Defaults to G_PRIORITY_DEFAULT. */
+ gint priority;
+
+ 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);
+};
+
+GType e_mail_formatter_extension_get_type
+ (void) G_GNUC_CONST;
+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);
+
+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..e9f88704c8
--- /dev/null
+++ b/em-format/e-mail-formatter-headers.c
@@ -0,0 +1,595 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <libemail-engine/e-mail-utils.h>
+#include <libedataserver/libedataserver.h>
+#include <e-util/e-util.h>
+#include <shell/e-shell.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-formatter-utils.h"
+#include "e-mail-inline-filter.h"
+#include "e-mail-part-headers.h"
+
+typedef EMailFormatterExtension EMailFormatterHeaders;
+typedef EMailFormatterExtensionClass EMailFormatterHeadersClass;
+
+GType e_mail_formatter_headers_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterHeaders,
+ e_mail_formatter_headers,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "application/vnd.evolution.headers",
+ NULL
+};
+
+static void
+format_short_headers (EMailFormatter *formatter,
+ GString *buffer,
+ EMailPart *part,
+ guint32 flags,
+ GCancellable *cancellable)
+{
+ CamelMimePart *mime_part;
+ GtkTextDirection direction;
+ const gchar *charset;
+ CamelContentType *ct;
+ gchar *hdr_charset;
+ gchar *evolution_imagesdir;
+ gchar *subject = NULL;
+ struct _camel_header_address *addrs = NULL;
+ struct _camel_header_raw *header;
+ GString *from;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ direction = gtk_widget_get_default_direction ();
+
+ ct = camel_mime_part_get_content_type (mime_part);
+ charset = camel_content_type_param (ct, "charset");
+ charset = camel_iconv_charset_name (charset);
+ hdr_charset = e_mail_formatter_dup_charset (formatter);
+ if (!hdr_charset)
+ hdr_charset = e_mail_formatter_dup_default_charset (formatter);
+
+ evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+ from = g_string_new ("");
+
+ g_string_append_printf (
+ buffer,
+ "<table class=\"header\" "
+ "id=\"__evo-short-headers\" style=\"display: %s\">",
+ flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "table" : "none");
+
+ header = mime_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 > 0)
+ g_string_printf (
+ from, "%s: %s",
+ _("From"), 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;
+ }
+
+ g_free (hdr_charset);
+
+ g_string_append (buffer, "<tr class=\"header\">");
+ if (direction == GTK_TEXT_DIR_RTL)
+ g_string_append (buffer, "<td class=\"header rtl\">");
+ else
+ g_string_append (buffer, "<td class=\"header ltr\">");
+ g_string_append (buffer, "<strong>");
+ if (subject != NULL && *subject != '\0')
+ g_string_append (buffer, subject);
+ else
+ g_string_append (buffer, _("(no subject)"));
+ g_string_append (buffer, "</strong>");
+ if (from->len > 0)
+ g_string_append_printf (buffer, " (%s)", from->str);
+ g_string_append (buffer, "</td></tr>");
+
+ g_string_append (buffer, "</table>");
+
+ g_free (subject);
+ if (addrs)
+ camel_header_address_list_clear (&addrs);
+
+ g_string_free (from, TRUE);
+ g_free (evolution_imagesdir);
+
+ g_object_unref (mime_part);
+}
+
+static void
+write_contact_picture (CamelMimePart *mime_part,
+ gint size,
+ GString *buffer)
+{
+ gchar *b64, *content_type;
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+ GByteArray *ba = NULL;
+
+ dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+ if (dw != NULL)
+ ba = camel_data_wrapper_get_byte_array (dw);
+
+ if (ba == NULL || ba->len == 0) {
+ const gchar *filename;
+
+ filename = camel_mime_part_get_filename (mime_part);
+
+ if (filename != NULL) {
+ if (size >= 0) {
+ g_string_append_printf (
+ buffer,
+ "<img width=\"%d\" src=\"evo-file://%s\" />",
+ size, filename);
+ } else {
+ g_string_append_printf (
+ buffer,
+ "<img src=\"evo-file://%s\" />",
+ filename);
+ }
+ }
+
+ return;
+ }
+
+ b64 = g_base64_encode (ba->data, ba->len);
+ ct = camel_mime_part_get_content_type (mime_part);
+ content_type = camel_content_type_simple (ct);
+
+ if (size >= 0) {
+ g_string_append_printf (
+ buffer,
+ "<img width=\"%d\" src=\"data:%s;base64,%s\">",
+ size, content_type, b64);
+ } else {
+ g_string_append_printf (
+ buffer,
+ "<img src=\"data:%s;base64,%s\">",
+ content_type, b64);
+ }
+
+ g_free (b64);
+ g_free (content_type);
+}
+
+static void
+format_full_headers (EMailFormatter *formatter,
+ GString *buffer,
+ EMailPart *part,
+ guint32 mode,
+ guint32 flags,
+ GCancellable *cancellable)
+{
+ CamelMimePart *mime_part;
+ const gchar *charset;
+ CamelContentType *ct;
+ struct _camel_header_raw *header;
+ const gchar *photo_name = NULL;
+ guchar *face_header_value = NULL;
+ gsize face_header_len = 0;
+ gchar *header_sender = NULL, *header_from = NULL, *name;
+ gboolean mail_from_delegate = FALSE;
+ gboolean show_sender_photo;
+ gchar *hdr_charset;
+ gchar *evolution_imagesdir;
+ const gchar *direction;
+
+ g_return_if_fail (E_IS_MAIL_PART_HEADERS (part));
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+
+ switch (gtk_widget_get_default_direction ()) {
+ case GTK_TEXT_DIR_RTL:
+ direction = "rtl";
+ break;
+ case GTK_TEXT_DIR_LTR:
+ direction = "ltr";
+ break;
+ default:
+ direction = "inherit";
+ break;
+ }
+
+ ct = camel_mime_part_get_content_type (mime_part);
+ charset = camel_content_type_param (ct, "charset");
+ charset = camel_iconv_charset_name (charset);
+ hdr_charset = e_mail_formatter_dup_charset (formatter);
+ if (!hdr_charset)
+ hdr_charset = e_mail_formatter_dup_default_charset (formatter);
+
+ evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+
+ g_string_append_printf (
+ buffer,
+ "<table cellspacing=\"0\" cellpadding=\"0\" "
+ "border=\"0\" width=\"100%%\" "
+ "id=\"__evo-full-headers\" "
+ "style=\"display: %s; direction: %s;\">",
+ flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "none" : "table",
+ direction);
+
+ header = mime_part->headers;
+ while (header != NULL) {
+ 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;
+ }
+
+ g_free (hdr_charset);
+
+ if (header_sender && header_from && mail_from_delegate) {
+ gchar *bold_sender, *bold_from;
+
+ g_string_append (
+ buffer,
+ "<tr valign=\"top\"><td><table border=1 width=\"100%\" "
+ "cellspacing=2 cellpadding=2><tr>");
+ if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
+ g_string_append (
+ buffer, "<td align=\"right\" width=\"100%\">");
+ else
+ g_string_append (
+ buffer, "<td align=\"left\" width=\"100%\">");
+ bold_sender = g_strconcat ("<b>", header_sender, "</b>", NULL);
+ bold_from = g_strconcat ("<b>", header_from, "</b>", 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, "</td></tr></table></td></tr>");
+ g_free (bold_sender);
+ g_free (bold_from);
+ }
+
+ g_free (header_sender);
+ g_free (header_from);
+
+ g_string_append (
+ buffer,
+ "<tr valign=\"top\"><td width=\"100%\">"
+ "<table class=\"header\">\n");
+
+ g_free (evolution_imagesdir);
+
+ /* dump selected headers */
+ if (mode & E_MAIL_FORMATTER_MODE_ALL_HEADERS) {
+ header = mime_part->headers;
+ while (header != NULL) {
+ e_mail_formatter_format_header (
+ formatter, buffer,
+ header->name,
+ header->value,
+ E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS, charset);
+ header = header->next;
+ }
+ } else {
+ CamelMedium *medium;
+ gchar **default_headers;
+ guint ii, length = 0;
+
+ medium = CAMEL_MEDIUM (mime_part);
+
+ default_headers =
+ e_mail_part_headers_dup_default_headers (
+ E_MAIL_PART_HEADERS (part));
+ if (default_headers != NULL)
+ length = g_strv_length (default_headers);
+
+ for (ii = 0; ii < length; ii++) {
+ const gchar *header_name;
+ const gchar *header_value = NULL;
+
+ header_name = default_headers[ii];
+
+ /* X-Evolution-Mailer is a pseudo-header and
+ * requires special treatment to extract the
+ * real header value. */
+ if (g_ascii_strcasecmp (header_name, "X-Evolution-Mailer") == 0) {
+ /* Check for "X-MimeOLE" last,
+ * as it's the least preferred. */
+ if (header_value == NULL)
+ header_value = camel_medium_get_header (
+ medium, "X-Mailer");
+ if (header_value == NULL)
+ header_value = camel_medium_get_header (
+ medium, "User-Agent");
+ if (header_value == NULL)
+ header_value = camel_medium_get_header (
+ medium, "X-Newsreader");
+ if (header_value == NULL)
+ header_value = camel_medium_get_header (
+ medium, "X-MimeOLE");
+ } else {
+ header_value = camel_medium_get_header (
+ medium, header_name);
+ }
+
+ if (header_value == NULL)
+ continue;
+
+ if (g_ascii_strcasecmp (header_name, "From") == 0)
+ photo_name = header_value;
+
+ if (g_ascii_strcasecmp (header_name, "Face") == 0) {
+ if (face_header_value == NULL) {
+ const 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;
+ }
+ continue;
+ }
+
+ e_mail_formatter_format_header (
+ formatter, buffer,
+ header_name,
+ header_value,
+ 0, charset);
+ }
+
+ g_strfreev (default_headers);
+ }
+
+ g_string_append (buffer, "</table></td>");
+
+ show_sender_photo =
+ e_mail_formatter_get_show_sender_photo (formatter);
+
+ /* Prefer contact photos over archaic "Face" headers. */
+ if (show_sender_photo && photo_name != NULL) {
+ gchar *name;
+
+ name = g_uri_escape_string (photo_name, NULL, FALSE);
+ g_string_append (
+ buffer,
+ "<td align=\"right\" valign=\"top\">");
+ g_string_append_printf (
+ buffer,
+ "<img src=\"mail://contact-photo?mailaddr=\" "
+ "data-mailaddr=\"%s\" id=\"__evo-contact-photo\"/>",
+ name);
+ g_string_append (buffer, "</td>");
+
+ g_free (name);
+
+ } else if (face_header_value != NULL) {
+ CamelMimePart *image_part;
+
+ image_part = camel_mime_part_new ();
+ camel_mime_part_set_content (
+ image_part,
+ (const gchar *) face_header_value,
+ face_header_len, "image/png");
+
+ g_string_append (
+ buffer,
+ "<td align=\"right\" valign=\"top\">");
+ write_contact_picture (image_part, 48, buffer);
+ g_string_append (buffer, "</td>");
+
+ g_object_unref (image_part);
+ g_free (face_header_value);
+ }
+
+ g_string_append (buffer, "</tr></table>");
+
+ g_object_unref (mime_part);
+}
+
+static gboolean
+emfe_headers_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ CamelMimePart *mime_part;
+ GString *buffer;
+ const GdkRGBA white = { 1.0, 1.0, 1.0, 1.0 };
+ const GdkRGBA *body_rgba = &white;
+ const GdkRGBA *header_rgba;
+ const gchar *direction;
+ gboolean is_collapsable;
+ gboolean is_collapsed;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ if (mime_part == NULL)
+ return FALSE;
+
+ switch (gtk_widget_get_default_direction ()) {
+ case GTK_TEXT_DIR_RTL:
+ direction = "rtl";
+ break;
+ case GTK_TEXT_DIR_LTR:
+ direction = "ltr";
+ break;
+ default:
+ direction = "inherit";
+ break;
+ }
+
+ is_collapsable =
+ (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE);
+
+ is_collapsed =
+ (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED);
+
+ buffer = g_string_new ("");
+
+ if (context->mode != E_MAIL_FORMATTER_MODE_PRINTING)
+ body_rgba = e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_BODY);
+
+ header_rgba = e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_HEADER);
+
+ g_string_append_printf (
+ buffer,
+ "<div class=\"headers\" style=\"background: #%06x;\" id=\"%s\">"
+ "<table border=\"0\" width=\"100%%\" "
+ "style=\"color: #%06x; direction: %s\">"
+ "<tr>",
+ e_rgba_to_value (body_rgba),
+ e_mail_part_get_id (part),
+ e_rgba_to_value (header_rgba),
+ direction);
+
+ if (is_collapsable)
+ g_string_append_printf (
+ buffer,
+ "<td valign=\"top\" width=\"16\">"
+ "<img src=\"evo-file://%s/%s\" class=\"navigable\" "
+ " id=\"__evo-collapse-headers-img\" />"
+ "</td>",
+ EVOLUTION_IMAGESDIR,
+ is_collapsed ? "plus.png" : "minus.png");
+
+ g_string_append (buffer, "<td>");
+
+ if (is_collapsable)
+ format_short_headers (
+ formatter,
+ buffer, part,
+ context->flags,
+ cancellable);
+
+ format_full_headers (
+ formatter,
+ buffer, part,
+ context->mode,
+ context->flags,
+ cancellable);
+
+ g_string_append (buffer, "</td>");
+
+ g_string_append (buffer, "</tr></table></div>");
+
+ camel_stream_write_string (stream, buffer->str, cancellable, NULL);
+
+ g_string_free (buffer, TRUE);
+
+ g_object_unref (mime_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_headers_class_init (EMailFormatterExtensionClass *class)
+{
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_headers_format;
+}
+
+static void
+e_mail_formatter_headers_init (EMailFormatterExtension *extension)
+{
+}
diff --git a/em-format/e-mail-formatter-image.c b/em-format/e-mail-formatter-image.c
new file mode 100644
index 0000000000..c3330e0db3
--- /dev/null
+++ b/em-format/e-mail-formatter-image.c
@@ -0,0 +1,162 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-inline-filter.h"
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailFormatterExtension EMailFormatterImage;
+typedef EMailFormatterExtensionClass EMailFormatterImageClass;
+
+GType e_mail_formatter_image_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterImage,
+ e_mail_formatter_image,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+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
+};
+
+static gboolean
+emfe_image_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ gchar *content;
+ CamelMimePart *mime_part;
+ CamelDataWrapper *dw;
+ GByteArray *ba;
+ CamelStream *raw_content;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ dw = camel_medium_get_content (CAMEL_MEDIUM (mime_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;
+ const gchar *mime_type;
+
+ 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);
+ }
+
+ mime_type = e_mail_part_get_mime_type (part);
+ if (mime_type == NULL)
+ mime_type = "image/*";
+
+ /* The image is already base64-encrypted so we can directly
+ * paste it to the output */
+ buffer = g_strdup_printf (
+ "<img src=\"data:%s;base64,%s\" "
+ " style=\"max-width: 100%%;\" />",
+ mime_type, content);
+
+ camel_stream_write_string (stream, buffer, cancellable, NULL);
+ g_free (buffer);
+ g_free (content);
+ }
+
+ g_object_unref (raw_content);
+
+ g_object_unref (mime_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_image_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("Regular Image");
+ class->description = _("Display part as an image");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_image_format;
+}
+
+static void
+e_mail_formatter_image_init (EMailFormatterExtension *extension)
+{
+}
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..0477e61517
--- /dev/null
+++ b/em-format/e-mail-formatter-message-rfc822.c
@@ -0,0 +1,262 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-part-list.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailFormatterExtension EMailFormatterMessageRFC822;
+typedef EMailFormatterExtensionClass EMailFormatterMessageRFC822Class;
+
+GType e_mail_formatter_message_rfc822_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterMessageRFC822,
+ e_mail_formatter_message_rfc822,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "message/rfc822",
+ "application/vnd.evolution.rfc822.end",
+ NULL
+};
+
+static gboolean
+emfe_message_rfc822_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ const gchar *part_id;
+
+ part_id = e_mail_part_get_id (part);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+ 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;
+
+ e_mail_part_list_queue_parts (
+ context->part_list, part_id, &queue);
+
+ /* Discard the first EMailPart. */
+ if (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ head = g_queue_peek_head_link (&queue);
+
+ end = g_strconcat (part_id, ".end", NULL);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *p = link->data;
+ const gchar *p_id;
+
+ p_id = e_mail_part_get_id (p);
+
+ /* Check for nested rfc822 messages */
+ if (e_mail_part_id_has_suffix (p, ".rfc822")) {
+ gchar *sub_end = g_strconcat (p_id, ".end", NULL);
+
+ while (link != NULL) {
+ p = link->data;
+
+ if (g_strcmp0 (p_id, sub_end) == 0)
+ break;
+
+ link = g_list_next (link);
+ }
+ 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);
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ context->mode = E_MAIL_FORMATTER_MODE_RAW;
+
+ camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+
+ } else if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+ gchar *end;
+
+ /* Part is EMailPartAttachment */
+ e_mail_part_list_queue_parts (
+ context->part_list, part_id, &queue);
+
+ /* Discard the first EMailPart. */
+ if (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ if (g_queue_is_empty (&queue))
+ return FALSE;
+
+ part = g_queue_pop_head (&queue);
+ end = g_strconcat (part_id, ".end", NULL);
+ g_object_unref (part);
+
+ head = g_queue_peek_head_link (&queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *p = link->data;
+ const gchar *p_id;
+
+ /* Skip attachment bar */
+ if (e_mail_part_id_has_suffix (part, ".attachment-bar"))
+ continue;
+
+ p_id = e_mail_part_get_id (p);
+
+ /* Check for nested rfc822 messages */
+ if (e_mail_part_id_has_suffix (p, ".rfc822")) {
+ gchar *sub_end = g_strconcat (p_id, ".end", NULL);
+
+ while (link != NULL) {
+ p = link->data;
+
+ if (g_strcmp0 (p_id, sub_end) == 0)
+ break;
+
+ link = g_list_next (link);
+ }
+ 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);
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ } else {
+ EMailPart *p;
+ CamelFolder *folder;
+ const gchar *message_uid;
+ const gchar *default_charset, *charset;
+ gchar *str;
+ gchar *uri;
+
+ p = e_mail_part_list_ref_part (context->part_list, part_id);
+ if (p == NULL)
+ return FALSE;
+
+ folder = e_mail_part_list_get_folder (context->part_list);
+ message_uid = e_mail_part_list_get_message_uid (context->part_list);
+ default_charset = e_mail_formatter_get_default_charset (formatter);
+ charset = e_mail_formatter_get_charset (formatter);
+
+ if (!default_charset)
+ default_charset = "";
+ if (!charset)
+ charset = "";
+
+ uri = e_mail_part_build_uri (
+ folder, message_uid,
+ "part_id", G_TYPE_STRING, e_mail_part_get_id (p),
+ "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+ "headers_collapsable", G_TYPE_INT, 0,
+ "formatter_default_charset", G_TYPE_STRING, default_charset,
+ "formatter_charset", G_TYPE_STRING, charset,
+ NULL);
+
+ str = g_strdup_printf (
+ "<div class=\"part-container\" style=\"border-color: #%06x; "
+ "background-color: #%06x;\">\n"
+ "<iframe width=\"100%%\" height=\"10\""
+ " id=\"%s.iframe\" "
+ " frameborder=\"0\" src=\"%s\" name=\"%s\"></iframe>"
+ "</div>",
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+ e_rgba_to_value (
+ 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);
+
+ g_object_unref (p);
+ }
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_message_rfc822_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("RFC822 message");
+ class->description = _("Format part as an RFC822 message");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_message_rfc822_format;
+}
+
+static void
+e_mail_formatter_message_rfc822_init (EMailFormatterExtension *extension)
+{
+}
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..29aa93a278
--- /dev/null
+++ b/em-format/e-mail-formatter-print-headers.c
@@ -0,0 +1,235 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include <e-util/e-util.h>
+#include <libemail-engine/e-mail-utils.h>
+
+#include "e-mail-formatter-print.h"
+#include "e-mail-formatter-utils.h"
+#include "e-mail-inline-filter.h"
+#include "e-mail-part-headers.h"
+
+typedef EMailFormatterExtension EMailFormatterPrintHeaders;
+typedef EMailFormatterExtensionClass EMailFormatterPrintHeadersClass;
+
+GType e_mail_formatter_print_headers_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterPrintHeaders,
+ e_mail_formatter_print_headers,
+ E_TYPE_MAIL_FORMATTER_PRINT_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "application/vnd.evolution.headers",
+ NULL
+};
+
+static gboolean
+emfpe_headers_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ EMailPartHeaders *headers_part;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ gboolean iter_valid;
+ GString *str, *tmp;
+ gchar *subject;
+ const gchar *buf;
+ gint attachments_count;
+ gchar *part_id_prefix;
+ CamelMimePart *mime_part;
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+ const gchar *part_id;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_HEADERS (part), FALSE);
+
+ mime_part = e_mail_part_ref_mime_part (part);
+
+ buf = camel_medium_get_header (CAMEL_MEDIUM (mime_part), "subject");
+ subject = camel_header_decode_string (buf, "UTF-8");
+ str = g_string_new ("");
+ g_string_append_printf (str, "<h1>%s</h1>\n", subject);
+ g_free (subject);
+
+ g_string_append (
+ str,
+ "<table border=\"0\" cellspacing=\"5\" "
+ "cellpadding=\"0\" class=\"printing-header\">\n");
+
+ headers_part = E_MAIL_PART_HEADERS (part);
+ tree_model = e_mail_part_headers_ref_print_model (headers_part);
+ iter_valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (iter_valid) {
+ gchar *header_name = NULL;
+ gchar *header_value = NULL;
+ gboolean include = FALSE;
+
+ gtk_tree_model_get (
+ tree_model, &iter,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_INCLUDE,
+ &include,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_HEADER_NAME,
+ &header_name,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_HEADER_VALUE,
+ &header_value,
+ -1);
+
+ if (include)
+ e_mail_formatter_format_header (
+ formatter, str,
+ header_name, header_value,
+ E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS,
+ "UTF-8");
+
+ g_free (header_name);
+ g_free (header_value);
+
+ iter_valid = gtk_tree_model_iter_next (tree_model, &iter);
+ }
+
+ g_object_unref (tree_model);
+
+ /* Get prefix of this PURI */
+ part_id = e_mail_part_get_id (part);
+ part_id_prefix = g_strndup (part_id, g_strrstr (part_id, ".") - part_id);
+
+ /* Add encryption/signature header */
+ tmp = g_string_new ("");
+
+ e_mail_part_list_queue_parts (context->part_list, NULL, &queue);
+
+ head = g_queue_peek_head_link (&queue);
+
+ /* Find first secured part. */
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ if (!e_mail_part_has_validity (mail_part))
+ continue;
+
+ if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix))
+ continue;
+
+ if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SIGNED)) {
+ g_string_append (tmp, _("GPG signed"));
+ }
+
+ if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_ENCRYPTED)) {
+ if (tmp->len > 0)
+ g_string_append (tmp, ", ");
+ g_string_append (tmp, _("GPG encrpyted"));
+ }
+
+ if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_SIGNED)) {
+ if (tmp->len > 0)
+ g_string_append (tmp, ", ");
+ g_string_append (tmp, _("S/MIME signed"));
+ }
+
+ if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | 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) {
+ e_mail_formatter_format_header (
+ formatter, str,
+ _("Security"), tmp->str,
+ 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 (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = E_MAIL_PART (link->data);
+
+ if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix))
+ continue;
+
+ if (!e_mail_part_get_is_attachment (mail_part))
+ continue;
+
+ if (mail_part->is_hidden)
+ continue;
+
+ if (e_mail_part_get_cid (mail_part) != NULL)
+ continue;
+
+ attachments_count++;
+ }
+
+ if (attachments_count > 0) {
+ gchar *header_value;
+
+ header_value = g_strdup_printf ("%d", attachments_count);
+ e_mail_formatter_format_header (
+ formatter, str,
+ _("Attachments"), header_value,
+ E_MAIL_FORMATTER_HEADER_FLAG_BOLD |
+ E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, "UTF-8");
+ g_free (header_value);
+ }
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ g_string_append (str, "</table>");
+
+ camel_stream_write_string (stream, str->str, cancellable, NULL);
+ g_string_free (str, TRUE);
+ g_free (part_id_prefix);
+
+ g_object_unref (mime_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_print_headers_class_init (EMailFormatterExtensionClass *class)
+{
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfpe_headers_format;
+}
+
+static void
+e_mail_formatter_print_headers_init (EMailFormatterExtension *extension)
+{
+}
diff --git a/em-format/e-mail-formatter-print.c b/em-format/e-mail-formatter-print.c
new file mode 100644
index 0000000000..4d5c303d03
--- /dev/null
+++ b/em-format/e-mail-formatter-print.c
@@ -0,0 +1,295 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter-print.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 <gdk/gdk.h>
+#include <glib/gi18n.h>
+
+#define STYLESHEET_URI \
+ "evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview-print.css"
+
+/* internal formatter extensions */
+GType e_mail_formatter_print_headers_get_type (void);
+
+void e_mail_formatter_print_internal_extensions_load (EMailExtensionRegistry *ereg);
+
+static gpointer e_mail_formatter_print_parent_class = 0;
+
+static void
+mail_formatter_print_write_attachments (EMailFormatter *formatter,
+ GQueue *attachments,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ GString *str;
+
+ str = g_string_new (
+ "<table border=\"0\" cellspacing=\"5\" cellpadding=\"0\" "
+ "class=\"attachments-list\" >\n");
+ g_string_append_printf (
+ str,
+ "<tr><th colspan=\"2\"><h1>%s</h1></td></tr>\n"
+ "<tr><th>%s</th><th>%s</th></tr>\n",
+ _("Attachments"), _("Name"), _("Size"));
+
+ while (!g_queue_is_empty (attachments)) {
+ EMailPartAttachment *part;
+ EAttachment *attachment;
+ GFileInfo *file_info;
+ const gchar *display_name;
+ gchar *description;
+ gchar *name;
+ gchar *size;
+
+ part = g_queue_pop_head (attachments);
+ attachment = e_mail_part_attachment_ref_attachment (part);
+
+ file_info = e_attachment_ref_file_info (attachment);
+ if (file_info == NULL) {
+ g_object_unref (attachment);
+ continue;
+ }
+
+ description = e_attachment_dup_description (attachment);
+ display_name = g_file_info_get_display_name (file_info);
+
+ if (description != NULL && *description != '\0') {
+ name = g_strdup_printf (
+ "%s (%s)", description, display_name);
+ } else {
+ name = g_strdup (display_name);
+ }
+
+ size = g_format_size (g_file_info_get_size (file_info));
+
+ g_string_append_printf (
+ str, "<tr><td>%s</td><td>%s</td></tr>\n",
+ name, size);
+
+ g_free (description);
+ g_free (name);
+ g_free (size);
+
+ g_object_unref (attachment);
+ g_object_unref (file_info);
+ }
+
+ g_string_append (str, "</table>\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)
+{
+ GQueue queue = G_QUEUE_INIT;
+ GQueue attachments = G_QUEUE_INIT;
+ GList *head, *link;
+
+ context->mode = E_MAIL_FORMATTER_MODE_PRINTING;
+
+ camel_stream_write_string (
+ stream,
+ "<!DOCTYPE HTML>\n"
+ "<html>\n"
+ "<head>\n"
+ "<meta name=\"generator\" content=\"Evolution Mail\" />\n"
+ "<title>Evolution Mail Display</title>\n"
+ "<link type=\"text/css\" rel=\"stylesheet\" "
+ " media=\"print\" href=\"" STYLESHEET_URI "/>\n"
+ "</head>\n"
+ "<body style=\"background: #FFF; color: #000;\">",
+ cancellable, NULL);
+
+ e_mail_part_list_queue_parts (context->part_list, NULL, &queue);
+
+ head = g_queue_peek_head_link (&queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *part = E_MAIL_PART (link->data);
+ const gchar *mime_type;
+ gboolean ok;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ break;
+
+ if (part->is_hidden && !part->is_error) {
+ if (e_mail_part_id_has_suffix (part, ".rfc822")) {
+ link = e_mail_formatter_find_rfc822_end_iter (link);
+ }
+
+ continue;
+ }
+
+ mime_type = e_mail_part_get_mime_type (part);
+ if (mime_type == NULL)
+ continue;
+
+ if (e_mail_part_get_is_attachment (part)) {
+ if (e_mail_part_get_cid (part) != NULL)
+ continue;
+
+ g_queue_push_tail (&attachments, part);
+ }
+
+ ok = e_mail_formatter_format_as (
+ formatter, context, part, stream,
+ 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 && e_mail_part_id_has_suffix (part, ".rfc822")) {
+ link = e_mail_formatter_find_rfc822_end_iter (link);
+
+ continue;
+ }
+ }
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ /* This consumes the attachments queue. */
+ if (!g_queue_is_empty (&attachments))
+ mail_formatter_print_write_attachments (
+ formatter, &attachments,
+ stream, cancellable);
+
+ camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+}
+
+static void
+mail_formatter_update_style (EMailFormatter *formatter,
+ GtkStateFlags state)
+{
+ /* White background */
+ GdkRGBA body_color = { 1.0, 1.0, 1.0, 1.0 };
+ /* Black text */
+ GdkRGBA text_color = { 0.0, 0.0, 0.0, 0.0 };
+
+ g_object_freeze_notify (G_OBJECT (formatter));
+
+ /* Chain up to parent's update_style() method. */
+ E_MAIL_FORMATTER_CLASS (e_mail_formatter_print_parent_class)->
+ update_style (formatter, 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_class_init (EMailFormatterPrintClass *class)
+{
+ EMailFormatterClass *formatter_class;
+
+ e_mail_formatter_print_parent_class = g_type_class_peek_parent (class);
+
+ formatter_class = E_MAIL_FORMATTER_CLASS (class);
+ formatter_class->run = mail_formatter_print_run;
+ formatter_class->update_style = mail_formatter_update_style;
+}
+
+static void
+e_mail_formatter_print_base_init (EMailFormatterPrintClass *class)
+{
+ /* Register internal extensions. */
+ g_type_ensure (e_mail_formatter_print_headers_get_type ());
+
+ e_mail_formatter_extension_registry_load (
+ E_MAIL_FORMATTER_CLASS (class)->extension_registry,
+ E_TYPE_MAIL_FORMATTER_PRINT_EXTENSION);
+
+ E_MAIL_FORMATTER_CLASS (class)->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;
+}
+
+/* ------------------------------------------------------------------------- */
+
+G_DEFINE_ABSTRACT_TYPE (
+ EMailFormatterPrintExtension,
+ e_mail_formatter_print_extension,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static void
+e_mail_formatter_print_extension_class_init (EMailFormatterPrintExtensionClass *class)
+{
+}
+
+static void
+e_mail_formatter_print_extension_init (EMailFormatterPrintExtension *extension)
+{
+}
+
diff --git a/em-format/e-mail-formatter-print.h b/em-format/e-mail-formatter-print.h
new file mode 100644
index 0000000000..e94ca75b7c
--- /dev/null
+++ b/em-format/e-mail-formatter-print.h
@@ -0,0 +1,93 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_PRINT_H
+#define E_MAIL_FORMATTER_PRINT_H
+
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-formatter-extension.h>
+
+/* 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;
+
+struct _EMailFormatterPrint {
+ EMailFormatter parent;
+};
+
+struct _EMailFormatterPrintClass {
+ EMailFormatterClass parent_class;
+};
+
+GType e_mail_formatter_print_get_type (void) G_GNUC_CONST;
+EMailFormatter *
+ e_mail_formatter_print_new (void);
+
+G_END_DECLS
+
+/* ------------------------------------------------------------------------- */
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FORMATTER_PRINT_EXTENSION \
+ (e_mail_formatter_print_extension_get_type ())
+
+G_BEGIN_DECLS
+
+/**
+ * EMailFormatterPrintExtension:
+ *
+ * This is an abstract base type for formatter extensions which are
+ * intended only for use by #EMailFormatterPrint.
+ **/
+typedef struct _EMailFormatterPrintExtension EMailFormatterPrintExtension;
+typedef struct _EMailFormatterPrintExtensionClass EMailFormatterPrintExtensionClass;
+
+struct _EMailFormatterPrintExtension {
+ EMailFormatterExtension parent;
+};
+
+struct _EMailFormatterPrintExtensionClass {
+ EMailFormatterExtensionClass parent_class;
+};
+
+GType e_mail_formatter_print_extension_get_type
+ (void) G_GNUC_CONST;
+
+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..1a6b19408c
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-attachment.c
@@ -0,0 +1,126 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-quote.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-utils.h"
+
+#define d(x)
+
+typedef EMailFormatterExtension EMailFormatterQuoteAttachment;
+typedef EMailFormatterExtensionClass EMailFormatterQuoteAttachmentClass;
+
+GType e_mail_formatter_quote_attachment_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterQuoteAttachment,
+ e_mail_formatter_quote_attachment,
+ E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ E_MAIL_PART_ATTACHMENT_MIME_TYPE,
+ NULL
+};
+
+static gboolean
+emfqe_attachment_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ gchar *text, *html;
+ EMailPartAttachment *empa;
+ EMailPart *attachment_view_part;
+ CamelMimeFilterToHTMLFlags text_format_flags;
+ CamelMimePart *mime_part;
+
+ empa = E_MAIL_PART_ATTACHMENT (part);
+
+ if (!empa->attachment_view_part_id)
+ return FALSE;
+
+ attachment_view_part = e_mail_part_list_ref_part (
+ context->part_list, empa->attachment_view_part_id);
+ if (attachment_view_part == NULL)
+ return FALSE;
+
+ camel_stream_write_string (stream, "<br><br>", cancellable, NULL);
+
+ text_format_flags =
+ e_mail_formatter_get_text_format_flags (formatter);
+ mime_part = e_mail_part_ref_mime_part (part);
+ text = e_mail_part_describe (
+ mime_part,
+ empa ? empa->snoop_mime_type :
+ e_mail_part_get_mime_type (part));
+ g_object_unref (mime_part);
+
+ 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, "<br>", cancellable, NULL);
+ g_free (html);
+ g_free (text);
+
+ camel_stream_write_string (
+ stream,
+ "<!--+GtkHTML:<DATA class=\"ClueFlow\" "
+ "key=\"orig\" value=\"1\">-->\n"
+ "<blockquote type=cite>\n", cancellable, NULL);
+
+ e_mail_formatter_format_as (
+ formatter, context, attachment_view_part,
+ stream, NULL, cancellable);
+
+ camel_stream_write_string (
+ stream,
+ "</blockquote><!--+GtkHTML:"
+ "<DATA class=\"ClueFlow\" clear=\"orig\">-->",
+ cancellable, NULL);
+
+ g_object_unref (attachment_view_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_quote_attachment_class_init (EMailFormatterExtensionClass *class)
+{
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_HIGH;
+ class->format = emfqe_attachment_format;
+}
+
+static void
+e_mail_formatter_quote_attachment_init (EMailFormatterExtension *extension)
+{
+}
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..e95e0c9489
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-headers.c
@@ -0,0 +1,279 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include <e-util/e-util.h>
+#include <libemail-engine/e-mail-utils.h>
+
+#include "e-mail-formatter-quote.h"
+#include "e-mail-formatter-utils.h"
+#include "e-mail-inline-filter.h"
+#include "e-mail-part-headers.h"
+
+typedef EMailFormatterExtension EMailFormatterQuoteHeaders;
+typedef EMailFormatterExtensionClass EMailFormatterQuoteHeadersClass;
+
+GType e_mail_formatter_quote_headers_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterQuoteHeaders,
+ e_mail_formatter_quote_headers,
+ E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "application/vnd.evolution.headers",
+ NULL
+};
+
+static void
+emfqe_format_text_header (EMailFormatter *emf,
+ GString *buffer,
+ const gchar *label,
+ const gchar *value,
+ guint32 flags,
+ gint is_html)
+{
+ const gchar *html;
+ gchar *mhtml = NULL;
+
+ if (value == NULL)
+ return;
+
+ while (*value == ' ')
+ value++;
+
+ if (!is_html)
+ html = mhtml = camel_text_to_html (value, 0, 0);
+ else
+ html = value;
+
+ if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD)
+ g_string_append_printf (
+ buffer, "<b>%s</b>: %s<br>", label, html);
+ else
+ g_string_append_printf (
+ buffer, "%s: %s<br>", label, html);
+
+ g_free (mhtml);
+}
+
+/* XXX: This is copied in e-mail-formatter-utils.c */
+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
+};
+
+static void
+emfqe_format_header (EMailFormatter *formatter,
+ GString *buffer,
+ EMailPart *part,
+ const gchar *header_name,
+ const gchar *charset)
+{
+ CamelMimePart *mime_part;
+ EMailFormatterHeaderFlags flags;
+ gchar *canon_name, *buf, *value = NULL;
+ const gchar *txt, *label;
+ gboolean addrspec = FALSE;
+ gint is_html = FALSE;
+ gint i;
+
+ flags = E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE;
+
+ canon_name = g_alloca (strlen (header_name) + 1);
+ strcpy (canon_name, header_name);
+ e_mail_formatter_canon_header_name (canon_name);
+
+ /* Never quote Bcc/Resent-Bcc headers. */
+ if (g_str_equal (canon_name, "Bcc"))
+ return;
+ if (g_str_equal (canon_name, "Resent-Bcc"))
+ return;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+
+ for (i = 0; addrspec_hdrs[i]; i++) {
+ if (g_str_equal (canon_name, addrspec_hdrs[i])) {
+ addrspec = TRUE;
+ break;
+ }
+ }
+
+ label = _(canon_name);
+
+ if (addrspec) {
+ CamelMedium *medium;
+ struct _camel_header_address *addrs;
+ GString *html;
+ gchar *charset;
+
+ medium = CAMEL_MEDIUM (mime_part);
+ txt = camel_medium_get_header (medium, canon_name);
+ if (txt == NULL)
+ return;
+
+ charset = e_mail_formatter_dup_charset (formatter);
+ if (!charset)
+ charset = e_mail_formatter_dup_default_charset (formatter);
+
+ buf = camel_header_unfold (txt);
+ addrs = camel_header_address_decode (txt, charset);
+ g_free (charset);
+
+ if (addrs == NULL) {
+ g_free (buf);
+ return;
+ }
+
+ g_free (buf);
+
+ html = g_string_new ("");
+ e_mail_formatter_format_address (formatter, html,
+ addrs, canon_name, FALSE, FALSE);
+ camel_header_address_unref (addrs);
+ txt = value = html->str;
+ g_string_free (html, FALSE);
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+ is_html = TRUE;
+
+ } else if (g_str_equal (canon_name, "Subject")) {
+ CamelMimeMessage *message;
+
+ message = CAMEL_MIME_MESSAGE (mime_part);
+ txt = camel_mime_message_get_subject (message);
+ label = _("Subject");
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_name, "X-Evolution-Mailer")) {
+ CamelMedium *medium;
+
+ medium = CAMEL_MEDIUM (mime_part);
+ txt = camel_medium_get_header (medium, "x-mailer");
+ if (txt == NULL)
+ txt = camel_medium_get_header (medium, "user-agent");
+ if (txt == NULL)
+ txt = camel_medium_get_header (medium, "x-newsreader");
+ if (txt == NULL)
+ txt = camel_medium_get_header (medium, "x-mimeole");
+ if (txt == NULL)
+ return;
+
+ txt = value = camel_header_format_ctext (txt, charset);
+
+ label = _("Mailer");
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_name, "Date") ||
+ g_str_equal (canon_name, "Resent-Date")) {
+ CamelMedium *medium;
+
+ medium = CAMEL_MEDIUM (mime_part);
+ txt = camel_medium_get_header (medium, canon_name);
+ if (txt == NULL)
+ return;
+
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else {
+ CamelMedium *medium;
+
+ medium = CAMEL_MEDIUM (mime_part);
+ txt = camel_medium_get_header (medium, canon_name);
+ buf = camel_header_unfold (txt);
+ txt = value = camel_header_decode_string (txt, charset);
+ g_free (buf);
+ }
+
+ emfqe_format_text_header (formatter, buffer, label, txt, flags, is_html);
+
+ g_free (value);
+
+ g_object_unref (mime_part);
+}
+
+static gboolean
+emqfe_headers_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ CamelContentType *ct;
+ CamelMimePart *mime_part;
+ const gchar *charset;
+ GString *buffer;
+ gchar **default_headers;
+ guint ii, length = 0;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_HEADERS (part), FALSE);
+
+ mime_part = e_mail_part_ref_mime_part (part);
+
+ ct = camel_mime_part_get_content_type (mime_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_part_headers_dup_default_headers (
+ E_MAIL_PART_HEADERS (part));
+ if (default_headers != NULL)
+ length = g_strv_length (default_headers);
+
+ for (ii = 0; ii < length; ii++)
+ emfqe_format_header (
+ formatter, buffer, part,
+ default_headers[ii], charset);
+
+ g_strfreev (default_headers);
+
+ g_string_append (buffer, "<br>\n");
+
+ camel_stream_write_string (stream, buffer->str, cancellable, NULL);
+
+ g_string_free (buffer, TRUE);
+
+ g_object_unref (mime_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_quote_headers_class_init (EMailFormatterExtensionClass *class)
+{
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_HIGH;
+ class->format = emqfe_headers_format;
+}
+
+static void
+e_mail_formatter_quote_headers_init (EMailFormatterExtension *extension)
+{
+}
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..15a9056062
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-message-rfc822.c
@@ -0,0 +1,154 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-quote.h"
+#include "e-mail-part-list.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailFormatterExtension EMailFormatterQuoteMessageRFC822;
+typedef EMailFormatterExtensionClass EMailFormatterQuoteMessageRFC822Class;
+
+GType e_mail_formatter_quote_message_rfc822_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterQuoteMessageRFC822,
+ e_mail_formatter_quote_message_rfc822,
+ E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "message/rfc822",
+ "application/vnd.evolution.rfc822.end",
+ NULL
+};
+
+static gboolean
+emfqe_message_rfc822_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+ gchar *header, *end;
+ EMailFormatterQuoteContext *qc = (EMailFormatterQuoteContext *) context;
+ const gchar *part_id;
+
+ part_id = e_mail_part_get_id (part);
+
+ 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);
+
+ e_mail_part_list_queue_parts (context->part_list, part_id, &queue);
+
+ if (g_queue_is_empty (&queue))
+ return FALSE;
+
+ /* Discard the first EMailPart. */
+ g_object_unref (g_queue_pop_head (&queue));
+
+ head = g_queue_peek_head (&queue);
+
+ end = g_strconcat (part_id, ".end", NULL);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *p = link->data;
+ const gchar *p_id;
+
+ p_id = e_mail_part_get_id (p);
+
+ /* Skip attachment bar */
+ if (e_mail_part_id_has_suffix (p, ".attachment-bar"))
+ continue;
+
+ if (e_mail_part_id_has_suffix (p, ".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 (e_mail_part_id_has_suffix (p, ".rfc822")) {
+ gchar *sub_end = g_strconcat (p_id, ".end", NULL);
+
+ while (link != NULL) {
+ p = link->data;
+
+ if (g_strcmp0 (p_id, sub_end) == 0)
+ break;
+
+ link = g_list_next (link);
+ }
+ 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);
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_quote_message_rfc822_class_init (EMailFormatterExtensionClass *class)
+{
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_HIGH;
+ class->format = emfqe_message_rfc822_format;
+}
+
+static void
+e_mail_formatter_quote_message_rfc822_init (EMailFormatterExtension *extension)
+{
+}
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..06a67592a7
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-text-enriched.c
@@ -0,0 +1,101 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-quote.h"
+#include "e-mail-inline-filter.h"
+
+typedef EMailFormatterExtension EMailFormatterQuoteTextEnriched;
+typedef EMailFormatterExtensionClass EMailFormatterQuoteTextEnrichedClass;
+
+GType e_mail_formatter_quote_text_enriched_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterQuoteTextEnriched,
+ e_mail_formatter_quote_text_enriched,
+ E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "text/enriched",
+ "text/richtext",
+ NULL
+};
+
+static gboolean
+emqfe_text_enriched_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ CamelStream *filtered_stream;
+ CamelMimeFilter *enriched;
+ const gchar *mime_type;
+ guint32 camel_flags = 0;
+
+ mime_type = e_mail_part_get_mime_type (part);
+
+ if (g_strcmp0 (mime_type, "text/richtext") == 0) {
+ camel_flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
+ camel_stream_write_string (
+ stream, "\n<!-- text/richtext -->\n",
+ cancellable, NULL);
+ } else {
+ camel_stream_write_string (
+ stream, "\n<!-- text/enriched -->\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, "<br><hr><br>", 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 void
+e_mail_formatter_quote_text_enriched_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("Richtext");
+ class->description = _("Display part as enriched text");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_HIGH;
+ class->format = emqfe_text_enriched_format;
+}
+
+static void
+e_mail_formatter_quote_text_enriched_init (EMailFormatterExtension *extension)
+{
+}
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..1d4f7c5794
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-text-html.c
@@ -0,0 +1,100 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-quote.h"
+#include "e-mail-part-utils.h"
+#include "e-mail-stripsig-filter.h"
+
+typedef EMailFormatterExtension EMailFormatterQuoteTextHTML;
+typedef EMailFormatterExtensionClass EMailFormatterQuoteTextHTMLClass;
+
+GType e_mail_formatter_quote_text_html_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterQuoteTextHTML,
+ e_mail_formatter_quote_text_html,
+ E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "text/html",
+ NULL
+};
+
+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<!-- text/html -->\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 void
+e_mail_formatter_quote_text_html_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("HTML");
+ class->description = _("Format part as HTML");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_HIGH;
+ class->format = emqfe_text_html_format;
+}
+
+static void
+e_mail_formatter_quote_text_html_init (EMailFormatterExtension *extension)
+{
+}
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..efe0638e44
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-text-plain.c
@@ -0,0 +1,125 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-quote.h"
+#include "e-mail-part-utils.h"
+#include "e-mail-stripsig-filter.h"
+
+typedef EMailFormatterExtension EMailFormatterQuoteTextPlain;
+typedef EMailFormatterExtensionClass EMailFormatterQuoteTextPlainClass;
+
+GType e_mail_formatter_quote_text_plain_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterQuoteTextPlain,
+ e_mail_formatter_quote_text_plain,
+ E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "text/plain",
+ NULL
+};
+
+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;
+ CamelMimePart *mime_part;
+ CamelContentType *type;
+ EMailFormatterQuoteContext *qf_context;
+ CamelMimeFilterToHTMLFlags text_flags;
+ const gchar *format;
+ guint32 rgb = 0x737373;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ if (mime_part == NULL)
+ 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 (mime_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);
+
+ g_object_unref (mime_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_quote_text_plain_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("Plain Text");
+ class->description = _("Format part as plain text");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_HIGH;
+ class->format = emqfe_text_plain_format;
+}
+
+static void
+e_mail_formatter_quote_text_plain_init (EMailFormatterExtension *extension)
+{
+}
diff --git a/em-format/e-mail-formatter-quote.c b/em-format/e-mail-formatter-quote.c
new file mode 100644
index 0000000000..99c4de9520
--- /dev/null
+++ b/em-format/e-mail-formatter-quote.c
@@ -0,0 +1,250 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter-quote.h"
+
+#include <camel/camel.h>
+
+#include "e-mail-formatter-quote.h"
+#include "e-mail-formatter-utils.h"
+#include "e-mail-part.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-utils.h"
+
+#include <libebackend/libebackend.h>
+#include <gdk/gdk.h>
+#include <glib/gi18n.h>
+
+#define E_MAIL_FORMATTER_QUOTE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuotePrivate))
+
+struct _EMailFormatterQuotePrivate {
+ gchar *credits;
+ EMailFormatterQuoteFlags flags;
+};
+
+/* internal formatter extensions */
+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);
+
+void e_mail_formatter_quote_internal_extensions_load (EMailExtensionRegistry *ereg);
+
+static gpointer e_mail_formatter_quote_parent_class = 0;
+
+static void
+mail_formatter_quote_run (EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ EMailFormatterQuote *qf;
+ EMailFormatterQuoteContext *qf_context;
+ GSettings *settings;
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+
+ 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, "<br>\n", cancellable, NULL);
+ g_object_unref (settings);
+
+ if (qf->priv->credits && *qf->priv->credits) {
+ gchar *credits = g_strdup_printf ("%s<br>", qf->priv->credits);
+ camel_stream_write_string (stream, credits, cancellable, NULL);
+ g_free (credits);
+ } else {
+ camel_stream_write_string (stream, "<br>", cancellable, NULL);
+ }
+
+ if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) {
+ camel_stream_write_string (
+ stream,
+ "<!--+GtkHTML:<DATA class=\"ClueFlow\" "
+ "key=\"orig\" value=\"1\">-->\n"
+ "<blockquote type=cite>\n", cancellable, NULL);
+ }
+
+ e_mail_part_list_queue_parts (context->part_list, NULL, &queue);
+
+ head = g_queue_peek_head_link (&queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *part = E_MAIL_PART (link->data);
+ const gchar *mime_type;
+
+ if (e_mail_part_id_has_suffix (part, ".headers") &&
+ !(qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS)) {
+ continue;
+ }
+
+ if (e_mail_part_id_has_suffix (part, ".rfc822")) {
+ link = e_mail_formatter_find_rfc822_end_iter (link);
+ continue;
+ }
+
+ if (part->is_hidden)
+ continue;
+
+ if (e_mail_part_get_is_attachment (part))
+ continue;
+
+ mime_type = e_mail_part_get_mime_type (part);
+
+ e_mail_formatter_format_as (
+ formatter, context, part, stream,
+ mime_type, cancellable);
+ }
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) {
+ camel_stream_write_string (
+ stream, "</blockquote><!--+GtkHTML:"
+ "<DATA class=\"ClueFlow\" clear=\"orig\">-->",
+ 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 *class)
+{
+ /* Register internal extensions. */
+ g_type_ensure (e_mail_formatter_quote_attachment_get_type ());
+ g_type_ensure (e_mail_formatter_quote_headers_get_type ());
+ g_type_ensure (e_mail_formatter_quote_message_rfc822_get_type ());
+ g_type_ensure (e_mail_formatter_quote_text_enriched_get_type ());
+ g_type_ensure (e_mail_formatter_quote_text_html_get_type ());
+ g_type_ensure (e_mail_formatter_quote_text_plain_get_type ());
+
+ e_mail_formatter_extension_registry_load (
+ E_MAIL_FORMATTER_CLASS (class)->extension_registry,
+ E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION);
+
+ E_MAIL_FORMATTER_CLASS (class)->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 *class)
+{
+ GObjectClass *object_class;
+ EMailFormatterClass *formatter_class;
+
+ e_mail_formatter_quote_parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailFormatterQuotePrivate));
+
+ formatter_class = E_MAIL_FORMATTER_CLASS (class);
+ formatter_class->context_size = sizeof (EMailFormatterQuoteContext);
+ formatter_class->run = mail_formatter_quote_run;
+
+ object_class = G_OBJECT_CLASS (class);
+ 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;
+}
+
+/* ------------------------------------------------------------------------- */
+
+G_DEFINE_ABSTRACT_TYPE (
+ EMailFormatterQuoteExtension,
+ e_mail_formatter_quote_extension,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static void
+e_mail_formatter_quote_extension_class_init (EMailFormatterQuoteExtensionClass *class)
+{
+}
+
+static void
+e_mail_formatter_quote_extension_init (EMailFormatterQuoteExtension *extension)
+{
+}
+
diff --git a/em-format/e-mail-formatter-quote.h b/em-format/e-mail-formatter-quote.h
new file mode 100644
index 0000000000..85e549acab
--- /dev/null
+++ b/em-format/e-mail-formatter-quote.h
@@ -0,0 +1,103 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_QUOTE_H
+#define E_MAIL_FORMATTER_QUOTE_H
+
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-formatter-extension.h>
+
+/* 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;
+
+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) G_GNUC_CONST;
+EMailFormatter *
+ e_mail_formatter_quote_new (const gchar *credits,
+ EMailFormatterQuoteFlags flags);
+
+G_END_DECLS
+
+/* ------------------------------------------------------------------------- */
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION \
+ (e_mail_formatter_quote_extension_get_type ())
+
+G_BEGIN_DECLS
+
+/**
+ * EMailFormatterQuoteExtension:
+ *
+ * This is an abstract base type for formatter extensions which are
+ * intended only for use by #EMailFormatterQuote.
+ **/
+typedef struct _EMailFormatterQuoteExtension EMailFormatterQuoteExtension;
+typedef struct _EMailFormatterQuoteExtensionClass EMailFormatterQuoteExtensionClass;
+
+struct _EMailFormatterQuoteExtension {
+ EMailFormatterExtension parent;
+};
+
+struct _EMailFormatterQuoteExtensionClass {
+ EMailFormatterExtensionClass parent_class;
+};
+
+GType e_mail_formatter_quote_extension_get_type
+ (void) G_GNUC_CONST;
+
+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..91a330348f
--- /dev/null
+++ b/em-format/e-mail-formatter-secure-button.c
@@ -0,0 +1,479 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+#include "certificate-manager.h"
+#include "e-cert-db.h"
+#endif
+
+#include "e-mail-formatter-extension.h"
+
+typedef EMailFormatterExtension EMailFormatterSecureButton;
+typedef EMailFormatterExtensionClass EMailFormatterSecureButtonClass;
+
+GType e_mail_formatter_secure_button_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterSecureButton,
+ e_mail_formatter_secure_button,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+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) &&
+ (context->mode != E_MAIL_FORMATTER_MODE_ALL_HEADERS))
+ return FALSE;
+
+ str = g_strdup_printf (
+ "<object type=\"application/vnd.evolution.widget.secure-button\" "
+ "height=\"20\" width=\"100%%\" data=\"%s\" id=\"%s\"></object>",
+ e_mail_part_get_id (part),
+ e_mail_part_get_id (part));
+
+ 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 *grid)
+{
+ 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 *dialog, *parent;
+
+ parent = gtk_widget_get_toplevel (grid);
+ if (!parent || !GTK_IS_WINDOW (parent))
+ parent = NULL;
+
+ dialog = e_cert_manager_new_certificate_viewer ((GtkWindow *) parent, ec);
+
+ gtk_widget_show (dialog);
+ g_signal_connect (
+ dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ 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,
+ CamelCipherValidity *validity)
+{
+ GtkBuilder *builder;
+ GtkWidget *grid, *w;
+ GtkWidget *dialog;
+
+ g_return_if_fail (validity != NULL);
+
+ 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[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 (validity->sign.description) {
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_set_text (
+ buffer, validity->sign.description,
+ strlen (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 (&validity->sign.signers))
+ add_cert_table (
+ grid, &validity->sign.signers, NULL);
+
+ gtk_widget_show_all (grid);
+
+ grid = e_builder_get_widget (builder, "encryption_grid");
+ w = gtk_label_new (_(smime_encrypt_table[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 (validity->encrypt.description) {
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_set_text (
+ buffer, validity->encrypt.description,
+ strlen (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 (&validity->encrypt.encrypters))
+ add_cert_table (grid, &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 *
+secure_button_get_widget_for_validity (CamelCipherValidity *validity)
+{
+ GtkWidget *box, *button, *layout, *widget;
+ const gchar *icon_name;
+ gchar *description;
+ GString *buffer;
+
+ g_return_val_if_fail (validity != NULL, NULL);
+
+ buffer = g_string_new ("");
+
+ if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
+ const gchar *desc;
+ gint status;
+
+ status = validity->sign.status;
+ desc = smime_sign_table[status].shortdesc;
+
+ g_string_append (buffer, gettext (desc));
+
+ format_cert_infos (&validity->sign.signers, buffer);
+ }
+
+ if (validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
+ const gchar *desc;
+ gint status;
+
+ if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
+ g_string_append (buffer, "\n");
+
+ status = 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 (validity->sign.status != 0)
+ icon_name = smime_sign_table[validity->sign.status].icon;
+ else
+ icon_name = smime_encrypt_table[validity->encrypt.status].icon;
+
+ box = gtk_event_box_new ();
+ if (validity->sign.status != 0)
+ gtk_widget_override_background_color (
+ box, GTK_STATE_FLAG_NORMAL,
+ &smime_sign_colour[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), validity);
+
+ 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);
+
+ g_free (description);
+
+ return box;
+}
+
+static GtkWidget *
+emfe_secure_button_get_widget (EMailFormatterExtension *extension,
+ EMailPartList *context,
+ EMailPart *part,
+ GHashTable *params)
+{
+ GtkWidget *grid;
+ GList *head, *link;
+
+ g_return_val_if_fail (part != NULL, NULL);
+
+ grid = g_object_new (
+ GTK_TYPE_GRID,
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ "row-spacing", 2,
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ NULL);
+
+ head = g_queue_peek_head_link (&part->validities);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+ GtkWidget *widget;
+
+ if (pair == NULL)
+ continue;
+
+ widget = secure_button_get_widget_for_validity (pair->validity);
+ if (widget != NULL) {
+ gtk_widget_set_halign (widget, GTK_ALIGN_FILL);
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_container_add (GTK_CONTAINER (grid), widget);
+ }
+ }
+
+ gtk_widget_show_all (grid);
+
+ return grid;
+}
+
+static void
+e_mail_formatter_secure_button_class_init (EMailFormatterExtensionClass *class)
+{
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_secure_button_format;
+ class->get_widget = emfe_secure_button_get_widget;
+}
+
+static void
+e_mail_formatter_secure_button_init (EMailFormatterExtension *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..944f9a4c14
--- /dev/null
+++ b/em-format/e-mail-formatter-source.c
@@ -0,0 +1,140 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-inline-filter.h"
+
+typedef EMailFormatterExtension EMailFormatterSource;
+typedef EMailFormatterExtensionClass EMailFormatterSourceClass;
+
+GType e_mail_formatter_source_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterSource,
+ e_mail_formatter_source,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+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;
+ CamelMimePart *mime_part;
+
+ mime_part = e_mail_part_ref_mime_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 (mime_part)) {
+ g_string_append_printf (
+ buffer,
+ "<div class=\"part-container\" "
+ "style=\"border: 0; background: #%06x; color: #%06x;\" >",
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_BODY)),
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_TEXT)));
+ } else {
+ g_string_append_printf (
+ buffer,
+ "<div class=\"part-container\" "
+ "style=\"border-color: #%06x; background: #%06x; color: #%06x;\">"
+ "<div class=\"part-container-inner-margin pre\">\n",
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_BODY)),
+ e_rgba_to_value (
+ 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, "<code class=\"pre\">", cancellable, NULL);
+
+ camel_data_wrapper_write_to_stream_sync (
+ CAMEL_DATA_WRAPPER (mime_part),
+ filtered_stream, cancellable, NULL);
+ camel_stream_flush (filtered_stream, cancellable, NULL);
+ g_object_unref (filtered_stream);
+
+ camel_stream_write_string (
+ stream, "</code>", cancellable, NULL);
+
+ g_string_free (buffer, TRUE);
+
+ if (CAMEL_IS_MIME_MESSAGE (mime_part)) {
+ camel_stream_write_string (stream, "</div>", cancellable, NULL);
+ } else {
+ camel_stream_write_string (stream, "</div></div>", cancellable, NULL);
+ }
+
+ g_object_unref (mime_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_source_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("Source");
+ class->description = _("Display source of a MIME part");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_source_format;
+}
+
+static void
+e_mail_formatter_source_init (EMailFormatterExtension *extension)
+{
+}
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..6c3b033171
--- /dev/null
+++ b/em-format/e-mail-formatter-text-enriched.c
@@ -0,0 +1,114 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-inline-filter.h"
+
+typedef EMailFormatterExtension EMailFormatterTextEnriched;
+typedef EMailFormatterExtensionClass EMailFormatterTextEnrichedClass;
+
+GType e_mail_formatter_text_enriched_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterTextEnriched,
+ e_mail_formatter_text_enriched,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "text/enriched",
+ "text/richtext",
+ NULL
+};
+
+static gboolean
+emfe_text_enriched_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ CamelStream *filtered_stream;
+ CamelMimeFilter *enriched;
+ const gchar *mime_type;
+ guint32 filter_flags = 0;
+ GString *buffer;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ mime_type = e_mail_part_get_mime_type (part);
+
+ if (g_strcmp0 (mime_type, "text/richtext") == 0)
+ 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,
+ "<div class=\"part-container\" style=\"border-color: #%06x; "
+ "background-color: #%06x; color: #%06x;\">"
+ "<div class=\"part-container-inner-margin\">\n",
+ e_rgba_to_value (
+ e_mail_formatter_get_color (formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+ e_rgba_to_value (
+ e_mail_formatter_get_color (formatter, E_MAIL_FORMATTER_COLOR_CONTENT)),
+ e_rgba_to_value (
+ 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, "</div></div>", cancellable, NULL);
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_text_enriched_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("Richtext");
+ class->description = _("Display part as enriched text");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_text_enriched_format;
+}
+
+static void
+e_mail_formatter_text_enriched_init (EMailFormatterExtension *extension)
+{
+}
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..0a581117a6
--- /dev/null
+++ b/em-format/e-mail-formatter-text-html.c
@@ -0,0 +1,363 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-inline-filter.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailFormatterExtension EMailFormatterTextHTML;
+typedef EMailFormatterExtensionClass EMailFormatterTextHTMLClass;
+
+GType e_mail_formatter_text_html_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterTextHTML,
+ e_mail_formatter_text_html,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "text/html",
+ NULL
+};
+
+static gchar *
+get_tag (const gchar *utf8_string,
+ const gchar *tag_name,
+ gchar *opening,
+ gchar *closing)
+{
+ gchar *t;
+ gunichar c;
+ gboolean has_end;
+
+ c = '\0';
+ 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 == '<') {
+ if (t[1] == '!' && t[2] == '-' && t[3] == '-') {
+ /* it's a comment start, read until the end of "-->" */
+ gchar *end = strstr (t + 4, "-->");
+ if (end) {
+ t = end + 2;
+ } else
+ break;
+ } else
+ break;
+ }
+
+ t = g_utf8_find_next_char (t, NULL);
+ }
+
+ has_end = FALSE;
+ 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 NULL;
+
+ 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 NULL;
+}
+
+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) {
+ 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);
+
+ if (!g_utf8_validate (string->str, -1, NULL)) {
+ gchar *valid_utf8;
+
+ valid_utf8 = e_util_utf8_make_valid (string->str);
+ g_string_free (string, TRUE);
+ string = g_string_new (valid_utf8);
+ g_free (valid_utf8);
+ }
+
+ tags = NULL;
+ pos = string->str;
+ valid = FALSE;
+
+ 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);
+
+ /* Something's wrong, let's write the entire HTML and hope
+ * that WebKit can handle it */
+ if (!valid) {
+ EMailFormatterContext c = {
+ .part_list = context->part_list,
+ .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, "<div ");
+
+ for (iter = tags; iter; iter = iter->next) {
+ if (iter->data)
+ 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, "</body>")) {
+ document_end = ">ydob/<";
+ }
+
+ if (g_strrstr (string->str, "</html>")) {
+ 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;
+ }
+ } else {
+ /* do not cut, if there is no end 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 {
+ CamelFolder *folder;
+ const gchar *message_uid;
+ const gchar *default_charset, *charset;
+ gchar *uri, *str;
+
+ folder = e_mail_part_list_get_folder (context->part_list);
+ message_uid = e_mail_part_list_get_message_uid (context->part_list);
+ default_charset = e_mail_formatter_get_default_charset (formatter);
+ charset = e_mail_formatter_get_charset (formatter);
+
+ if (!default_charset)
+ default_charset = "";
+ if (!charset)
+ charset = "";
+
+ uri = e_mail_part_build_uri (
+ folder, message_uid,
+ "part_id", G_TYPE_STRING, e_mail_part_get_id (part),
+ "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+ "formatter_default_charset", G_TYPE_STRING, default_charset,
+ "formatter_charset", G_TYPE_STRING, charset,
+ NULL);
+
+ /* HTML messages expect white background and black color for text.
+ * If Evolution uses a dark theme, then the dark background with
+ * a black text is hard to read, thus force white background color.
+ * The HTML content can still overwrite both colors.
+ */
+ str = g_strdup_printf (
+ "<div class=\"part-container-nostyle\">"
+ "<iframe width=\"100%%\" height=\"10\" "
+ " frameborder=\"0\" src=\"%s\" "
+ " id=\"%s.iframe\" name=\"%s\" "
+ " style=\"border: 1px solid #%06x; background-color: #ffffff;\">"
+ "</iframe>"
+ "</div>",
+ uri,
+ e_mail_part_get_id (part),
+ e_mail_part_get_id (part),
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_FRAME)));
+
+ camel_stream_write_string (stream, str, cancellable, NULL);
+
+ g_free (str);
+ g_free (uri);
+ }
+
+ return TRUE;
+}
+
+static void
+e_mail_formatter_text_html_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("HTML");
+ class->description = _("Format part as HTML");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_text_html_format;
+}
+
+static void
+e_mail_formatter_text_html_init (EMailFormatterExtension *extension)
+{
+}
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..638f0119a1
--- /dev/null
+++ b/em-format/e-mail-formatter-text-plain.c
@@ -0,0 +1,204 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-inline-filter.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailFormatterExtension EMailFormatterTextPlain;
+typedef EMailFormatterExtensionClass EMailFormatterTextPlainClass;
+
+GType e_mail_formatter_text_plain_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailFormatterTextPlain,
+ e_mail_formatter_text_plain,
+ E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+ "text/plain",
+ "text/*",
+ "message/*",
+ "application/vnd.evolution.plaintext",
+ NULL
+};
+
+static gboolean
+emfe_text_plain_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ CamelStream *filtered_stream;
+ CamelMimeFilter *html_filter;
+ gchar *content;
+ const gchar *format;
+ 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)) {
+ CamelMimeFilterToHTMLFlags flags;
+ CamelMimePart *mime_part;
+ CamelDataWrapper *dw;
+
+ 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 <iframe> */
+ camel_stream_write_string (
+ stream,
+ "<style>body{ margin: 0; }</style>",
+ cancellable, NULL);
+ }
+
+ flags = e_mail_formatter_get_text_format_flags (formatter);
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+ if (dw == NULL) {
+ g_object_unref (mime_part);
+ return FALSE;
+ }
+
+ /* Check for RFC 2646 flowed text. */
+ if (camel_content_type_is (dw->mime_type, "text", "plain")
+ && (format = camel_content_type_param (dw->mime_type, "format"))
+ && !g_ascii_strcasecmp (format, "flowed"))
+ flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
+
+ rgb = e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_CITATION));
+
+ filtered_stream = camel_stream_filter_new (stream);
+ html_filter = camel_mime_filter_tohtml_new (flags, rgb);
+ camel_stream_filter_add (
+ CAMEL_STREAM_FILTER (filtered_stream), html_filter);
+ g_object_unref (html_filter);
+
+ content = g_strdup_printf (
+ "<div class=\"part-container pre\" style=\""
+ "border: none; padding: 8px; margin: 0; "
+ "background-color: #%06x; color: #%06x;\">\n",
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_CONTENT)),
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_TEXT)));
+
+ camel_stream_write_string (stream, content, cancellable, NULL);
+ e_mail_formatter_format_text (formatter, part, filtered_stream, cancellable);
+ camel_stream_flush (filtered_stream, cancellable, NULL);
+
+ g_object_unref (filtered_stream);
+ g_free (content);
+
+ camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
+
+ if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+ camel_stream_write_string (
+ stream, "</body></html>",
+ cancellable, NULL);
+ }
+
+ g_object_unref (mime_part);
+
+ return TRUE;
+
+ } else {
+ CamelFolder *folder;
+ const gchar *message_uid;
+ gchar *uri, *str;
+ const gchar *default_charset, *charset;
+
+ folder = e_mail_part_list_get_folder (context->part_list);
+ message_uid = e_mail_part_list_get_message_uid (context->part_list);
+ default_charset = e_mail_formatter_get_default_charset (formatter);
+ charset = e_mail_formatter_get_charset (formatter);
+
+ if (!default_charset)
+ default_charset = "";
+ if (!charset)
+ charset = "";
+
+ uri = e_mail_part_build_uri (
+ folder, message_uid,
+ "part_id", G_TYPE_STRING, e_mail_part_get_id (part),
+ "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+ "formatter_default_charset", G_TYPE_STRING, default_charset,
+ "formatter_charset", G_TYPE_STRING, charset,
+ NULL);
+
+ str = g_strdup_printf (
+ "<div class=\"part-container-nostyle\" >"
+ "<iframe width=\"100%%\" height=\"10\""
+ " id=\"%s.iframe\" name=\"%s\" "
+ " frameborder=\"0\" src=\"%s\" "
+ " style=\"border: 1px solid #%06x; background-color: #%06x;\">"
+ "</iframe>"
+ "</div>",
+ e_mail_part_get_id (part),
+ e_mail_part_get_id (part),
+ uri,
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+ e_rgba_to_value (
+ 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 void
+e_mail_formatter_text_plain_class_init (EMailFormatterExtensionClass *class)
+{
+ class->display_name = _("Plain Text");
+ class->description = _("Format part as plain text");
+ class->mime_types = formatter_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->format = emfe_text_plain_format;
+}
+
+static void
+e_mail_formatter_text_plain_init (EMailFormatterExtension *extension)
+{
+}
diff --git a/em-format/e-mail-formatter-utils.c b/em-format/e-mail-formatter-utils.c
new file mode 100644
index 0000000000..1967a61ccd
--- /dev/null
+++ b/em-format/e-mail-formatter-utils.c
@@ -0,0 +1,541 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG
+#include <config.h>
+#endif
+
+#include "e-mail-formatter-utils.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include <camel/camel.h>
+#include <libedataserver/libedataserver.h>
+
+#include <e-util/e-util.h>
+#include <libemail-engine/e-mail-utils.h>
+#include <libemail-engine/mail-config.h>
+
+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)
+{
+ GtkTextDirection direction;
+ const gchar *fmt, *html;
+ const gchar *display;
+ gchar *mhtml = NULL;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (buffer != NULL);
+ g_return_if_fail (label != NULL);
+
+ if (value == NULL)
+ return;
+
+ while (*value == ' ')
+ value++;
+
+ if (!(flags & E_MAIL_FORMATTER_HEADER_FLAG_HTML)) {
+ CamelMimeFilterToHTMLFlags text_format_flags;
+
+ text_format_flags =
+ e_mail_formatter_get_text_format_flags (formatter);
+ html = mhtml = camel_text_to_html (
+ value, text_format_flags, 0);
+ } else {
+ html = value;
+ }
+
+ direction = gtk_widget_get_default_direction ();
+
+ if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS) {
+ if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) {
+ fmt = "<tr style=\"display: %s\">"
+ "<td><b>%s:</b> %s</td></tr>";
+ } else {
+ fmt = "<tr style=\"display: %s\">"
+ "<td>%s: %s</td></tr>";
+ }
+ } else if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NODEC) {
+ if (direction == GTK_TEXT_DIR_RTL)
+ fmt = "<tr class=\"header\" style=\"display: %s\">"
+ "<th class=\"header rtl\">%s</th>"
+ "<td class=\"header rtl\">%s</td>"
+ "</tr>";
+ else
+ fmt = "<tr class=\"header\" style=\"display: %s\">"
+ "<th class=\"header ltr\">%s</th>"
+ "<td class=\"header ltr\">%s</td>"
+ "</tr>";
+ } else {
+ if (direction == GTK_TEXT_DIR_RTL)
+ fmt = "<tr class=\"header\" style=\"display: %s\">"
+ "<th class=\"header rtl\">%s:</th>"
+ "<td class=\"header rtl\">%s</td>"
+ "</tr>";
+ else
+ fmt = "<tr class=\"header\" style=\"display: %s\">"
+ "<th class=\"header ltr\">%s:</th>"
+ "<td class=\"header ltr\">%s</td>"
+ "</tr>";
+ }
+
+ if (flags & E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN)
+ display = "none";
+ else
+ display = "table-row";
+
+ g_string_append_printf (buffer, fmt, display, label, html);
+
+ g_free (mhtml);
+}
+
+gchar *
+e_mail_formatter_format_address (EMailFormatter *formatter,
+ GString *out,
+ struct _camel_header_address *a,
+ const gchar *field,
+ gboolean no_links,
+ gboolean elipsize)
+{
+ CamelMimeFilterToHTMLFlags flags;
+ gchar *name, *mailto, *addr;
+ gint i = 0;
+ gchar *str = NULL;
+ gint limit = mail_config_get_address_count ();
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+ g_return_val_if_fail (out != NULL, NULL);
+ g_return_val_if_fail (field != NULL, NULL);
+
+ flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
+
+ while (a != NULL) {
+ 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 != NULL && *name != '\0') {
+ gchar *real, *mailaddr;
+
+ if (strchr (a->name, ',') || strchr (a->name, ';'))
+ g_string_append_printf (out, "&quot;%s&quot;", name);
+ else
+ g_string_append (out, name);
+
+ g_string_append (out, " &lt;");
+
+ /* 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, "<a href=\"mailto:%s\">%s</a>", mailto, addr);
+ g_free (mailto);
+ g_free (addr);
+
+ if (name != NULL && *name != '\0')
+ g_string_append (out, "&gt;");
+ 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 != NULL)
+ g_string_append (out, ", ");
+
+ if (!elipsize)
+ continue;
+
+ /* Let us add a '...' if we have more addresses */
+ if (limit > 0 && i == limit && a != NULL) {
+ 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 != NULL) {
+ g_string_append_printf (
+ out,
+ "<span id=\"__evo-moreaddr-%s\" "
+ "style=\"display: none;\">", id);
+ str = g_strdup_printf (
+ "<img src=\"evo-file://%s/plus.png\" "
+ "id=\"__evo-moreaddr-img-%s\" class=\"navigable\">",
+ 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 != NULL) {
+ g_string_append_printf (
+ out,
+ "</span>"
+ "<span class=\"navigable\" "
+ "id=\"__evo-moreaddr-ellipsis-%s\" "
+ "style=\"display: inline;\">...</span>",
+ id);
+ }
+ }
+
+ return str;
+}
+
+void
+e_mail_formatter_canon_header_name (gchar *name)
+{
+ gchar *inptr = name;
+
+ g_return_if_fail (name != NULL);
+
+ /* 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,
+ const gchar *header_name,
+ const gchar *header_value,
+ guint32 flags,
+ const gchar *charset)
+{
+ gchar *canon_name, *buf, *value = NULL;
+ const gchar *label, *txt;
+ gboolean addrspec = FALSE;
+ gchar *str_field = NULL;
+ gint i;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (buffer != NULL);
+ g_return_if_fail (header_name != NULL);
+ g_return_if_fail (header_value != NULL);
+
+ canon_name = g_alloca (strlen (header_name) + 1);
+ strcpy (canon_name, header_name);
+ e_mail_formatter_canon_header_name (canon_name);
+
+ for (i = 0; addrspec_hdrs[i]; i++) {
+ if (g_str_equal (canon_name, addrspec_hdrs[i])) {
+ addrspec = TRUE;
+ break;
+ }
+ }
+
+ label = _(canon_name);
+
+ if (addrspec) {
+ struct _camel_header_address *addrs;
+ GString *html;
+ gchar *img;
+ gchar *charset;
+
+ charset = e_mail_formatter_dup_charset (formatter);
+ if (charset == NULL)
+ charset = e_mail_formatter_dup_default_charset (formatter);
+
+ buf = camel_header_unfold (header_value);
+ addrs = camel_header_address_decode (buf, charset);
+ if (addrs == NULL) {
+ g_free (charset);
+ g_free (buf);
+ return;
+ }
+
+ g_free (charset);
+ g_free (buf);
+
+ html = g_string_new ("");
+ img = e_mail_formatter_format_address (
+ formatter, html, addrs, label,
+ (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS),
+ !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
+
+ if (img != NULL) {
+ str_field = g_strdup_printf ("%s: %s", label, img);
+ 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;
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_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 (g_str_equal (canon_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 (g_str_equal (canon_name, "Date") ||
+ g_str_equal (canon_name, "Resent-Date")) {
+ CamelMimeFilterToHTMLFlags text_format_flags;
+ 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++;
+
+ text_format_flags =
+ e_mail_formatter_get_text_format_flags (formatter);
+
+ html = camel_text_to_html (txt, text_format_flags, 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 (<I>%s</I>)", html, date_str);
+ g_free (date_str);
+ }
+ g_free (html);
+ }
+
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML;
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_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, "<a href=\"news:%s\">%s</a>",
+ 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;
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_name, "Received") ||
+ g_str_has_prefix (canon_name, "X-")) {
+ /* 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);
+}
+
+GList *
+e_mail_formatter_find_rfc822_end_iter (GList *rfc822_start_iter)
+{
+ GList *link = rfc822_start_iter;
+ EMailPart *part;
+ const gchar *part_id;
+ gchar *end;
+
+ g_return_val_if_fail (rfc822_start_iter != NULL, NULL);
+
+ part = E_MAIL_PART (link->data);
+
+ part_id = e_mail_part_get_id (part);
+ g_return_val_if_fail (part_id != NULL, NULL);
+
+ end = g_strconcat (part_id, ".end", NULL);
+
+ while (link != NULL) {
+ part = E_MAIL_PART (link->data);
+
+ part_id = e_mail_part_get_id (part);
+ g_return_val_if_fail (part_id != NULL, NULL);
+
+ if (g_strcmp0 (part_id, end) == 0)
+ break;
+
+ link = g_list_next (link);
+ }
+
+ g_free (end);
+
+ return link;
+}
+
+gchar *
+e_mail_formatter_parse_html_mnemonics (const gchar *label,
+ gchar **out_access_key)
+{
+ const gchar *pos = NULL;
+ GString *html_label = NULL;
+
+ g_return_val_if_fail (label != NULL, NULL);
+
+ if (out_access_key != NULL)
+ *out_access_key = NULL;
+
+ pos = strstr (label, "_");
+ if (pos != NULL) {
+ gchar ak = pos[1];
+
+ /* Convert to uppercase */
+ if (ak >= 'a')
+ ak = ak - 32;
+
+ html_label = g_string_new ("");
+ g_string_append_len (html_label, label, pos - label);
+ g_string_append_printf (html_label, "<u>%c</u>", pos[1]);
+ g_string_append (html_label, &pos[2]);
+
+ if (out_access_key != NULL && ak != '\0')
+ *out_access_key = g_strdup_printf ("%c", ak);
+
+ } else {
+ html_label = g_string_new (label);
+ }
+
+ return g_string_free (html_label, FALSE);
+}
diff --git a/em-format/e-mail-formatter-utils.h b/em-format/e-mail-formatter-utils.h
new file mode 100644
index 0000000000..0312d545e0
--- /dev/null
+++ b/em-format/e-mail-formatter-utils.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_UTILS_H_
+#define E_MAIL_FORMATTER_UTILS_H_
+
+#include <camel/camel.h>
+#include <em-format/e-mail-formatter.h>
+
+G_BEGIN_DECLS
+
+void e_mail_formatter_format_header (EMailFormatter *formatter,
+ GString *buffer,
+ const gchar *header_name,
+ const gchar *header_value,
+ 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,
+ const gchar *field,
+ gboolean no_links,
+ gboolean elipsize);
+
+void e_mail_formatter_canon_header_name
+ (gchar *name);
+
+GList * e_mail_formatter_find_rfc822_end_iter
+ (GList *rfc822_start_iter);
+
+gchar * e_mail_formatter_parse_html_mnemonics
+ (const gchar *label,
+ gchar **out_access_key);
+
+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..f3f09670d4
--- /dev/null
+++ b/em-format/e-mail-formatter.c
@@ -0,0 +1,1435 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter.h"
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-formatter-utils.h"
+#include "e-mail-part.h"
+
+#include <e-util/e-util.h>
+#include <libebackend/libebackend.h>
+#include <gdk/gdk.h>
+#include <glib/gi18n.h>
+
+#include "libemail-engine/e-mail-enumtypes.h"
+
+#define d(x)
+
+#define E_MAIL_FORMATTER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterPrivate))\
+
+#define STYLESHEET_URI \
+ "evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css"
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _EMailFormatterPrivate {
+ EMailImageLoadingPolicy image_loading_policy;
+
+ gboolean show_sender_photo;
+ gboolean show_real_date;
+ gboolean animate_images;
+
+ GMutex property_lock;
+
+ gchar *charset;
+ gchar *default_charset;
+};
+
+struct _AsyncContext {
+ CamelStream *stream;
+ EMailPartList *part_list;
+ EMailFormatterHeaderFlags flags;
+ EMailFormatterMode mode;
+};
+
+/* internal formatter extensions */
+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_image_get_type (void);
+GType e_mail_formatter_message_rfc822_get_type (void);
+GType e_mail_formatter_secure_button_get_type (void);
+GType e_mail_formatter_source_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);
+
+void e_mail_formatter_internal_extensions_load (EMailExtensionRegistry *ereg);
+
+static gpointer e_mail_formatter_parent_class = 0;
+
+enum {
+ PROP_0,
+ PROP_ANIMATE_IMAGES,
+ PROP_BODY_COLOR,
+ PROP_CHARSET,
+ PROP_CITATION_COLOR,
+ PROP_CONTENT_COLOR,
+ PROP_DEFAULT_CHARSET,
+ PROP_FRAME_COLOR,
+ PROP_HEADER_COLOR,
+ PROP_IMAGE_LOADING_POLICY,
+ PROP_MARK_CITATIONS,
+ PROP_SHOW_REAL_DATE,
+ PROP_SHOW_SENDER_PHOTO,
+ PROP_TEXT_COLOR
+};
+
+enum {
+ NEED_REDRAW,
+ LAST_SIGNAL
+};
+
+static gint signals[LAST_SIGNAL];
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+ g_clear_object (&async_context->part_list);
+ g_clear_object (&async_context->stream);
+
+ g_slice_free (AsyncContext, async_context);
+}
+
+static EMailFormatterContext *
+mail_formatter_create_context (EMailFormatter *formatter,
+ EMailPartList *part_list,
+ EMailFormatterMode mode,
+ EMailFormatterHeaderFlags flags)
+{
+ EMailFormatterClass *class;
+ EMailFormatterContext *context;
+
+ class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+
+ g_warn_if_fail (class->context_size >= sizeof (EMailFormatterContext));
+
+ context = g_malloc0 (class->context_size);
+ context->part_list = g_object_ref (part_list);
+ context->mode = mode;
+ context->flags = flags;
+
+ return context;
+}
+
+static void
+mail_formatter_free_context (EMailFormatterContext *context)
+{
+ if (context->part_list != NULL)
+ g_object_unref (context->part_list);
+
+ g_free (context);
+}
+
+static void
+e_mail_formatter_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ANIMATE_IMAGES:
+ e_mail_formatter_set_animate_images (
+ E_MAIL_FORMATTER (object),
+ g_value_get_boolean (value));
+ return;
+
+ 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_CHARSET:
+ e_mail_formatter_set_charset (
+ E_MAIL_FORMATTER (object),
+ g_value_get_string (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_DEFAULT_CHARSET:
+ e_mail_formatter_set_default_charset (
+ E_MAIL_FORMATTER (object),
+ g_value_get_string (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_enum (value));
+ return;
+
+ case PROP_MARK_CITATIONS:
+ e_mail_formatter_set_mark_citations (
+ 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_SHOW_SENDER_PHOTO:
+ e_mail_formatter_set_show_sender_photo (
+ 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;
+ }
+
+ 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_ANIMATE_IMAGES:
+ g_value_set_boolean (
+ value,
+ e_mail_formatter_get_animate_images (
+ E_MAIL_FORMATTER (object)));
+ return;
+
+ 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_CHARSET:
+ g_value_take_string (
+ value,
+ e_mail_formatter_dup_charset (
+ E_MAIL_FORMATTER (object)));
+ 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_DEFAULT_CHARSET:
+ g_value_take_string (
+ value,
+ e_mail_formatter_dup_default_charset (
+ E_MAIL_FORMATTER (object)));
+ 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_enum (
+ 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_SHOW_REAL_DATE:
+ g_value_set_boolean (
+ value,
+ e_mail_formatter_get_show_real_date (
+ 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_TEXT_COLOR:
+ g_value_set_boxed (
+ value,
+ e_mail_formatter_get_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_TEXT));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_formatter_finalize (GObject *object)
+{
+ EMailFormatterPrivate *priv;
+
+ priv = E_MAIL_FORMATTER_GET_PRIVATE (object);
+
+ g_free (priv->charset);
+ g_free (priv->default_charset);
+
+ g_mutex_clear (&priv->property_lock);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_formatter_parent_class)->finalize (object);
+}
+
+static void
+e_mail_formatter_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_formatter_parent_class)->constructed (object);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (object));
+}
+
+static void
+mail_formatter_run (EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+ gchar *hdr;
+
+ hdr = e_mail_formatter_get_html_header (formatter);
+ camel_stream_write_string (stream, hdr, cancellable, NULL);
+ g_free (hdr);
+
+ e_mail_part_list_queue_parts (context->part_list, NULL, &queue);
+
+ head = g_queue_peek_head_link (&queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *part = link->data;
+ const gchar *part_id;
+ gboolean ok;
+
+ part_id = e_mail_part_get_id (part);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ break;
+
+ if (part->is_hidden && !part->is_error) {
+ if (e_mail_part_id_has_suffix (part, ".rfc822")) {
+ link = e_mail_formatter_find_rfc822_end_iter (link);
+ }
+
+ if (link == NULL)
+ break;
+
+ continue;
+ }
+
+ /* Force formatting as source if needed */
+ if (context->mode != E_MAIL_FORMATTER_MODE_SOURCE) {
+ const gchar *mime_type;
+
+ mime_type = e_mail_part_get_mime_type (part);
+ if (mime_type == NULL)
+ continue;
+
+ ok = e_mail_formatter_format_as (
+ formatter, context, part, stream,
+ 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 && e_mail_part_id_has_suffix (part, ".rfc822")) {
+ link = e_mail_formatter_find_rfc822_end_iter (link);
+
+ if (link == NULL)
+ break;
+
+ continue;
+ }
+
+ } else {
+ ok = FALSE;
+ }
+
+ if (!ok) {
+ /* We don't want to source these */
+ if (e_mail_part_id_has_suffix (part, ".headers") ||
+ e_mail_part_id_has_suffix (part, "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 (e_mail_part_id_has_suffix (part, ".rfc822")) {
+
+ do {
+ part = link->data;
+ if (e_mail_part_id_has_suffix (part, ".rfc822.end"))
+ break;
+
+ link = g_list_next (link);
+ } while (link != NULL);
+
+ if (link == NULL)
+ break;
+ }
+ }
+ }
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+}
+
+static void
+mail_formatter_update_style (EMailFormatter *formatter,
+ GtkStateFlags state)
+{
+ GtkStyleContext *style_context;
+ GtkWidgetPath *widget_path;
+ GdkRGBA rgba;
+
+ g_object_freeze_notify (G_OBJECT (formatter));
+
+ /* derive colors from top-level window */
+ style_context = gtk_style_context_new ();
+ widget_path = gtk_widget_path_new ();
+ gtk_widget_path_append_type (widget_path, GTK_TYPE_WINDOW);
+ gtk_style_context_set_path (style_context, widget_path);
+ gtk_style_context_invalidate (style_context);
+
+ gtk_style_context_save (style_context);
+ gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_TOOLBAR);
+
+ gtk_style_context_get_background_color (style_context, state, &rgba);
+ e_mail_formatter_set_color (
+ formatter, E_MAIL_FORMATTER_COLOR_BODY, &rgba);
+
+ rgba.red *= 0.8;
+ rgba.green *= 0.8;
+ rgba.blue *= 0.8;
+ e_mail_formatter_set_color (
+ formatter, E_MAIL_FORMATTER_COLOR_FRAME, &rgba);
+
+ gtk_style_context_restore (style_context);
+ gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_ENTRY);
+
+ gtk_style_context_get_color (style_context, state, &rgba);
+ e_mail_formatter_set_color (
+ formatter, E_MAIL_FORMATTER_COLOR_HEADER, &rgba);
+
+ gtk_style_context_get_background_color (
+ style_context, state | GTK_STATE_FLAG_FOCUSED, &rgba);
+ e_mail_formatter_set_color (
+ formatter, E_MAIL_FORMATTER_COLOR_CONTENT, &rgba);
+
+ gtk_style_context_get_color (
+ style_context, state | GTK_STATE_FLAG_FOCUSED, &rgba);
+ e_mail_formatter_set_color (
+ formatter, E_MAIL_FORMATTER_COLOR_TEXT, &rgba);
+
+ gtk_widget_path_free (widget_path);
+ g_object_unref (style_context);
+
+ g_object_thaw_notify (G_OBJECT (formatter));
+}
+
+static void
+e_mail_formatter_base_init (EMailFormatterClass *class)
+{
+ /* Register internal extensions. */
+ g_type_ensure (e_mail_formatter_attachment_get_type ());
+ g_type_ensure (e_mail_formatter_attachment_bar_get_type ());
+ g_type_ensure (e_mail_formatter_error_get_type ());
+ g_type_ensure (e_mail_formatter_headers_get_type ());
+ g_type_ensure (e_mail_formatter_image_get_type ());
+ g_type_ensure (e_mail_formatter_message_rfc822_get_type ());
+ g_type_ensure (e_mail_formatter_secure_button_get_type ());
+ g_type_ensure (e_mail_formatter_source_get_type ());
+ g_type_ensure (e_mail_formatter_text_enriched_get_type ());
+ g_type_ensure (e_mail_formatter_text_html_get_type ());
+ g_type_ensure (e_mail_formatter_text_plain_get_type ());
+
+ class->extension_registry = g_object_new (
+ E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, NULL);
+
+ e_mail_formatter_extension_registry_load (
+ class->extension_registry,
+ E_TYPE_MAIL_FORMATTER_EXTENSION);
+
+ e_extensible_load_extensions (
+ E_EXTENSIBLE (class->extension_registry));
+
+ class->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_CONVERT_ADDRESSES |
+ CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+}
+
+static void
+e_mail_formatter_base_finalize (EMailFormatterClass *class)
+{
+ g_object_unref (class->extension_registry);
+}
+
+static void
+e_mail_formatter_class_init (EMailFormatterClass *class)
+{
+ GObjectClass *object_class;
+ GdkRGBA *rgba;
+
+ e_mail_formatter_parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailFormatterPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = e_mail_formatter_set_property;
+ object_class->get_property = e_mail_formatter_get_property;
+ object_class->finalize = e_mail_formatter_finalize;
+ object_class->constructed = e_mail_formatter_constructed;
+
+ class->context_size = sizeof (EMailFormatterContext);
+ class->run = mail_formatter_run;
+ class->update_style = mail_formatter_update_style;
+
+ rgba = &class->colors[E_MAIL_FORMATTER_COLOR_BODY];
+ gdk_rgba_parse (rgba, "#eeeeee");
+
+ rgba = &class->colors[E_MAIL_FORMATTER_COLOR_CONTENT];
+ gdk_rgba_parse (rgba, "#ffffff");
+
+ rgba = &class->colors[E_MAIL_FORMATTER_COLOR_FRAME];
+ gdk_rgba_parse (rgba, "#3f3f3f");
+
+ rgba = &class->colors[E_MAIL_FORMATTER_COLOR_HEADER];
+ gdk_rgba_parse (rgba, "#eeeeee");
+
+ rgba = &class->colors[E_MAIL_FORMATTER_COLOR_TEXT];
+ gdk_rgba_parse (rgba, "#000000");
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ANIMATE_IMAGES,
+ g_param_spec_boolean (
+ "animate-images",
+ "Animate images",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BODY_COLOR,
+ g_param_spec_boxed (
+ "body-color",
+ "Body Color",
+ NULL,
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CHARSET,
+ g_param_spec_string (
+ "charset",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CITATION_COLOR,
+ g_param_spec_boxed (
+ "citation-color",
+ "Citation Color",
+ NULL,
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CONTENT_COLOR,
+ g_param_spec_boxed (
+ "content-color",
+ "Content Color",
+ NULL,
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DEFAULT_CHARSET,
+ g_param_spec_string (
+ "default-charset",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FRAME_COLOR,
+ g_param_spec_boxed (
+ "frame-color",
+ "Frame Color",
+ NULL,
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_HEADER_COLOR,
+ g_param_spec_boxed (
+ "header-color",
+ "Header Color",
+ NULL,
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_IMAGE_LOADING_POLICY,
+ g_param_spec_enum (
+ "image-loading-policy",
+ "Image Loading Policy",
+ NULL,
+ E_TYPE_MAIL_IMAGE_LOADING_POLICY,
+ E_MAIL_IMAGE_LOADING_POLICY_NEVER,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MARK_CITATIONS,
+ g_param_spec_boolean (
+ "mark-citations",
+ "Mark Citations",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ 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_PARAM_STATIC_STRINGS));
+
+ 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_PARAM_STATIC_STRINGS));
+
+ 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_PARAM_STATIC_STRINGS));
+
+ signals[NEED_REDRAW] = g_signal_new (
+ "need-redraw",
+ E_TYPE_MAIL_FORMATTER,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EMailFormatterClass, need_redraw),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+}
+
+static void
+e_mail_formatter_init (EMailFormatter *formatter)
+{
+ formatter->priv = E_MAIL_FORMATTER_GET_PRIVATE (formatter);
+
+ g_mutex_init (&formatter->priv->property_lock);
+}
+
+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 *part_list,
+ CamelStream *stream,
+ EMailFormatterHeaderFlags flags,
+ EMailFormatterMode mode,
+ GCancellable *cancellable)
+{
+ EMailFormatterContext *context;
+ EMailFormatterClass *class;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ /* EMailPartList can be NULL. */
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+ class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+ g_return_if_fail (class->run != NULL);
+
+ context = mail_formatter_create_context (
+ formatter, part_list, mode, flags);
+
+ class->run (formatter, context, stream, cancellable);
+
+ mail_formatter_free_context (context);
+}
+
+static void
+mail_formatter_format_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ AsyncContext *async_context;
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ e_mail_formatter_format_sync (
+ E_MAIL_FORMATTER (source_object),
+ async_context->part_list,
+ async_context->stream,
+ async_context->flags,
+ async_context->mode,
+ cancellable);
+}
+
+void
+e_mail_formatter_format (EMailFormatter *formatter,
+ EMailPartList *part_list,
+ CamelStream *stream,
+ EMailFormatterHeaderFlags flags,
+ EMailFormatterMode mode,
+ GAsyncReadyCallback callback,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+ EMailFormatterClass *class;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ /* EMailPartList can be NULL. */
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+ class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+ g_return_if_fail (class->run != NULL);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->stream = g_object_ref (stream);
+ async_context->flags = flags;
+ async_context->mode = mode;
+
+ 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);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ if (part_list != NULL) {
+ async_context->part_list = g_object_ref (part_list);
+
+ g_simple_async_result_run_in_thread (
+ simple, mail_formatter_format_thread,
+ G_PRIORITY_DEFAULT, cancellable);
+ } else {
+ g_simple_async_result_complete_in_idle (simple);
+ }
+
+ g_object_unref (simple);
+}
+
+gboolean
+e_mail_formatter_format_finish (EMailFormatter *formatter,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (formatter),
+ e_mail_formatter_format), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
+/**
+ * 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 *extension_registry;
+ GQueue *formatters;
+ 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 != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE);
+
+ if (as_mime_type == NULL || *as_mime_type == '\0')
+ as_mime_type = e_mail_part_get_mime_type (part);
+
+ if (as_mime_type == NULL || *as_mime_type == '\0')
+ return FALSE;
+
+ extension_registry =
+ e_mail_formatter_get_extension_registry (formatter);
+ formatters = e_mail_extension_registry_get_for_mime_type (
+ extension_registry, as_mime_type);
+ if (formatters == NULL)
+ formatters = e_mail_extension_registry_get_fallback (
+ extension_registry, 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 != NULL) {
+ GList *head, *link;
+
+ head = g_queue_peek_head_link (formatters);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailFormatterExtension *extension;
+
+ extension = link->data;
+ if (extension == NULL)
+ 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;
+ CamelMimeFilter *windows = NULL;
+ CamelStream *mem_stream = NULL;
+ CamelMimePart *mime_part;
+ CamelContentType *mime_type;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ mime_type = CAMEL_DATA_WRAPPER (mime_part)->mime_type;
+
+ if (formatter->priv->charset != NULL) {
+ charset = formatter->priv->charset;
+ } else if (mime_type != NULL
+ && (charset = camel_content_type_param (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 = camel_mime_filter_windows_new (charset);
+ camel_stream_filter_add (
+ CAMEL_STREAM_FILTER (filter_stream), windows);
+
+ camel_data_wrapper_decode_to_stream_sync (
+ CAMEL_DATA_WRAPPER (mime_part),
+ filter_stream, cancellable, NULL);
+ camel_stream_flush (filter_stream, cancellable, NULL);
+ g_object_unref (filter_stream);
+
+ charset = camel_mime_filter_windows_real_charset (
+ CAMEL_MIME_FILTER_WINDOWS (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);
+
+ filter = camel_mime_filter_charset_new (charset, "UTF-8");
+ if (filter != NULL) {
+ camel_stream_filter_add (
+ CAMEL_STREAM_FILTER (filter_stream), filter);
+ g_object_unref (filter);
+ }
+
+ camel_data_wrapper_decode_to_stream_sync (
+ camel_medium_get_content (CAMEL_MEDIUM (mime_part)),
+ filter_stream, cancellable, NULL);
+ camel_stream_flush (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, stream, cancellable, NULL);
+ camel_stream_flush (mem_stream, cancellable, NULL);
+
+ if (windows != NULL)
+ g_object_unref (windows);
+
+ g_object_unref (mem_stream);
+
+ g_object_unref (mime_part);
+}
+
+gchar *
+e_mail_formatter_get_html_header (EMailFormatter *formatter)
+{
+ return g_strdup_printf (
+ "<!DOCTYPE HTML>\n"
+ "<html>\n"
+ "<head>\n"
+ "<meta name=\"generator\" content=\"Evolution Mail\"/>\n"
+ "<title>Evolution Mail Display</title>\n"
+ "<link type=\"text/css\" rel=\"stylesheet\" "
+ " href=\"" STYLESHEET_URI "\"/>\n"
+ "<style type=\"text/css\">\n"
+ " table th { color: #%06x; font-weight: bold; }\n"
+ "</style>\n"
+ "</head>"
+ "<body bgcolor=\"#%06x\" text=\"#%06x\">",
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_HEADER)),
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_BODY)),
+ e_rgba_to_value (
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_TEXT)));
+}
+
+EMailExtensionRegistry *
+e_mail_formatter_get_extension_registry (EMailFormatter *formatter)
+{
+ EMailFormatterClass * class;
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+ class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+ return E_MAIL_EXTENSION_REGISTRY (class->extension_registry);
+}
+
+CamelMimeFilterToHTMLFlags
+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 GdkRGBA *
+e_mail_formatter_get_color (EMailFormatter *formatter,
+ EMailFormatterColor 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,
+ EMailFormatterColor type,
+ const GdkRGBA *color)
+{
+ GdkRGBA *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_rgba_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_update_style (EMailFormatter *formatter,
+ GtkStateFlags state)
+{
+ EMailFormatterClass *class;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+ g_return_if_fail (class->update_style != NULL);
+
+ class->update_style (formatter, 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_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));
+
+ if (formatter->priv->show_sender_photo == show_sender_photo)
+ return;
+
+ 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));
+
+ if (formatter->priv->show_real_date == show_real_date)
+ return;
+
+ 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));
+
+ if (formatter->priv->animate_images == animate_images)
+ return;
+
+ 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;
+}
+
+gchar *
+e_mail_formatter_dup_charset (EMailFormatter *formatter)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+ g_mutex_lock (&formatter->priv->property_lock);
+
+ protected = e_mail_formatter_get_charset (formatter);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (&formatter->priv->property_lock);
+
+ return duplicate;
+}
+
+void
+e_mail_formatter_set_charset (EMailFormatter *formatter,
+ const gchar *charset)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ g_mutex_lock (&formatter->priv->property_lock);
+
+ if (g_strcmp0 (formatter->priv->charset, charset) == 0) {
+ g_mutex_unlock (&formatter->priv->property_lock);
+ return;
+ }
+
+ g_free (formatter->priv->charset);
+ formatter->priv->charset = g_strdup (charset);
+
+ g_mutex_unlock (&formatter->priv->property_lock);
+
+ 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;
+}
+
+gchar *
+e_mail_formatter_dup_default_charset (EMailFormatter *formatter)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+ g_mutex_lock (&formatter->priv->property_lock);
+
+ protected = e_mail_formatter_get_default_charset (formatter);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (&formatter->priv->property_lock);
+
+ return duplicate;
+}
+
+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);
+
+ g_mutex_lock (&formatter->priv->property_lock);
+
+ if (g_strcmp0 (formatter->priv->default_charset, default_charset) == 0) {
+ g_mutex_unlock (&formatter->priv->property_lock);
+ return;
+ }
+
+ g_free (formatter->priv->default_charset);
+ formatter->priv->default_charset = g_strdup (default_charset);
+
+ g_mutex_unlock (&formatter->priv->property_lock);
+
+ g_object_notify (G_OBJECT (formatter), "default-charset");
+}
+
diff --git a/em-format/e-mail-formatter.h b/em-format/e-mail-formatter.h
new file mode 100644
index 0000000000..9405789b72
--- /dev/null
+++ b/em-format/e-mail-formatter.h
@@ -0,0 +1,192 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_H_
+#define E_MAIL_FORMATTER_H_
+
+#include <gdk/gdk.h>
+#include <libemail-engine/e-mail-enums.h>
+
+#include <em-format/e-mail-extension-registry.h>
+#include <em-format/e-mail-formatter-enums.h>
+#include <em-format/e-mail-part-list.h>
+
+/* 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 struct _EMailFormatter EMailFormatter;
+typedef struct _EMailFormatterClass EMailFormatterClass;
+typedef struct _EMailFormatterPrivate EMailFormatterPrivate;
+typedef struct _EMailFormatterContext EMailFormatterContext;
+
+struct _EMailFormatterContext {
+ EMailPartList *part_list;
+ EMailFormatterMode mode;
+ EMailFormatterHeaderFlags flags;
+
+ gchar *uri;
+};
+
+struct _EMailFormatter {
+ GObject parent;
+ EMailFormatterPrivate *priv;
+};
+
+struct _EMailFormatterClass {
+ GObjectClass parent_class;
+
+ EMailFormatterExtensionRegistry *extension_registry;
+ CamelMimeFilterToHTMLFlags text_html_flags;
+
+ /* Colors should apply globally */
+ GdkRGBA colors[E_MAIL_FORMATTER_NUM_COLOR_TYPES];
+
+ /* sizeof(EMailFormatterContext) or some derivative struct */
+ gsize context_size;
+
+ void (*run) (EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ CamelStream *stream,
+ GCancellable *cancellable);
+
+ void (*update_style) (EMailFormatter *formatter,
+ GtkStateFlags state);
+
+ /* Signals */
+ void (*need_redraw) (EMailFormatter *formatter);
+};
+
+GType e_mail_formatter_get_type (void);
+
+EMailFormatter *
+ e_mail_formatter_new (void);
+
+void e_mail_formatter_format_sync (EMailFormatter *formatter,
+ EMailPartList *part_list,
+ CamelStream *stream,
+ EMailFormatterHeaderFlags flags,
+ EMailFormatterMode mode,
+ GCancellable *cancellable);
+
+void e_mail_formatter_format (EMailFormatter *formatter,
+ EMailPartList *part_list,
+ CamelStream *stream,
+ EMailFormatterHeaderFlags flags,
+ EMailFormatterMode mode,
+ GAsyncReadyCallback callback,
+ GCancellable *cancellable,
+ gpointer user_data);
+
+gboolean e_mail_formatter_format_finish (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);
+
+CamelMimeFilterToHTMLFlags
+ e_mail_formatter_get_text_format_flags
+ (EMailFormatter *formatter);
+
+const GdkRGBA * e_mail_formatter_get_color (EMailFormatter *formatter,
+ EMailFormatterColor type);
+void e_mail_formatter_set_color (EMailFormatter *formatter,
+ EMailFormatterColor type,
+ const GdkRGBA *color);
+void e_mail_formatter_update_style (EMailFormatter *formatter,
+ GtkStateFlags 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_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);
+gchar * e_mail_formatter_dup_charset (EMailFormatter *formatter);
+void e_mail_formatter_set_charset (EMailFormatter *formatter,
+ const gchar *charset);
+
+const gchar * e_mail_formatter_get_default_charset
+ (EMailFormatter *formatter);
+gchar * e_mail_formatter_dup_default_charset
+ (EMailFormatter *formatter);
+void e_mail_formatter_set_default_charset
+ (EMailFormatter *formatter,
+ const gchar *charset);
+
+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..538e884e8e
--- /dev/null
+++ b/em-format/e-mail-inline-filter.c
@@ -0,0 +1,496 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#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 gboolean
+newline_or_whitespace_follows (const gchar *str,
+ guint len,
+ guint skip_first)
+{
+ if (len <= skip_first)
+ return len == skip_first;
+
+ str += skip_first;
+ len -= skip_first;
+
+ while (len > 0 && *str != '\n') {
+ if (!*str)
+ return TRUE;
+
+ if (!camel_mime_is_lwsp (*str))
+ return FALSE;
+
+ len--;
+ str++;
+ }
+
+ return len == 0 || *str == '\n';
+}
+
+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 &&
+ newline_or_whitespace_follows (start, rest_len, 34)) {
+ 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 &&
+ newline_or_whitespace_follows (start, rest_len, 27)) {
+ 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 &&
+ newline_or_whitespace_follows (start, rest_len, 27)) {
+ 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 &&
+ newline_or_whitespace_follows (start, rest_len, 25)) {
+ 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.
+ * @filename: Filename of the part, or NULL
+ *
+ * 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,
+ const gchar *filename)
+{
+ 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);
+ }
+
+ if (filename && *filename)
+ emif->filename = g_strdup (filename);
+
+ 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..df4c2bc0f9
--- /dev/null
+++ b/em-format/e-mail-inline-filter.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_INLINE_FILTER_H
+#define E_MAIL_INLINE_FILTER_H
+
+#include <camel/camel.h>
+
+/* 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_IS_MAIL_INLINE_FILTER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_INLINE_FILTER))
+#define E_IS_MAIL_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,
+ const gchar *filename);
+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..73c86a7a57
--- /dev/null
+++ b/em-format/e-mail-parser-application-mbox.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserApplicationMBox;
+typedef EMailParserExtensionClass EMailParserApplicationMBoxClass;
+
+GType e_mail_parser_application_mbox_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserApplicationMBox,
+ e_mail_parser_application_mbox,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/mbox",
+ NULL
+};
+
+static gboolean
+empe_app_mbox_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelMimeParser *mime_parser;
+ CamelStream *mem_stream;
+ camel_mime_parser_state_t state;
+ gint old_len;
+ gint messages;
+ GError *error = 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);
+
+ camel_mime_parser_init_with_stream (mime_parser, mem_stream, &error);
+ if (error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Error parsing MBOX part: %s"),
+ error->message);
+ g_object_unref (mem_stream);
+ g_object_unref (mime_parser);
+ g_error_free (error);
+ return TRUE;
+ }
+
+ 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);
+
+ while (state == CAMEL_MIME_PARSER_STATE_FROM) {
+ GQueue work_queue = G_QUEUE_INIT;
+ CamelMimeMessage *message;
+ CamelMimePart *opart;
+
+ 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);
+
+ opart = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (opart), CAMEL_DATA_WRAPPER (message));
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (opart), "message/rfc822");
+
+ e_mail_parser_parse_part_as (
+ parser, opart, part_id, "message/rfc822",
+ cancellable, &work_queue);
+
+ /* Wrap every message as attachment */
+ e_mail_parser_wrap_as_attachment (
+ parser, opart, part_id, &work_queue);
+
+ /* Inline all messages in mbox */
+ if (!g_queue_is_empty (&work_queue)) {
+ EMailPart *p = g_queue_peek_head (&work_queue);
+
+ p->force_inline = TRUE;
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, old_len);
+
+ g_object_unref (message);
+ g_object_unref (opart);
+
+ /* 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 TRUE;
+}
+
+static void
+e_mail_parser_application_mbox_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->flags =
+ E_MAIL_PARSER_EXTENSION_INLINE |
+ E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+ class->parse = empe_app_mbox_parse;
+}
+
+static void
+e_mail_parser_application_mbox_init (EMailParserExtension *extension)
+{
+}
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..e84e1e948e
--- /dev/null
+++ b/em-format/e-mail-parser-application-smime.c
@@ -0,0 +1,161 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserApplicationSMIME;
+typedef EMailParserExtensionClass EMailParserApplicationSMIMEClass;
+
+GType e_mail_parser_application_smime_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserApplicationSMIME,
+ e_mail_parser_application_smime,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/xpkcs7mime",
+ "application/x-pkcs7-mime",
+ "application/pkcs7-mime",
+ "application/pkcs7-signature",
+ "application/xpkcs7-signature",
+ "application/x-pkcs7-signature",
+ NULL
+};
+
+static gboolean
+empe_app_smime_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelCipherContext *context;
+ CamelMimePart *opart;
+ CamelCipherValidity *valid;
+ GError *local_error = NULL;
+ CamelContentType *ct;
+
+ 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") ||
+ camel_content_type_is (ct, "application", "x-pkcs7-signature")) {
+ return TRUE;
+ }
+
+ 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 (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse S/MIME message: %s"),
+ local_error->message);
+ g_error_free (local_error);
+
+ } else {
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ gint len = part_id->len;
+
+ g_string_append (part_id, ".encrypted");
+
+ e_mail_parser_parse_part (
+ parser, opart, part_id, cancellable, &work_queue);
+
+ g_string_truncate (part_id, len);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ /* Update validity flags of all the involved subp-arts */
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_SMIME);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ /* 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)) {
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".encrypted.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.widget.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_SMIME);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ camel_cipher_validity_free (valid);
+ }
+
+ g_object_unref (opart);
+ g_object_unref (context);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_application_smime_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->flags = E_MAIL_PARSER_EXTENSION_INLINE;
+ class->parse = empe_app_smime_parse;
+}
+
+static void
+e_mail_parser_application_smime_init (EMailParserExtension *extension)
+{
+}
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..063221164c
--- /dev/null
+++ b/em-format/e-mail-parser-attachment-bar.c
@@ -0,0 +1,79 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-part-attachment-bar.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+
+typedef EMailParserExtension EMailParserAttachmentBar;
+typedef EMailParserExtensionClass EMailParserAttachmentBarClass;
+
+GType e_mail_parser_attachment_bar_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserAttachmentBar,
+ e_mail_parser_attachment_bar,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ E_MAIL_PART_ATTACHMENT_BAR_MIME_TYPE,
+ NULL
+};
+
+static gboolean
+empe_attachment_bar_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ EMailPart *mail_part;
+ gint len;
+
+ len = part_id->len;
+ g_string_append (part_id, ".attachment-bar");
+ mail_part = e_mail_part_attachment_bar_new (part, part_id->str);
+ e_mail_part_set_mime_type (mail_part, parser_mime_types[0]);
+ g_string_truncate (part_id, len);
+
+ g_queue_push_tail (out_mail_parts, mail_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_attachment_bar_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_attachment_bar_parse;
+}
+
+static void
+e_mail_parser_attachment_bar_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-extension.c b/em-format/e-mail-parser-extension.c
new file mode 100644
index 0000000000..68aac73cbf
--- /dev/null
+++ b/em-format/e-mail-parser-extension.c
@@ -0,0 +1,93 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-parser-extension.h"
+
+G_DEFINE_ABSTRACT_TYPE (
+ EMailParserExtension,
+ e_mail_parser_extension,
+ G_TYPE_OBJECT)
+
+static void
+e_mail_parser_extension_class_init (EMailParserExtensionClass *class)
+{
+ class->priority = G_PRIORITY_DEFAULT;
+}
+
+static void
+e_mail_parser_extension_init (EMailParserExtension *extension)
+{
+}
+
+/**
+ * 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.
+ * @cancellable: (allow-none) A #GCancellable
+ * @out_mail_parts: a #GQueue to deposit #EMailPart instances
+ *
+ * A virtual function reimplemented in all mail parser extensions. The function
+ * decodes and parses the @mime_part, appending one or more #EMailPart<!-//>s
+ * to the @out_mail_parts queue.
+ *
+ * When the function is unable to parse the @mime_part (either because it's
+ * broken or because it is a different MIME type then the extension is
+ * specialized for), the function will return %FALSE to indicate to 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 parts are appeded to @out_mail_parts in the correct order.
+ *
+ * part1.rfc822.plain_text
+ * part1.rfc822.attachment
+ * part2.image
+ *
+ * Implementation of this function must be thread-safe.
+ *
+ * Returns: %TRUE if the @mime_part was handled (even if no
+ * #EMailPart<!-//>s were added to @out_mail_parts), or
+ * %FALSE if the @mime_part was not handled
+ */
+gboolean
+e_mail_parser_extension_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *mime_part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ EMailParserExtensionClass *class;
+
+ g_return_val_if_fail (E_IS_MAIL_PARSER_EXTENSION (extension), FALSE);
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), FALSE);
+
+ class = E_MAIL_PARSER_EXTENSION_GET_CLASS (extension);
+ g_return_val_if_fail (class->parse != NULL, FALSE);
+
+ /* Check for cancellation before calling the method. */
+ if (g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ return class->parse (
+ extension, parser, mime_part, part_id,
+ cancellable, out_mail_parts);
+}
+
diff --git a/em-format/e-mail-parser-extension.h b/em-format/e-mail-parser-extension.h
new file mode 100644
index 0000000000..840f84dc3c
--- /dev/null
+++ b/em-format/e-mail-parser-extension.h
@@ -0,0 +1,96 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PARSER_EXTENSION_H
+#define E_MAIL_PARSER_EXTENSION_H
+
+#include <camel/camel.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-formatter-enums.h>
+
+/* 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_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PARSER_EXTENSION, EMailParserExtensionClass))
+#define E_IS_MAIL_PARSER_EXTENSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PARSER_EXTENSION))
+#define E_IS_MAIL_PARSER_EXTENSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PARSER_EXTENSION))
+#define E_MAIL_PARSER_EXTENSION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PARSER_EXTENSION, EMailParserExtensionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailParserExtension EMailParserExtension;
+typedef struct _EMailParserExtensionClass EMailParserExtensionClass;
+typedef struct _EMailParserExtensionPrivate EMailParserExtensionPrivate;
+
+/**
+ * EMailParserExtension:
+ *
+ * The #EMailParserExtension is an abstract interface for all extensions for
+ * #EMailParser.
+ */
+struct _EMailParserExtension {
+ GObject parent;
+ EMailParserExtensionPrivate *priv;
+};
+
+struct _EMailParserExtensionClass {
+ GObjectClass parent_class;
+
+ /* This is a NULL-terminated array of supported MIME types.
+ * The MIME types can be exact (e.g. "text/plain") or use a
+ * wildcard (e.g. "text/ *"). */
+ const gchar **mime_types;
+
+ /* This is used to prioritize extensions with identical MIME
+ * types. Lower values win. Defaults to G_PRIORITY_DEFAULT. */
+ gint priority;
+
+ /* See the flag descriptions above. */
+ EMailParserExtensionFlags flags;
+
+ gboolean (*parse) (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *mime_part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts);
+};
+
+GType e_mail_parser_extension_get_type
+ (void) G_GNUC_CONST;
+gboolean e_mail_parser_extension_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *mime_part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts);
+
+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..76cad8b22a
--- /dev/null
+++ b/em-format/e-mail-parser-headers.c
@@ -0,0 +1,80 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+#include <libemail-engine/e-mail-utils.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-headers.h"
+
+typedef EMailParserExtension EMailParserHeaders;
+typedef EMailParserExtensionClass EMailParserHeadersClass;
+
+GType e_mail_parser_headers_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserHeaders,
+ e_mail_parser_headers,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ E_MAIL_PART_HEADERS_MIME_TYPE,
+ NULL
+};
+
+static gboolean
+empe_headers_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ EMailPart *mail_part;
+ gint len;
+
+ len = part_id->len;
+ g_string_append (part_id, ".headers");
+
+ mail_part = e_mail_part_headers_new (part, part_id->str);
+ g_queue_push_tail (out_mail_parts, mail_part);
+
+ g_string_truncate (part_id, len);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_headers_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_headers_parse;
+}
+
+static void
+e_mail_parser_headers_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-image.c b/em-format/e-mail-parser-image.c
new file mode 100644
index 0000000000..807e72430e
--- /dev/null
+++ b/em-format/e-mail-parser-image.c
@@ -0,0 +1,102 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-image.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserImage;
+typedef EMailParserExtensionClass EMailParserImageClass;
+
+GType e_mail_parser_image_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserImage,
+ e_mail_parser_image,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+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 gboolean
+empe_image_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ GQueue work_queue = G_QUEUE_INIT;
+ EMailPart *mail_part;
+ gint len;
+
+ len = part_id->len;
+ g_string_append (part_id, ".image");
+
+ mail_part = e_mail_part_image_new (part, part_id->str);
+
+ g_string_truncate (part_id, len);
+
+ g_queue_push_tail (&work_queue, mail_part);
+
+ if (!mail_part->is_hidden)
+ e_mail_parser_wrap_as_attachment (
+ parser, part, part_id, &work_queue);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_image_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_image_parse;
+}
+
+static void
+e_mail_parser_image_init (EMailParserExtension *extension)
+{
+}
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..ae008dca02
--- /dev/null
+++ b/em-format/e-mail-parser-inlinepgp-encrypted.c
@@ -0,0 +1,188 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserInlinePGPEncrypted;
+typedef EMailParserExtensionClass EMailParserInlinePGPEncryptedClass;
+
+GType e_mail_parser_inline_pgp_encrypted_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserInlinePGPEncrypted,
+ e_mail_parser_inline_pgp_encrypted,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/x-inlinepgp-encrypted",
+ NULL
+};
+
+static gboolean
+empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelCipherContext *cipher;
+ CamelCipherValidity *valid;
+ CamelMimePart *opart;
+ CamelDataWrapper *dw;
+ gchar *mime_type;
+ gint len;
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ GError *local_error = NULL;
+
+ if (g_cancellable_is_cancelled (cancellable) ||
+ /* avoid recursion */
+ (part_id->str && part_id->len > 20 && g_str_has_suffix (part_id->str, ".inlinepgp_encrypted")))
+ return FALSE;
+
+ 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 (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse PGP message: %s"),
+ local_error->message);
+ g_error_free (local_error);
+
+ e_mail_parser_parse_part_as (
+ parser,
+ part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ g_object_unref (cipher);
+ g_object_unref (opart);
+
+ return TRUE;
+ }
+
+ 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;
+
+ snoop = e_mail_part_snoop_type (opart);
+
+ if (snoop != NULL) {
+ camel_data_wrapper_set_mime_type (dw, snoop);
+
+ /* Set the MIME type on the 'opart' itself as well.
+ * If it's "text/plain", then we want the TextPlain
+ * parser extension to treat it as "text/plain" and
+ * NOT wrap it as an attachment. */
+ camel_data_wrapper_set_mime_type (
+ CAMEL_DATA_WRAPPER (opart), 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");
+
+ e_mail_parser_parse_part_as (
+ parser, opart, part_id,
+ camel_data_wrapper_get_mime_type (dw),
+ cancellable, &work_queue);
+
+ g_string_truncate (part_id, len);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_PGP);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ /* 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)) {
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".inlinepgp_encrypted.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.widget.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_PGP);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ /* Clean Up */
+ camel_cipher_validity_free (valid);
+ g_object_unref (opart);
+ g_object_unref (cipher);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_inline_pgp_encrypted_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_inlinepgp_encrypted_parse;
+}
+
+static void
+e_mail_parser_inline_pgp_encrypted_init (EMailParserExtension *extension)
+{
+}
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..37cf5a2dcf
--- /dev/null
+++ b/em-format/e-mail-parser-inlinepgp-signed.c
@@ -0,0 +1,201 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserInlinePGPSigned;
+typedef EMailParserExtensionClass EMailParserInlinePGPSignedClass;
+
+GType e_mail_parser_inline_pgp_signed_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserInlinePGPSigned,
+ e_mail_parser_inline_pgp_signed,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/x-inlinepgp-signed",
+ NULL
+};
+
+static gboolean
+empe_inlinepgp_signed_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelStream *filtered_stream;
+ CamelMimeFilterPgp *pgp_filter;
+ CamelContentType *content_type;
+ CamelCipherContext *cipher;
+ CamelCipherValidity *valid;
+ CamelDataWrapper *dw;
+ CamelMimePart *opart;
+ CamelStream *ostream;
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ gchar *type;
+ gint len;
+ GError *local_error = NULL;
+ GByteArray *ba;
+
+ if (g_cancellable_is_cancelled (cancellable) ||
+ /* avoid recursion */
+ (part_id->str && part_id->len > 17 && g_str_has_suffix (part_id->str, ".inlinepgp_signed")))
+ return FALSE;
+
+ 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 (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Error verifying signature: %s"),
+ local_error->message);
+
+ g_error_free (local_error);
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ g_object_unref (cipher);
+
+ return TRUE;
+ }
+
+ /* 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");
+
+ e_mail_parser_parse_part (
+ parser, opart, part_id, cancellable, &work_queue);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_SIGNED |
+ E_MAIL_PART_VALIDITY_PGP);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ 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)) {
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".inlinepgp_signed.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.widget.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_SIGNED |
+ E_MAIL_PART_VALIDITY_PGP);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ /* Clean Up */
+ camel_cipher_validity_free (valid);
+ g_object_unref (opart);
+ g_object_unref (ostream);
+ g_object_unref (cipher);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_inline_pgp_signed_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_inlinepgp_signed_parse;
+}
+
+static void
+e_mail_parser_inline_pgp_signed_init (EMailParserExtension *extension)
+{
+}
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..9b672c52ba
--- /dev/null
+++ b/em-format/e-mail-parser-message-deliverystatus.c
@@ -0,0 +1,87 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+
+typedef EMailParserExtension EMailParserMessageDeliveryStatus;
+typedef EMailParserExtensionClass EMailParserMessageDeliveryStatusClass;
+
+GType e_mail_parser_message_delivery_status_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMessageDeliveryStatus,
+ e_mail_parser_message_delivery_status,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "message/delivery-status",
+ "message/feedback-report",
+ "message/disposition-notification",
+ NULL
+};
+
+static gboolean
+empe_msg_deliverystatus_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ GQueue work_queue = G_QUEUE_INIT;
+ EMailPart *mail_part;
+ gsize len;
+
+ len = part_id->len;
+ g_string_append (part_id, ".delivery-status");
+ mail_part = e_mail_part_new (part, part_id->str);
+ e_mail_part_set_mime_type (mail_part, "text/plain");
+
+ g_string_truncate (part_id, len);
+
+ g_queue_push_tail (&work_queue, mail_part);
+
+ /* The only reason for having a separate parser for
+ * message/delivery-status is to display the part as an attachment */
+ e_mail_parser_wrap_as_attachment (parser, part, part_id, &work_queue);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_message_delivery_status_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_msg_deliverystatus_parse;
+}
+
+static void
+e_mail_parser_message_delivery_status_init (EMailParserExtension *extension)
+{
+}
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..8668df5fba
--- /dev/null
+++ b/em-format/e-mail-parser-message-external.c
@@ -0,0 +1,182 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+
+typedef EMailParserExtension EMailParserMessageExternal;
+typedef EMailParserExtensionClass EMailParserMessageExternalClass;
+
+GType e_mail_parser_message_external_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMessageExternal,
+ e_mail_parser_message_external,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "message/external-body",
+ NULL
+};
+
+static gboolean
+empe_msg_external_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ EMailPart *mail_part;
+ CamelMimePart *newpart;
+ CamelContentType *type;
+ const gchar *access_type;
+ const gchar *mime_type;
+ gchar *url = NULL, *desc = NULL;
+ gchar *content;
+ gint len;
+
+ 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 = "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 = "text/html";
+ content = g_strdup_printf ("<a href=\"%s\">%s</a>", 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 = "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);
+ e_mail_part_set_mime_type (mail_part, mime_type);
+ g_string_truncate (part_id, len);
+
+ g_queue_push_tail (out_mail_parts, mail_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_message_external_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_msg_external_parse;
+}
+
+static void
+e_mail_parser_message_external_init (EMailParserExtension *extension)
+{
+}
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..e9bfab15a3
--- /dev/null
+++ b/em-format/e-mail-parser-message-rfc822.c
@@ -0,0 +1,136 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-list.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMessageRFC822;
+typedef EMailParserExtensionClass EMailParserMessageRFC822Class;
+
+GType e_mail_parser_message_rfc822_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMessageRFC822,
+ e_mail_parser_message_rfc822,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "message/rfc822",
+ "message/news",
+ NULL
+};
+
+static gboolean
+empe_msg_rfc822_parse (EMailParserExtension *extension,
+ EMailParser *eparser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ 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);
+ e_mail_part_set_mime_type (mail_part, "message/rfc822");
+ g_queue_push_tail (out_mail_parts, mail_part);
+
+ /* Sometime the actual message is encapsulated in another
+ * CamelMimePart, sometimes the CamelMimePart itself 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);
+ }
+
+ e_mail_parser_parse_part_as (
+ eparser, message, part_id,
+ "application/vnd.evolution.message",
+ cancellable, out_mail_parts);
+
+ 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 <iframe>. */
+ g_string_append (part_id, ".end");
+ mail_part = e_mail_part_new (message, part_id->str);
+ mail_part->is_hidden = TRUE;
+ g_queue_push_tail (out_mail_parts, mail_part);
+
+ g_string_truncate (part_id, len);
+
+ if (e_mail_part_is_attachment (message))
+ e_mail_parser_wrap_as_attachment (
+ eparser, message, part_id, out_mail_parts);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_message_rfc822_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->flags =
+ E_MAIL_PARSER_EXTENSION_INLINE |
+ E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+ class->parse = empe_msg_rfc822_parse;
+}
+
+static void
+e_mail_parser_message_rfc822_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-message.c b/em-format/e-mail-parser-message.c
new file mode 100644
index 0000000000..609663201c
--- /dev/null
+++ b/em-format/e-mail-parser-message.c
@@ -0,0 +1,130 @@
+/*
+ * e-mail-parser-message.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+#include <libemail-engine/e-mail-utils.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMessage;
+typedef EMailParserExtensionClass EMailParserMessageClass;
+
+GType e_mail_parser_message_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMessage,
+ e_mail_parser_message,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/vnd.evolution.message",
+ NULL
+};
+
+static gboolean
+empe_message_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ GQueue work_queue = G_QUEUE_INIT;
+ CamelContentType *ct;
+ EMailPart *mail_part;
+ gchar *mime_type;
+
+ /* Headers */
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.headers",
+ cancellable, out_mail_parts);
+
+ /* Attachment Bar */
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.widget.attachment-bar",
+ cancellable, out_mail_parts);
+
+ ct = camel_mime_part_get_content_type (part);
+ mime_type = camel_content_type_simple (ct);
+
+ if (mime_type && g_ascii_strcasecmp (mime_type, "message/rfc822") == 0) {
+ /* get mime type of the content of the message,
+ * instead of using a generic message/rfc822 */
+ CamelDataWrapper *content;
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (part));
+ if (content) {
+ ct = camel_data_wrapper_get_mime_type_field (content);
+
+ g_free (mime_type);
+ mime_type = camel_content_type_simple (ct);
+ }
+ }
+
+ /* Actual message body */
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, mime_type,
+ cancellable, &work_queue);
+
+ /* If the EMailPart representing the message body is marked as an
+ * attachment, wrap it as such so it gets added to the attachment
+ * bar but also set the "force_inline" flag since it doesn't make
+ * sense to collapse the message body if we can render it. */
+ mail_part = g_queue_peek_head (&work_queue);
+ if (mail_part != NULL) {
+ if (e_mail_part_get_is_attachment (mail_part)) {
+ e_mail_parser_wrap_as_attachment (
+ parser, part, part_id, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ if (mail_part != NULL)
+ mail_part->force_inline = TRUE;
+ }
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_free (mime_type);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_message_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_message_parse;
+}
+
+static void
+e_mail_parser_message_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-multipart-alternative.c b/em-format/e-mail-parser-multipart-alternative.c
new file mode 100644
index 0000000000..1ecb7789ce
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-alternative.c
@@ -0,0 +1,158 @@
+/*
+ * e-mail-parser-multipart-alternative.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMultipartAlternative;
+typedef EMailParserExtensionClass EMailParserMultipartAlternativeClass;
+
+GType e_mail_parser_multipart_alternative_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartAlternative,
+ e_mail_parser_multipart_alternative,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/alternative",
+ NULL
+};
+
+static gboolean
+related_display_part_is_attachment (CamelMimePart *part)
+{
+ CamelMimePart *display_part;
+
+ display_part = e_mail_part_get_related_display_part (part, NULL);
+ return display_part && e_mail_part_is_attachment (display_part);
+}
+
+static gboolean
+empe_mp_alternative_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelMultipart *mp;
+ gint i, nparts, bestid = 0;
+ CamelMimePart *best = NULL;
+ EMailExtensionRegistry *reg;
+
+ reg = e_mail_parser_get_extension_registry (parser);
+
+ mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+ if (!CAMEL_IS_MULTIPART (mp))
+ return e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ /* as per rfc, find the last part we know how to display */
+ nparts = camel_multipart_get_number (mp);
+ for (i = 0; i < nparts; i++) {
+ CamelMimePart *mpart;
+ CamelDataWrapper *data_wrapper;
+ CamelContentType *type;
+ CamelStream *null_stream;
+ gchar *mime_type;
+ gsize content_size;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return TRUE;
+
+ /* is it correct to use the passed in *part here? */
+ mpart = camel_multipart_get_part (mp, i);
+
+ if (mpart == NULL)
+ continue;
+
+ /* This may block even though the stream does not.
+ * XXX Pretty inefficient way to test if the MIME part
+ * is empty. Surely there's a quicker way? */
+ null_stream = camel_stream_null_new ();
+ data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (mpart));
+ camel_data_wrapper_decode_to_stream_sync (
+ data_wrapper, null_stream, cancellable, NULL);
+ content_size = CAMEL_STREAM_NULL (null_stream)->written;
+ g_object_unref (null_stream);
+
+ if (content_size == 0)
+ continue;
+
+ type = camel_mime_part_get_content_type (mpart);
+ mime_type = camel_content_type_simple (type);
+
+ camel_strdown (mime_type);
+
+ if (!e_mail_part_is_attachment (mpart) &&
+ ((camel_content_type_is (type, "multipart", "related") == 0) ||
+ !related_display_part_is_attachment (mpart)) &&
+ (e_mail_extension_registry_get_for_mime_type (reg, mime_type) ||
+ ((best == NULL) &&
+ (e_mail_extension_registry_get_fallback (reg, mime_type)))))
+ {
+ best = mpart;
+ bestid = i;
+ }
+
+ g_free (mime_type);
+ }
+
+ if (best) {
+ gint len = part_id->len;
+
+ g_string_append_printf (part_id, ".alternative.%d", bestid);
+
+ e_mail_parser_parse_part (
+ parser, best, part_id,
+ cancellable, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ } else {
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+ }
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_alternative_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_mp_alternative_parse;
+}
+
+static void
+e_mail_parser_multipart_alternative_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-multipart-appledouble.c b/em-format/e-mail-parser-multipart-appledouble.c
new file mode 100644
index 0000000000..bc79348783
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-appledouble.c
@@ -0,0 +1,95 @@
+/*
+ * e-mail-parser-multipart-appledouble.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-parser-extension.h"
+
+typedef EMailParserExtension EMailParserMultipartAppleDouble;
+typedef EMailParserExtensionClass EMailParserMultipartAppleDoubleClass;
+
+GType e_mail_parser_multipart_apple_double_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartAppleDouble,
+ e_mail_parser_multipart_apple_double,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/appledouble",
+ NULL
+};
+
+static gboolean
+empe_mp_appledouble_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelMultipart *mp;
+
+ mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+ if (!CAMEL_IS_MULTIPART (mp)) {
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+ } else {
+ CamelMimePart *mime_part;
+ mime_part = camel_multipart_get_part (mp, 1);
+
+ if (mime_part) {
+ gint len;
+ /* try the data fork for something useful, doubtful but who knows */
+ len = part_id->len;
+ g_string_append_printf (part_id, ".appledouble.1");
+
+ e_mail_parser_parse_part (
+ parser, mime_part, part_id,
+ cancellable, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+
+ } else {
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_apple_double_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_mp_appledouble_parse;
+}
+
+static void
+e_mail_parser_multipart_apple_double_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-multipart-digest.c b/em-format/e-mail-parser-multipart-digest.c
new file mode 100644
index 0000000000..ef1090848c
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-digest.c
@@ -0,0 +1,135 @@
+/*
+ * e-mail-parser-multipart-digest.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+
+typedef EMailParserExtension EMailParserMultipartDigest;
+typedef EMailParserExtensionClass EMailParserMultipartDigestClass;
+
+GType e_mail_parser_multipart_digest_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartDigest,
+ e_mail_parser_multipart_digest,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/digest",
+ NULL
+};
+
+static gboolean
+empe_mp_digest_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelMultipart *mp;
+ gint i, nparts, len;
+
+ mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+ if (!CAMEL_IS_MULTIPART (mp))
+ return e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ len = part_id->len;
+ nparts = camel_multipart_get_number (mp);
+ for (i = 0; i < nparts; i++) {
+ CamelMimePart *subpart;
+ CamelContentType *ct;
+ gchar *cts;
+
+ subpart = camel_multipart_get_part (mp, i);
+
+ if (!subpart)
+ continue;
+
+ g_string_append_printf (part_id, ".digest.%d", i);
+
+ ct = camel_mime_part_get_content_type (subpart);
+
+ /* According to RFC this shouldn't happen, but who knows... */
+ if (ct && !camel_content_type_is (ct, "message", "rfc822")) {
+ cts = camel_content_type_simple (ct);
+
+ e_mail_parser_parse_part_as (
+ parser, subpart, part_id, cts,
+ cancellable, out_mail_parts);
+
+ g_free (cts);
+ } else {
+ GQueue work_queue = G_QUEUE_INIT;
+ EMailPart *mail_part;
+ gboolean wrap_as_attachment;
+
+ e_mail_parser_parse_part_as (
+ parser, subpart, part_id, "message/rfc822",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ wrap_as_attachment =
+ (mail_part != NULL) &&
+ !e_mail_part_get_is_attachment (mail_part);
+
+ /* Force the message to be collapsable */
+ if (wrap_as_attachment)
+ e_mail_parser_wrap_as_attachment (
+ parser, subpart, part_id, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ /* Force the message to be expanded */
+ if (mail_part != NULL)
+ mail_part->force_inline = TRUE;
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+ }
+
+ g_string_truncate (part_id, len);
+ }
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_digest_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->flags = E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+ class->parse = empe_mp_digest_parse;
+}
+
+static void
+e_mail_parser_multipart_digest_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-multipart-encrypted.c b/em-format/e-mail-parser-multipart-encrypted.c
new file mode 100644
index 0000000000..85bcb9f41f
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-encrypted.c
@@ -0,0 +1,183 @@
+/*
+ * e-mail-parser-multipart-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMultipartEncrypted;
+typedef EMailParserExtensionClass EMailParserMultipartEncryptedClass;
+
+GType e_mail_parser_multipart_encrypted_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartEncrypted,
+ e_mail_parser_multipart_encrypted,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/encrypted",
+ NULL
+};
+
+static gboolean
+empe_mp_encrypted_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelCipherContext *context;
+ const gchar *protocol;
+ CamelMimePart *opart;
+ CamelCipherValidity *valid;
+ CamelMultipartEncrypted *mpe;
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ GError *local_error = NULL;
+ gint len;
+
+ mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part);
+ if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse MIME message. "
+ "Displaying as source."));
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution/source",
+ cancellable, out_mail_parts);
+
+ return TRUE;
+ }
+
+ /* Currently we only handle RFC2015-style PGP encryption. */
+ protocol = camel_content_type_param (
+ ((CamelDataWrapper *) mpe)->mime_type, "protocol");
+ if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Unsupported encryption type for multipart/encrypted"));
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ return TRUE;
+ }
+
+ context = camel_gpg_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 (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse PGP/MIME message: %s"),
+ local_error->message);
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ g_object_unref (opart);
+ g_object_unref (context);
+ g_error_free (local_error);
+
+ return TRUE;
+ }
+
+ len = part_id->len;
+ g_string_append (part_id, ".encrypted");
+
+ e_mail_parser_parse_part (
+ parser, opart, part_id, cancellable, &work_queue);
+
+ g_string_truncate (part_id, len);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ /* Update validity of all encrypted sub-parts */
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_PGP);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ /* Add a widget with details about the encryption, but only when
+ * the decrypted part isn't itself secured, in that case it has
+ * created the button itself. */
+ if (!e_mail_part_is_secured (opart)) {
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".encrypted.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.widget.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_PGP);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ camel_cipher_validity_free (valid);
+
+ /* TODO: Make sure when we finalize this part, it is zero'd out */
+ g_object_unref (opart);
+ g_object_unref (context);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_encrypted_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_mp_encrypted_parse;
+}
+
+static void
+e_mail_parser_multipart_encrypted_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-multipart-mixed.c b/em-format/e-mail-parser-multipart-mixed.c
new file mode 100644
index 0000000000..6fb9ca787f
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-mixed.c
@@ -0,0 +1,133 @@
+/*
+ * e-mail-parser-multipart-mixed.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMultipartMixed;
+typedef EMailParserExtensionClass EMailParserMultipartMixedClass;
+
+GType e_mail_parser_multipart_mixed_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartMixed,
+ e_mail_parser_multipart_mixed,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/mixed",
+ "multipart/report",
+ "multipart/*",
+ NULL
+};
+
+static gboolean
+empe_mp_mixed_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelMultipart *mp;
+ gint i, nparts, len;
+
+ mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+ if (!CAMEL_IS_MULTIPART (mp))
+ return e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ len = part_id->len;
+ nparts = camel_multipart_get_number (mp);
+ for (i = 0; i < nparts; i++) {
+ GQueue work_queue = G_QUEUE_INIT;
+ EMailPart *mail_part;
+ CamelMimePart *subpart;
+ CamelContentType *ct;
+
+ subpart = camel_multipart_get_part (mp, i);
+
+ g_string_append_printf (part_id, ".mixed.%d", i);
+
+ e_mail_parser_parse_part (
+ parser, subpart, part_id, cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ ct = camel_mime_part_get_content_type (subpart);
+
+ /* Display parts with CID as attachments
+ * (unless they already are attachments).
+ * Show also hidden attachments with CID,
+ * because this is multipart/mixed,
+ * not multipart/related. */
+ if (mail_part != NULL &&
+ e_mail_part_get_cid (mail_part) != NULL &&
+ (!e_mail_part_get_is_attachment (mail_part) ||
+ mail_part->is_hidden)) {
+
+ e_mail_parser_wrap_as_attachment (
+ parser, subpart, part_id, &work_queue);
+
+ /* Force messages to be expandable */
+ } else if (mail_part == NULL ||
+ (camel_content_type_is (ct, "message", "rfc822") &&
+ mail_part != NULL &&
+ !e_mail_part_get_is_attachment (mail_part))) {
+
+ e_mail_parser_wrap_as_attachment (
+ parser, subpart, part_id, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ if (mail_part != NULL)
+ mail_part->force_inline = TRUE;
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_mixed_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->flags = E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+ class->parse = empe_mp_mixed_parse;
+}
+
+static void
+e_mail_parser_multipart_mixed_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-multipart-related.c b/em-format/e-mail-parser-multipart-related.c
new file mode 100644
index 0000000000..45a5d440f5
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-related.c
@@ -0,0 +1,155 @@
+/*
+ * e-mail-parser-multipart-related.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMultipartRelated;
+typedef EMailParserExtensionClass EMailParserMultipartRelatedClass;
+
+GType e_mail_parser_multipart_related_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartRelated,
+ e_mail_parser_multipart_related,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/related",
+ NULL
+};
+
+static gboolean
+empe_mp_related_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelMultipart *mp;
+ CamelMimePart *body_part, *display_part = NULL;
+ CamelContentType *display_content_type;
+ gchar *html_body = NULL;
+ gint i, nparts, partidlen, displayid = 0;
+
+ mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+ if (!CAMEL_IS_MULTIPART (mp))
+ return e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ display_part = e_mail_part_get_related_display_part (part, &displayid);
+
+ if (display_part == NULL)
+ return e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ display_content_type = camel_mime_part_get_content_type (display_part);
+ if (display_content_type &&
+ camel_content_type_is (display_content_type, "text", "html")) {
+ CamelDataWrapper *dw;
+
+ dw = camel_medium_get_content ((CamelMedium *) display_part);
+ if (dw) {
+ CamelStream *mem = camel_stream_mem_new ();
+ GByteArray *bytes;
+
+ camel_data_wrapper_decode_to_stream_sync (dw, mem, cancellable, NULL);
+ camel_stream_close (mem, cancellable, NULL);
+
+ bytes = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem));
+ if (bytes && bytes->len)
+ html_body = g_strndup ((const gchar *) bytes->data, bytes->len);
+
+ g_object_unref (mem);
+ }
+ }
+
+ /* The to-be-displayed part goes first */
+ partidlen = part_id->len;
+ g_string_append_printf (part_id, ".related.%d", displayid);
+
+ e_mail_parser_parse_part (
+ parser, display_part, part_id, cancellable, out_mail_parts);
+
+ g_string_truncate (part_id, partidlen);
+
+ /* Process the related parts */
+ nparts = camel_multipart_get_number (mp);
+ for (i = 0; i < nparts; i++) {
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+
+ body_part = camel_multipart_get_part (mp, i);
+
+ if (body_part == display_part)
+ continue;
+
+ g_string_append_printf (part_id, ".related.%d", i);
+
+ e_mail_parser_parse_part (
+ parser, body_part, part_id,
+ cancellable, &work_queue);
+
+ g_string_truncate (part_id, partidlen);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+ const gchar *cid;
+
+ cid = e_mail_part_get_cid (mail_part);
+
+ /* Don't render the part on its own! */
+ if (e_mail_part_utils_body_refers (html_body, cid))
+ mail_part->is_hidden = TRUE;
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+ }
+
+ g_free (html_body);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_related_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_mp_related_parse;
+}
+
+static void
+e_mail_parser_multipart_related_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-multipart-signed.c b/em-format/e-mail-parser-multipart-signed.c
new file mode 100644
index 0000000000..440d791f6a
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-signed.c
@@ -0,0 +1,217 @@
+/*
+ * e-mail-parser-multipart-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMultipartSigned;
+typedef EMailParserExtensionClass EMailParserMultipartSignedClass;
+
+GType e_mail_parser_multipart_signed_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartSigned,
+ e_mail_parser_multipart_signed,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/signed",
+ "application/pgp-signature",
+ NULL
+};
+
+static gboolean
+empe_mp_signed_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelMimePart *cpart;
+ CamelMultipartSigned *mps;
+ CamelCipherContext *cipher = NULL;
+ CamelSession *session;
+ guint32 validity_type;
+ CamelCipherValidity *valid;
+ GError *local_error = NULL;
+ gint i, nparts, len;
+ gboolean secured;
+
+ /* If the part is application/pgp-signature sub-part then skip it. */
+ if (!CAMEL_IS_MULTIPART (part)) {
+ CamelContentType *ct;
+ ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (part));
+ if (camel_content_type_is (ct, "application", "pgp-signature")) {
+ return TRUE;
+ }
+ }
+
+ mps = (CamelMultipartSigned *) camel_medium_get_content ((CamelMedium *) part);
+ if (!CAMEL_IS_MULTIPART_SIGNED (mps)
+ || (
+ cpart = camel_multipart_get_part (
+ (CamelMultipart *) mps,
+ CAMEL_MULTIPART_SIGNED_CONTENT)) == NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse MIME message. "
+ "Displaying as source."));
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ return TRUE;
+ }
+
+ session = e_mail_parser_get_session (parser);
+ /* FIXME: Should be done via a plugin interface */
+ /* FIXME: duplicated in em-format-html-display.c */
+ if (mps->protocol) {
+#ifdef ENABLE_SMIME
+ if (g_ascii_strcasecmp ("application/x-pkcs7-signature", mps->protocol) == 0
+ || g_ascii_strcasecmp ("application/pkcs7-signature", mps->protocol) == 0) {
+ cipher = camel_smime_context_new (session);
+ validity_type = E_MAIL_PART_VALIDITY_SMIME;
+ } else {
+#endif
+ if (g_ascii_strcasecmp ("application/pgp-signature", mps->protocol) == 0) {
+ cipher = camel_gpg_context_new (session);
+ validity_type = E_MAIL_PART_VALIDITY_PGP;
+ }
+#ifdef ENABLE_SMIME
+ }
+#endif
+ }
+
+ if (cipher == NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Unsupported signature format"));
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ return TRUE;
+ }
+
+ valid = camel_cipher_context_verify_sync (
+ cipher, part, cancellable, &local_error);
+
+ if (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Error verifying signature: %s"),
+ local_error->message);
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ g_object_unref (cipher);
+ g_error_free (local_error);
+
+ return TRUE;
+ }
+
+ nparts = camel_multipart_get_number (CAMEL_MULTIPART (mps));
+ secured = FALSE;
+ len = part_id->len;
+ for (i = 0; i < nparts; i++) {
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ CamelMimePart *subpart;
+
+ subpart = camel_multipart_get_part (CAMEL_MULTIPART (mps), i);
+
+ g_string_append_printf (part_id, ".signed.%d", i);
+
+ e_mail_parser_parse_part (
+ parser, subpart, part_id, cancellable, &work_queue);
+
+ g_string_truncate (part_id, len);
+
+ if (!secured)
+ secured = e_mail_part_is_secured (subpart);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ validity_type | E_MAIL_PART_VALIDITY_SIGNED);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+ }
+
+ /* 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 (!secured) {
+ GQueue work_queue = G_QUEUE_INIT;
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".signed.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.widget.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ validity_type | E_MAIL_PART_VALIDITY_SIGNED);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ camel_cipher_validity_free (valid);
+
+ g_object_unref (cipher);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_signed_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_mp_signed_parse;
+}
+
+static void
+e_mail_parser_multipart_signed_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-secure-button.c b/em-format/e-mail-parser-secure-button.c
new file mode 100644
index 0000000000..2e2d9967fb
--- /dev/null
+++ b/em-format/e-mail-parser-secure-button.c
@@ -0,0 +1,77 @@
+/*
+ * e-mail-parser-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+
+typedef EMailParserExtension EMailParserSecureButton;
+typedef EMailParserExtensionClass EMailParserSecureButtonClass;
+
+GType e_mail_parser_secure_button_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserSecureButton,
+ e_mail_parser_secure_button,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/vnd.evolution.widget.secure-button",
+ NULL
+};
+
+static gboolean
+empe_secure_button_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ EMailPart *mail_part;
+ gint len;
+
+ len = part_id->len;
+ g_string_append (part_id, ".secure_button");
+ mail_part = e_mail_part_new (part, part_id->str);
+ e_mail_part_set_mime_type (mail_part, parser_mime_types[0]);
+ g_string_truncate (part_id, len);
+
+ g_queue_push_tail (out_mail_parts, mail_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_secure_button_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_secure_button_parse;
+}
+
+static void
+e_mail_parser_secure_button_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-source.c b/em-format/e-mail-parser-source.c
new file mode 100644
index 0000000000..9a8759cb95
--- /dev/null
+++ b/em-format/e-mail-parser-source.c
@@ -0,0 +1,78 @@
+/*
+ * e-mail-parser-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+
+typedef EMailParserExtension EMailParserSource;
+typedef EMailParserExtensionClass EMailParserSourceClass;
+
+GType e_mail_parser_source_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserSource,
+ e_mail_parser_source,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/vnd.evolution.source",
+ NULL
+};
+
+static gboolean
+empe_source_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ EMailPart *mail_part;
+ gint len;
+
+ len = part_id->len;
+ g_string_append (part_id, ".source");
+
+ mail_part = e_mail_part_new (part, part_id->str);
+ e_mail_part_set_mime_type (mail_part, parser_mime_types[0]);
+ g_string_truncate (part_id, len);
+
+ g_queue_push_tail (out_mail_parts, mail_part);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_source_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_source_parse;
+}
+
+static void
+e_mail_parser_source_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-text-enriched.c b/em-format/e-mail-parser-text-enriched.c
new file mode 100644
index 0000000000..f938471e62
--- /dev/null
+++ b/em-format/e-mail-parser-text-enriched.c
@@ -0,0 +1,109 @@
+/*
+ * e-mail-parser-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserTextEnriched;
+typedef EMailParserExtensionClass EMailParserTextEnrichedClass;
+
+GType e_mail_parser_text_enriched_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserTextEnriched,
+ e_mail_parser_text_enriched,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "text/richtext",
+ "text/enriched",
+ NULL
+};
+
+static gboolean
+empe_text_enriched_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ GQueue work_queue = G_QUEUE_INIT;
+ EMailPart *mail_part;
+ const gchar *cid;
+ gint len;
+ CamelContentType *ct;
+
+ len = part_id->len;
+ g_string_append (part_id, ".text_enriched");
+
+ mail_part = e_mail_part_new (part, part_id->str);
+
+ ct = camel_mime_part_get_content_type (part);
+ if (ct != NULL) {
+ gchar *mime_type;
+
+ mime_type = camel_content_type_simple (ct);
+ e_mail_part_set_mime_type (mail_part, mime_type);
+ g_free (mime_type);
+ } else {
+ e_mail_part_set_mime_type (mail_part, "text/enriched");
+ }
+
+ cid = camel_mime_part_get_content_id (part);
+ if (cid != NULL) {
+ gchar *cid_uri;
+
+ cid_uri = g_strdup_printf ("cid:%s", cid);
+ e_mail_part_set_cid (mail_part, cid_uri);
+ g_free (cid_uri);
+ }
+
+ g_string_truncate (part_id, len);
+
+ g_queue_push_tail (&work_queue, mail_part);
+
+ if (e_mail_part_is_attachment (part))
+ e_mail_parser_wrap_as_attachment (
+ parser, part, part_id, &work_queue);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_text_enriched_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_text_enriched_parse;
+}
+
+static void
+e_mail_parser_text_enriched_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-text-html.c b/em-format/e-mail-parser-text-html.c
new file mode 100644
index 0000000000..bfb8cae2af
--- /dev/null
+++ b/em-format/e-mail-parser-text-html.c
@@ -0,0 +1,110 @@
+/*
+ * e-mail-parser-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserTextHTML;
+typedef EMailParserExtensionClass EMailParserTextHTMLClass;
+
+GType e_mail_parser_text_html_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserTextHTML,
+ e_mail_parser_text_html,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "text/html",
+ NULL
+};
+
+static gboolean
+empe_text_html_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ GQueue work_queue = G_QUEUE_INIT;
+ EMailPart *mail_part;
+ const gchar *location;
+ gchar *cid = NULL;
+ const gchar *base;
+ gint len;
+
+ cid = NULL;
+ base = camel_medium_get_header (CAMEL_MEDIUM (part), "content-base");
+ location = camel_mime_part_get_content_location (part);
+ if (location != NULL) {
+ if (strchr (location, ':') == NULL && base != NULL) {
+ CamelURL *uri;
+ CamelURL *base_url = camel_url_new (base, NULL);
+
+ uri = camel_url_new_with_base (base_url, location);
+ cid = camel_url_to_string (uri, 0);
+ camel_url_free (uri);
+ camel_url_free (base_url);
+ } else {
+ cid = g_strdup (location);
+ }
+ }
+
+ len = part_id->len;
+ g_string_append (part_id, ".text_html");
+
+ mail_part = e_mail_part_new (part, part_id->str);
+ e_mail_part_set_mime_type (mail_part, "text/html");
+ e_mail_part_set_cid (mail_part, cid);
+ g_string_truncate (part_id, len);
+
+ g_queue_push_head (&work_queue, mail_part);
+
+ if (e_mail_part_is_attachment (part))
+ e_mail_parser_wrap_as_attachment (
+ parser, part, part_id, &work_queue);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_free (cid);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_text_html_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_text_html_parse;
+}
+
+static void
+e_mail_parser_text_html_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser-text-plain.c b/em-format/e-mail-parser-text-plain.c
new file mode 100644
index 0000000000..a4550ea0fe
--- /dev/null
+++ b/em-format/e-mail-parser-text-plain.c
@@ -0,0 +1,241 @@
+/*
+ * e-mail-parser-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#include "e-mail-inline-filter.h"
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserTextPlain;
+typedef EMailParserExtensionClass EMailParserTextPlainClass;
+
+GType e_mail_parser_text_plain_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserTextPlain,
+ e_mail_parser_text_plain,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "text/plain",
+ "text/*",
+ NULL
+};
+
+static gboolean
+part_is_empty (CamelMimePart *part)
+{
+ CamelDataWrapper *dw;
+ GByteArray *ba;
+ guint i;
+
+ dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+ ba = camel_data_wrapper_get_byte_array (dw);
+
+ if (!ba)
+ return TRUE;
+
+ for (i = 0; i < ba->len; i++) {
+
+ /* Checks for \n, \t, \f, \r, \v and space */
+ if (!isspace (ba->data[i]))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+process_part (EMailParser *parser,
+ GString *part_id,
+ gint part_number,
+ CamelMimePart *part,
+ gboolean is_attachment,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelContentType *type;
+ EMailPart *mail_part;
+ gint s_len = part_id->len;
+
+ if (part_is_empty (part))
+ return TRUE;
+
+ type = camel_mime_part_get_content_type (part);
+ if (!camel_content_type_is (type, "text", "*")) {
+ e_mail_parser_parse_part (
+ parser, CAMEL_MIME_PART (part), part_id,
+ cancellable, out_mail_parts);
+
+ } else if (!camel_content_type_is (type, "text", "calendar")) {
+ GQueue work_queue = G_QUEUE_INIT;
+ gchar *mime_type;
+
+ g_string_append_printf (part_id, ".plain_text.%d", part_number);
+
+ mail_part = e_mail_part_new (part, part_id->str);
+
+ mime_type = camel_content_type_simple (type);
+ e_mail_part_set_mime_type (mail_part, mime_type);
+ g_free (mime_type);
+
+ g_string_truncate (part_id, s_len);
+
+ g_queue_push_tail (&work_queue, mail_part);
+
+ if (is_attachment)
+ e_mail_parser_wrap_as_attachment (
+ parser, part, part_id, &work_queue);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ } else {
+ g_string_append_printf (part_id, ".inline.%d", part_number);
+
+ e_mail_parser_parse_part (
+ parser, CAMEL_MIME_PART (part), part_id,
+ cancellable, out_mail_parts);
+
+ g_string_truncate (part_id, s_len);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+empe_text_plain_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelStream *filtered_stream, *null;
+ CamelMultipart *mp;
+ CamelDataWrapper *dw;
+ CamelContentType *type;
+ gint ii, count;
+ EMailInlineFilter *inline_filter;
+ gboolean charset_added = FALSE;
+ const gchar *snoop_type = NULL;
+ gboolean is_attachment;
+ gboolean handled = FALSE;
+
+ dw = camel_medium_get_content ((CamelMedium *) part);
+ if (!dw)
+ return FALSE;
+
+ /* This scans the text part for inline-encoded data, creates
+ * a multipart of all the parts inside it. */
+
+ /* FIXME: We should discard this multipart if it only contains
+ * the original text, but it makes this hash lookup more complex */
+ if (!dw->mime_type)
+ snoop_type = e_mail_part_snoop_type (part);
+
+ /* if we had to snoop the part type to get here, then
+ * use that as the base type, yuck */
+ if (snoop_type == NULL
+ || (type = camel_content_type_decode (snoop_type)) == NULL) {
+ type = dw->mime_type;
+ camel_content_type_ref (type);
+ }
+
+ if (dw->mime_type && type != dw->mime_type && camel_content_type_param (dw->mime_type, "charset")) {
+ camel_content_type_set_param (type, "charset", camel_content_type_param (dw->mime_type, "charset"));
+ charset_added = TRUE;
+ }
+
+ null = camel_stream_null_new ();
+ filtered_stream = camel_stream_filter_new (null);
+ g_object_unref (null);
+ inline_filter = e_mail_inline_filter_new (
+ camel_mime_part_get_encoding (part),
+ type,
+ camel_mime_part_get_filename (part));
+
+ camel_stream_filter_add (
+ CAMEL_STREAM_FILTER (filtered_stream),
+ CAMEL_MIME_FILTER (inline_filter));
+ camel_data_wrapper_decode_to_stream_sync (
+ dw, (CamelStream *) filtered_stream, cancellable, NULL);
+ camel_stream_close ((CamelStream *) filtered_stream, cancellable, NULL);
+ g_object_unref (filtered_stream);
+
+ if (!e_mail_inline_filter_found_any (inline_filter)) {
+ g_object_unref (inline_filter);
+ camel_content_type_unref (type);
+
+ return process_part (
+ parser, part_id, 0,
+ part, e_mail_part_is_attachment (part),
+ cancellable, out_mail_parts);
+ }
+
+ mp = e_mail_inline_filter_get_multipart (inline_filter);
+
+ if (charset_added) {
+ camel_content_type_set_param (type, "charset", NULL);
+ }
+
+ g_object_unref (inline_filter);
+ camel_content_type_unref (type);
+
+ /* We handle our made-up multipart here,
+ * so we don't recursively call ourselves. */
+
+ count = camel_multipart_get_number (mp);
+
+ is_attachment = ((count == 1) && (e_mail_part_is_attachment (part)));
+
+ for (ii = 0; ii < count; ii++) {
+ CamelMimePart *newpart = camel_multipart_get_part (mp, ii);
+
+ if (newpart != NULL) {
+ handled |= process_part (
+ parser, part_id, ii,
+ newpart, is_attachment,
+ cancellable, out_mail_parts);
+ }
+ }
+
+ g_object_unref (mp);
+
+ return handled;
+}
+
+static void
+e_mail_parser_text_plain_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_text_plain_parse;
+}
+
+static void
+e_mail_parser_text_plain_init (EMailParserExtension *extension)
+{
+}
diff --git a/em-format/e-mail-parser.c b/em-format/e-mail-parser.c
new file mode 100644
index 0000000000..57c362e286
--- /dev/null
+++ b/em-format/e-mail-parser.c
@@ -0,0 +1,776 @@
+/*
+ * e-mail-parser.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-parser.h"
+
+#include <string.h>
+
+#include <libebackend/libebackend.h>
+
+#include <shell/e-shell.h>
+#include <shell/e-shell-window.h>
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-utils.h"
+
+#define E_MAIL_PARSER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PARSER, EMailParserPrivate))
+
+#define d(x)
+
+struct _EMailParserPrivate {
+ GMutex mutex;
+
+ gint last_error;
+
+ CamelSession *session;
+};
+
+enum {
+ PROP_0,
+ PROP_SESSION
+};
+
+/* internal parser extensions */
+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
+
+void e_mail_parser_internal_extensions_load (EMailExtensionRegistry *ereg);
+
+static gpointer parent_class;
+
+static void
+mail_parser_run (EMailParser *parser,
+ EMailPartList *part_list,
+ GCancellable *cancellable)
+{
+ EMailExtensionRegistry *reg;
+ CamelMimeMessage *message;
+ EMailPart *mail_part;
+ GQueue *parsers;
+ GQueue mail_part_queue = G_QUEUE_INIT;
+ GList *iter;
+ GString *part_id;
+
+ message = e_mail_part_list_get_message (part_list);
+
+ reg = e_mail_parser_get_extension_registry (parser);
+
+ parsers = e_mail_extension_registry_get_for_mime_type (
+ reg, "application/vnd.evolution.message");
+
+ if (parsers == NULL)
+ parsers = e_mail_extension_registry_get_for_mime_type (
+ reg, "message/*");
+
+ /* No parsers means the internal Evolution parser
+ * extensions were not loaded. Something is terribly wrong! */
+ g_return_if_fail (parsers != NULL);
+
+ part_id = g_string_new (".message");
+
+ mail_part = e_mail_part_new (CAMEL_MIME_PART (message), ".message");
+ e_mail_part_list_add_part (part_list, mail_part);
+ g_object_unref (mail_part);
+
+ for (iter = parsers->head; iter; iter = iter->next) {
+ EMailParserExtension *extension;
+ gboolean message_handled;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ break;
+
+ extension = iter->data;
+ if (!extension)
+ continue;
+
+ message_handled = e_mail_parser_extension_parse (
+ extension, parser,
+ CAMEL_MIME_PART (message),
+ part_id, cancellable, &mail_part_queue);
+
+ if (message_handled)
+ break;
+ }
+
+ while (!g_queue_is_empty (&mail_part_queue)) {
+ mail_part = g_queue_pop_head (&mail_part_queue);
+ e_mail_part_list_add_part (part_list, mail_part);
+ g_object_unref (mail_part);
+ }
+
+ g_string_free (part_id, TRUE);
+}
+
+static void
+mail_parser_set_session (EMailParser *parser,
+ CamelSession *session)
+{
+ g_return_if_fail (CAMEL_IS_SESSION (session));
+ g_return_if_fail (parser->priv->session == NULL);
+
+ parser->priv->session = g_object_ref (session);
+}
+
+static void
+e_mail_parser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SESSION:
+ mail_parser_set_session (
+ E_MAIL_PARSER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_parser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SESSION:
+ g_value_set_object (
+ value,
+ e_mail_parser_get_session (
+ E_MAIL_PARSER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_parser_finalize (GObject *object)
+{
+ EMailParserPrivate *priv;
+
+ priv = E_MAIL_PARSER_GET_PRIVATE (object);
+
+ g_mutex_clear (&priv->mutex);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+e_mail_parser_base_init (EMailParserClass *class)
+{
+ /* Register internal extensions. */
+ g_type_ensure (e_mail_parser_application_mbox_get_type ());
+ g_type_ensure (e_mail_parser_attachment_bar_get_type ());
+ g_type_ensure (e_mail_parser_headers_get_type ());
+ g_type_ensure (e_mail_parser_message_get_type ());
+ g_type_ensure (e_mail_parser_secure_button_get_type ());
+ g_type_ensure (e_mail_parser_source_get_type ());
+ g_type_ensure (e_mail_parser_image_get_type ());
+ g_type_ensure (e_mail_parser_inline_pgp_encrypted_get_type ());
+ g_type_ensure (e_mail_parser_inline_pgp_signed_get_type ());
+ g_type_ensure (e_mail_parser_message_delivery_status_get_type ());
+ g_type_ensure (e_mail_parser_message_external_get_type ());
+ g_type_ensure (e_mail_parser_message_rfc822_get_type ());
+ g_type_ensure (e_mail_parser_multipart_alternative_get_type ());
+ g_type_ensure (e_mail_parser_multipart_apple_double_get_type ());
+ g_type_ensure (e_mail_parser_multipart_digest_get_type ());
+ g_type_ensure (e_mail_parser_multipart_encrypted_get_type ());
+ g_type_ensure (e_mail_parser_multipart_mixed_get_type ());
+ g_type_ensure (e_mail_parser_multipart_related_get_type ());
+ g_type_ensure (e_mail_parser_multipart_signed_get_type ());
+ g_type_ensure (e_mail_parser_text_enriched_get_type ());
+ g_type_ensure (e_mail_parser_text_html_get_type ());
+ g_type_ensure (e_mail_parser_text_plain_get_type ());
+#ifdef ENABLE_SMIME
+ g_type_ensure (e_mail_parser_application_smime_get_type ());
+#endif
+
+ class->extension_registry = g_object_new (
+ E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, NULL);
+
+ e_mail_parser_extension_registry_load (class->extension_registry);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (class->extension_registry));
+}
+
+static void
+e_mail_parser_base_finalize (EMailParserClass *class)
+{
+ g_object_unref (class->extension_registry);
+}
+
+static void
+e_mail_parser_class_init (EMailParserClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailParserPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = e_mail_parser_finalize;
+ object_class->set_property = e_mail_parser_set_property;
+ object_class->get_property = e_mail_parser_get_property;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SESSION,
+ g_param_spec_object (
+ "session",
+ "Camel Session",
+ NULL,
+ CAMEL_TYPE_SESSION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+e_mail_parser_init (EMailParser *parser)
+{
+ parser->priv = E_MAIL_PARSER_GET_PRIVATE (parser);
+
+ g_mutex_init (&parser->priv->mutex);
+}
+
+GType
+e_mail_parser_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailParserClass),
+ (GBaseInitFunc) e_mail_parser_base_init,
+ (GBaseFinalizeFunc) e_mail_parser_base_finalize,
+ (GClassInitFunc) e_mail_parser_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailParser),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) e_mail_parser_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EMailParser",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+EMailParser *
+e_mail_parser_new (CamelSession *session)
+{
+ g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PARSER,
+ "session", session, NULL);
+}
+
+/**
+ * e_mail_parser_parse_sync:
+ * @parser: an #EMailParser
+ * @folder: (allow none) a #CamelFolder containing the @message or %NULL
+ * @message_uid: (allow none) UID of the @message within the @folder or %NULL
+ * @message: a #CamelMimeMessage
+ * @cancellable: (allow-none) a #GCancellable
+ *
+ * Parses the @message synchronously. Returns a list of #EMailPart<!-//>s which
+ * represents structure of the message and additional properties of each part.
+ *
+ * Note that this function can block for a while, so it's not a good idea to call
+ * it from main thread.
+ *
+ * Return Value: An #EMailPartsList
+ */
+EMailPartList *
+e_mail_parser_parse_sync (EMailParser *parser,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ GCancellable *cancellable)
+{
+ EMailPartList *part_list;
+
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+ part_list = e_mail_part_list_new (message, message_uid, folder);
+
+ mail_parser_run (parser, part_list, cancellable);
+
+ if (camel_debug_start ("emformat:parser")) {
+ GQueue queue = G_QUEUE_INIT;
+
+ printf (
+ "%s finished with EMailPartList:\n",
+ G_OBJECT_TYPE_NAME (parser));
+
+ e_mail_part_list_queue_parts (part_list, NULL, &queue);
+
+ while (!g_queue_is_empty (&queue)) {
+ EMailPart *part;
+
+ part = g_queue_pop_head (&queue);
+
+ printf (
+ " id: %s | cid: %s | mime_type: %s | "
+ "is_hidden: %d | is_attachment: %d\n",
+ e_mail_part_get_id (part),
+ e_mail_part_get_cid (part),
+ e_mail_part_get_mime_type (part),
+ part->is_hidden ? 1 : 0,
+ e_mail_part_get_is_attachment (part) ? 1 : 0);
+
+ g_object_unref (part);
+ }
+
+ camel_debug_end ();
+ }
+
+ return part_list;
+}
+
+static void
+mail_parser_parse_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EMailPartList *part_list;
+
+ part_list = g_simple_async_result_get_op_res_gpointer (simple);
+
+ mail_parser_run (
+ E_MAIL_PARSER (source_object),
+ part_list, cancellable);
+}
+
+/**
+ * e_mail_parser_parse:
+ * @parser: an #EMailParser
+ * @message: a #CamelMimeMessage
+ * @callback: a #GAsyncReadyCallback
+ * @cancellable: (allow-none) a #GCancellable
+ * @user_data: (allow-none) user data passed to the callback
+ *
+ * Asynchronous version of e_mail_parser_parse_sync().
+ */
+void
+e_mail_parser_parse (EMailParser *parser,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ GAsyncReadyCallback callback,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ EMailPartList *part_list;
+
+ g_return_if_fail (E_IS_MAIL_PARSER (parser));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ part_list = e_mail_part_list_new (message, message_uid, folder);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (parser), callback,
+ user_data, e_mail_parser_parse);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, part_list, (GDestroyNotify) g_object_unref);
+
+ g_simple_async_result_run_in_thread (
+ simple, mail_parser_parse_thread,
+ G_PRIORITY_DEFAULT, cancellable);
+
+ g_object_unref (simple);
+}
+
+EMailPartList *
+e_mail_parser_parse_finish (EMailParser *parser,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ EMailPartList *part_list;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (parser), e_mail_parser_parse), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ part_list = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (camel_debug_start ("emformat:parser")) {
+ GQueue queue = G_QUEUE_INIT;
+
+ printf (
+ "%s finished with EMailPartList:\n",
+ G_OBJECT_TYPE_NAME (parser));
+
+ e_mail_part_list_queue_parts (part_list, NULL, &queue);
+
+ while (!g_queue_is_empty (&queue)) {
+ EMailPart *part;
+
+ part = g_queue_pop_head (&queue);
+
+ printf (
+ " id: %s | cid: %s | mime_type: %s | "
+ "is_hidden: %d | is_attachment: %d\n",
+ e_mail_part_get_id (part),
+ e_mail_part_get_cid (part),
+ e_mail_part_get_mime_type (part),
+ part->is_hidden ? 1 : 0,
+ e_mail_part_get_is_attachment (part) ? 1 : 0);
+
+ g_object_unref (part);
+ }
+
+ camel_debug_end ();
+ }
+
+ return g_object_ref (part_list);
+}
+
+gboolean
+e_mail_parser_parse_part (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelContentType *ct;
+ gchar *mime_type;
+ gint n_parts_queued = 0;
+
+ ct = camel_mime_part_get_content_type (part);
+ if (!ct) {
+ mime_type = (gchar *) "application/vnd.evolution.error";
+ } else {
+ gchar *tmp;
+ tmp = camel_content_type_simple (ct);
+ mime_type = g_ascii_strdown (tmp, -1);
+ g_free (tmp);
+ }
+
+ n_parts_queued = e_mail_parser_parse_part_as (
+ parser, part, part_id, mime_type,
+ cancellable, out_mail_parts);
+
+ if (ct) {
+ g_free (mime_type);
+ }
+
+ return n_parts_queued;
+}
+
+gboolean
+e_mail_parser_parse_part_as (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ const gchar *mime_type,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ GQueue *parsers;
+ GList *iter;
+ EMailExtensionRegistry *reg;
+ EMailParserClass *parser_class;
+ gchar *as_mime_type;
+ gboolean mime_part_handled = FALSE;
+
+ if (mime_type)
+ as_mime_type = g_ascii_strdown (mime_type, -1);
+ else
+ as_mime_type = NULL;
+
+ parser_class = E_MAIL_PARSER_GET_CLASS (parser);
+ reg = E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry);
+
+ parsers = e_mail_extension_registry_get_for_mime_type (reg, as_mime_type);
+ if (!parsers) {
+ parsers = e_mail_extension_registry_get_fallback (reg, as_mime_type);
+ }
+
+ if (as_mime_type)
+ g_free (as_mime_type);
+
+ if (parsers == NULL) {
+ e_mail_parser_wrap_as_attachment (
+ parser, part, part_id, out_mail_parts);
+ return TRUE;
+ }
+
+ for (iter = parsers->head; iter; iter = iter->next) {
+ EMailParserExtension *extension;
+
+ extension = iter->data;
+ if (!extension)
+ continue;
+
+ mime_part_handled = e_mail_parser_extension_parse (
+ extension, parser, part, part_id,
+ cancellable, out_mail_parts);
+
+ if (mime_part_handled)
+ break;
+ }
+
+ return mime_part_handled;
+}
+
+void
+e_mail_parser_error (EMailParser *parser,
+ GQueue *out_mail_parts,
+ const gchar *format,
+ ...)
+{
+ const gchar *mime_type = "application/vnd.evolution.error";
+ EMailPart *mail_part;
+ CamelMimePart *part;
+ gchar *errmsg;
+ gchar *uri;
+ va_list ap;
+
+ g_return_if_fail (E_IS_MAIL_PARSER (parser));
+ g_return_if_fail (out_mail_parts != NULL);
+ g_return_if_fail (format != NULL);
+
+ va_start (ap, format);
+ errmsg = g_strdup_vprintf (format, ap);
+
+ part = camel_mime_part_new ();
+ camel_mime_part_set_content (
+ part, errmsg, strlen (errmsg), mime_type);
+ g_free (errmsg);
+ va_end (ap);
+
+ g_mutex_lock (&parser->priv->mutex);
+ parser->priv->last_error++;
+ uri = g_strdup_printf (".error.%d", parser->priv->last_error);
+ g_mutex_unlock (&parser->priv->mutex);
+
+ mail_part = e_mail_part_new (part, uri);
+ e_mail_part_set_mime_type (mail_part, mime_type);
+ mail_part->is_error = TRUE;
+
+ g_free (uri);
+ g_object_unref (part);
+
+ g_queue_push_tail (out_mail_parts, mail_part);
+}
+
+static void
+attachment_loaded (EAttachment *attachment,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EShell *shell;
+ GtkWindow *window;
+
+ shell = e_shell_get_default ();
+ window = e_shell_get_active_window (shell);
+
+ e_attachment_load_handle_error (attachment, res, window);
+
+ g_object_unref (attachment);
+}
+
+/* Idle callback */
+static gboolean
+load_attachment_idle (EAttachment *attachment)
+{
+ e_attachment_load_async (
+ attachment,
+ (GAsyncReadyCallback) attachment_loaded, NULL);
+
+ return FALSE;
+}
+
+void
+e_mail_parser_wrap_as_attachment (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GQueue *parts_queue)
+{
+ EMailPartAttachment *empa;
+ EAttachment *attachment;
+ EMailPart *first_part;
+ const gchar *snoop_mime_type;
+ GQueue *extensions;
+ CamelContentType *ct;
+ gchar *mime_type;
+ CamelDataWrapper *dw;
+ GByteArray *ba;
+ gsize size;
+ gint part_id_len;
+
+ ct = camel_mime_part_get_content_type (part);
+ extensions = NULL;
+ snoop_mime_type = NULL;
+ if (ct) {
+ EMailExtensionRegistry *reg;
+ mime_type = camel_content_type_simple (ct);
+
+ reg = e_mail_parser_get_extension_registry (parser);
+ extensions = e_mail_extension_registry_get_for_mime_type (
+ reg, mime_type);
+
+ if (camel_content_type_is (ct, "text", "*") ||
+ camel_content_type_is (ct, "message", "*"))
+ snoop_mime_type = mime_type;
+ else
+ g_free (mime_type);
+ }
+
+ if (!snoop_mime_type)
+ snoop_mime_type = e_mail_part_snoop_type (part);
+
+ if (!extensions) {
+ EMailExtensionRegistry *reg;
+
+ reg = e_mail_parser_get_extension_registry (parser);
+ extensions = e_mail_extension_registry_get_for_mime_type (
+ reg, snoop_mime_type);
+
+ if (!extensions) {
+ extensions = e_mail_extension_registry_get_fallback (
+ reg, snoop_mime_type);
+ }
+ }
+
+ part_id_len = part_id->len;
+ g_string_append (part_id, ".attachment");
+
+ empa = e_mail_part_attachment_new (part, part_id->str);
+ empa->shown = extensions && (!g_queue_is_empty (extensions) &&
+ e_mail_part_is_inline (part, extensions));
+ empa->snoop_mime_type = snoop_mime_type;
+
+ first_part = g_queue_peek_head (parts_queue);
+ if (first_part != NULL) {
+ const gchar *id = e_mail_part_get_id (first_part);
+ empa->attachment_view_part_id = g_strdup (id);
+ first_part->is_hidden = TRUE;
+ }
+
+ attachment = e_mail_part_attachment_ref_attachment (empa);
+
+ e_attachment_set_shown (attachment, empa->shown);
+ e_attachment_set_can_show (
+ attachment,
+ extensions && !g_queue_is_empty (extensions));
+
+ /* Try to guess size of the attachments */
+ dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+ ba = camel_data_wrapper_get_byte_array (dw);
+ if (ba) {
+ size = ba->len;
+
+ if (camel_mime_part_get_encoding (part) == CAMEL_TRANSFER_ENCODING_BASE64)
+ size = size / 1.37;
+ } else {
+ size = 0;
+ }
+
+ /* e_attachment_load_async must be called from main thread */
+ /* Prioritize ahead of GTK+ redraws. */
+ g_idle_add_full (
+ G_PRIORITY_HIGH_IDLE,
+ (GSourceFunc) load_attachment_idle,
+ g_object_ref (attachment),
+ NULL);
+
+ if (size != 0) {
+ GFileInfo *file_info;
+
+ file_info = e_attachment_ref_file_info (attachment);
+
+ if (file_info == NULL) {
+ file_info = g_file_info_new ();
+ g_file_info_set_content_type (
+ file_info, empa->snoop_mime_type);
+ }
+
+ g_file_info_set_size (file_info, size);
+ e_attachment_set_file_info (attachment, file_info);
+
+ g_object_unref (file_info);
+ }
+
+ g_object_unref (attachment);
+
+ g_string_truncate (part_id, part_id_len);
+
+ /* Push to head, not tail. */
+ g_queue_push_head (parts_queue, empa);
+}
+
+CamelSession *
+e_mail_parser_get_session (EMailParser *parser)
+{
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+
+ return parser->priv->session;
+}
+
+EMailExtensionRegistry *
+e_mail_parser_get_extension_registry (EMailParser *parser)
+{
+ EMailParserClass *parser_class;
+
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+
+ parser_class = E_MAIL_PARSER_GET_CLASS (parser);
+ return E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry);
+}
diff --git a/em-format/e-mail-parser.h b/em-format/e-mail-parser.h
new file mode 100644
index 0000000000..77818b86e6
--- /dev/null
+++ b/em-format/e-mail-parser.h
@@ -0,0 +1,115 @@
+/*
+ * e-mail-parser.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PARSER_H_
+#define E_MAIL_PARSER_H_
+
+#include <em-format/e-mail-part-list.h>
+#include <em-format/e-mail-extension-registry.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PARSER \
+ (e_mail_parser_get_type ())
+#define E_MAIL_PARSER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PARSER, EMailParser))
+#define E_MAIL_PARSER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PARSER, EMailParserClass))
+#define E_IS_MAIL_PARSER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PARSER))
+#define E_IS_MAIL_PARSER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PARSER))
+#define E_MAIL_PARSER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PARSER, EMailParserClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailParser EMailParser;
+typedef struct _EMailParserClass EMailParserClass;
+typedef struct _EMailParserPrivate EMailParserPrivate;
+
+struct _EMailParser {
+ GObject parent;
+ EMailParserPrivate *priv;
+};
+
+struct _EMailParserClass {
+ GObjectClass parent_class;
+
+ EMailParserExtensionRegistry *extension_registry;
+};
+
+GType e_mail_parser_get_type (void);
+
+EMailParser * e_mail_parser_new (CamelSession *session);
+
+EMailPartList * e_mail_parser_parse_sync (EMailParser *parser,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ GCancellable *cancellable);
+
+void e_mail_parser_parse (EMailParser *parser,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ GAsyncReadyCallback callback,
+ GCancellable *cancellable,
+ gpointer user_data);
+
+EMailPartList * e_mail_parser_parse_finish (EMailParser *parser,
+ GAsyncResult *result,
+ GError **error);
+
+gboolean e_mail_parser_parse_part (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts);
+
+gboolean e_mail_parser_parse_part_as (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ const gchar *mime_type,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts);
+
+void e_mail_parser_error (EMailParser *parser,
+ GQueue *out_mail_parts,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (3, 4);
+
+void e_mail_parser_wrap_as_attachment
+ (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GQueue *parts_queue);
+
+CamelSession * e_mail_parser_get_session (EMailParser *parser);
+
+EMailExtensionRegistry *
+ e_mail_parser_get_extension_registry
+ (EMailParser *parser);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PARSER_H_ */
diff --git a/em-format/e-mail-part-attachment-bar.c b/em-format/e-mail-part-attachment-bar.c
new file mode 100644
index 0000000000..5cebd9b8dc
--- /dev/null
+++ b/em-format/e-mail-part-attachment-bar.c
@@ -0,0 +1,89 @@
+/*
+ * e-mail-part-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-attachment-bar.h"
+
+#define E_MAIL_PART_ATTACHMENT_BAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PART_ATTACHMENT_BAR, EMailPartAttachmentBarPrivate))
+
+struct _EMailPartAttachmentBarPrivate {
+ EAttachmentStore *store;
+};
+
+G_DEFINE_TYPE (
+ EMailPartAttachmentBar,
+ e_mail_part_attachment_bar,
+ E_TYPE_MAIL_PART)
+
+static void
+mail_part_attachment_bar_dispose (GObject *object)
+{
+ EMailPartAttachmentBarPrivate *priv;
+
+ priv = E_MAIL_PART_ATTACHMENT_BAR_GET_PRIVATE (object);
+
+ g_clear_object (&priv->store);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_part_attachment_bar_parent_class)->
+ dispose (object);
+}
+
+static void
+e_mail_part_attachment_bar_class_init (EMailPartAttachmentBarClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (
+ class, sizeof (EMailPartAttachmentBarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = mail_part_attachment_bar_dispose;
+}
+
+static void
+e_mail_part_attachment_bar_init (EMailPartAttachmentBar *part)
+{
+ GtkTreeModel *tree_model;
+
+ part->priv = E_MAIL_PART_ATTACHMENT_BAR_GET_PRIVATE (part);
+
+ tree_model = e_attachment_store_new ();
+ part->priv->store = E_ATTACHMENT_STORE (tree_model);
+}
+
+EMailPart *
+e_mail_part_attachment_bar_new (CamelMimePart *mime_part,
+ const gchar *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART_ATTACHMENT_BAR,
+ "id", id, "mime-part", mime_part, NULL);
+}
+
+EAttachmentStore *
+e_mail_part_attachment_bar_get_store (EMailPartAttachmentBar *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT_BAR (part), NULL);
+
+ return part->priv->store;
+}
+
diff --git a/em-format/e-mail-part-attachment-bar.h b/em-format/e-mail-part-attachment-bar.h
new file mode 100644
index 0000000000..ca9f93185b
--- /dev/null
+++ b/em-format/e-mail-part-attachment-bar.h
@@ -0,0 +1,71 @@
+/*
+ * e-mail-part-attachment-bar.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_ATTACHMENT_BAR_H
+#define E_MAIL_PART_ATTACHMENT_BAR_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_ATTACHMENT_BAR \
+ (e_mail_part_attachment_bar_get_type ())
+#define E_MAIL_PART_ATTACHMENT_BAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PART_ATTACHMENT_BAR, EMailPartAttachmentBar))
+#define E_MAIL_PART_ATTACHMENT_BAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PART_ATTACHMENT_BAR, EMailPartAttachmentBarClass))
+#define E_IS_MAIL_PART_ATTACHMENT_BAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PART_ATTACHMENT_BAR))
+#define E_IS_MAIL_PART_ATTACHMENT_BAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PART_ATTACHMENT_BAR))
+#define E_MAIL_PART_ATTACHMENT_BAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PART_ATTACHMENT_BAR, EMailPartAttachmentBarClass))
+
+#define E_MAIL_PART_ATTACHMENT_BAR_MIME_TYPE \
+ "application/vnd.evolution.widget.attachment-bar"
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartAttachmentBar EMailPartAttachmentBar;
+typedef struct _EMailPartAttachmentBarClass EMailPartAttachmentBarClass;
+typedef struct _EMailPartAttachmentBarPrivate EMailPartAttachmentBarPrivate;
+
+struct _EMailPartAttachmentBar {
+ EMailPart parent;
+ EMailPartAttachmentBarPrivate *priv;
+};
+
+struct _EMailPartAttachmentBarClass {
+ EMailPartClass parent_class;
+};
+
+GType e_mail_part_attachment_bar_get_type
+ (void) G_GNUC_CONST;
+EMailPart * e_mail_part_attachment_bar_new (CamelMimePart *mime_part,
+ const gchar *id);
+EAttachmentStore *
+ e_mail_part_attachment_bar_get_store
+ (EMailPartAttachmentBar *part);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_ATTACHMENT_BAR_H */
diff --git a/em-format/e-mail-part-attachment.c b/em-format/e-mail-part-attachment.c
new file mode 100644
index 0000000000..df81357bed
--- /dev/null
+++ b/em-format/e-mail-part-attachment.c
@@ -0,0 +1,170 @@
+/*
+ * e-mail-part-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-attachment.h"
+
+#define E_MAIL_PART_ATTACHMENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PART_ATTACHMENT, EMailPartAttachmentPrivate))
+
+struct _EMailPartAttachmentPrivate {
+ EAttachment *attachment;
+};
+
+enum {
+ PROP_0,
+ PROP_ATTACHMENT
+};
+
+G_DEFINE_TYPE (
+ EMailPartAttachment,
+ e_mail_part_attachment,
+ E_TYPE_MAIL_PART)
+
+static void
+mail_part_attachment_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ATTACHMENT:
+ g_value_take_object (
+ value,
+ e_mail_part_attachment_ref_attachment (
+ E_MAIL_PART_ATTACHMENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_attachment_dispose (GObject *object)
+{
+ EMailPartAttachmentPrivate *priv;
+
+ priv = E_MAIL_PART_ATTACHMENT_GET_PRIVATE (object);
+
+ g_clear_object (&priv->attachment);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_part_attachment_parent_class)->
+ dispose (object);
+}
+
+static void
+mail_part_attachment_finalize (GObject *object)
+{
+ EMailPartAttachment *part = E_MAIL_PART_ATTACHMENT (object);
+
+ g_free (part->attachment_view_part_id);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_part_attachment_parent_class)->
+ finalize (object);
+}
+
+static void
+mail_part_attachment_constructed (GObject *object)
+{
+ EMailPartAttachmentPrivate *priv;
+ CamelMimePart *mime_part;
+ EAttachment *attachment;
+ EMailPart *part;
+ const gchar *cid;
+
+ part = E_MAIL_PART (object);
+ priv = E_MAIL_PART_ATTACHMENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_part_attachment_parent_class)->
+ constructed (object);
+
+ e_mail_part_set_mime_type (part, E_MAIL_PART_ATTACHMENT_MIME_TYPE);
+ e_mail_part_set_is_attachment (part, TRUE);
+
+ mime_part = e_mail_part_ref_mime_part (part);
+
+ cid = camel_mime_part_get_content_id (mime_part);
+ if (cid != NULL) {
+ gchar *cid_uri;
+
+ cid_uri = g_strconcat ("cid:", cid, NULL);
+ e_mail_part_set_cid (part, cid_uri);
+ g_free (cid_uri);
+ }
+
+ attachment = e_attachment_new ();
+ e_attachment_set_mime_part (attachment, mime_part);
+ priv->attachment = g_object_ref (attachment);
+ g_object_unref (attachment);
+
+ g_object_unref (mime_part);
+}
+
+static void
+e_mail_part_attachment_class_init (EMailPartAttachmentClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EMailPartAttachmentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = mail_part_attachment_get_property;
+ object_class->dispose = mail_part_attachment_dispose;
+ object_class->finalize = mail_part_attachment_finalize;
+ object_class->constructed = mail_part_attachment_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ATTACHMENT,
+ g_param_spec_object (
+ "attachment",
+ "Attachment",
+ "The attachment object",
+ E_TYPE_ATTACHMENT,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_mail_part_attachment_init (EMailPartAttachment *part)
+{
+ part->priv = E_MAIL_PART_ATTACHMENT_GET_PRIVATE (part);
+}
+
+EMailPartAttachment *
+e_mail_part_attachment_new (CamelMimePart *mime_part,
+ const gchar *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART_ATTACHMENT,
+ "id", id, "mime-part", mime_part, NULL);
+}
+
+EAttachment *
+e_mail_part_attachment_ref_attachment (EMailPartAttachment *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT (part), NULL);
+
+ return g_object_ref (part->priv->attachment);
+}
+
diff --git a/em-format/e-mail-part-attachment.h b/em-format/e-mail-part-attachment.h
new file mode 100644
index 0000000000..5c9fd617b0
--- /dev/null
+++ b/em-format/e-mail-part-attachment.h
@@ -0,0 +1,75 @@
+/*
+ * e-mail-part-attachment.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_ATTACHMENT_H
+#define E_MAIL_PART_ATTACHMENT_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_ATTACHMENT \
+ (e_mail_part_attachment_get_type ())
+#define E_MAIL_PART_ATTACHMENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PART_ATTACHMENT, EMailPartAttachment))
+#define E_MAIL_PART_ATTACHMENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PART_ATTACHMENT, EMailPartAttachmentClass))
+#define E_IS_MAIL_PART_ATTACHMENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PART_ATTACHMENT))
+#define E_IS_MAIL_PART_ATTACHMENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PART_ATTACHMENT))
+#define E_MAIL_PART_ATTACHMENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PART_ATTACHMENT, EMailPartAttachmentClass))
+
+#define E_MAIL_PART_ATTACHMENT_MIME_TYPE \
+ "application/vnd.evolution.attachment"
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartAttachment EMailPartAttachment;
+typedef struct _EMailPartAttachmentClass EMailPartAttachmentClass;
+typedef struct _EMailPartAttachmentPrivate EMailPartAttachmentPrivate;
+
+struct _EMailPartAttachment {
+ EMailPart parent;
+ EMailPartAttachmentPrivate *priv;
+
+ gchar *attachment_view_part_id;
+
+ gboolean shown;
+ const gchar *snoop_mime_type;
+};
+
+struct _EMailPartAttachmentClass {
+ EMailPartClass parent_class;
+};
+
+GType e_mail_part_attachment_get_type (void) G_GNUC_CONST;
+EMailPartAttachment *
+ e_mail_part_attachment_new (CamelMimePart *mime_part,
+ const gchar *id);
+EAttachment * e_mail_part_attachment_ref_attachment
+ (EMailPartAttachment *part);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_ATTACHMENT_H */
diff --git a/em-format/e-mail-part-headers.c b/em-format/e-mail-part-headers.c
new file mode 100644
index 0000000000..9087e8e60d
--- /dev/null
+++ b/em-format/e-mail-part-headers.c
@@ -0,0 +1,382 @@
+/*
+ * e-mail-part-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-headers.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-mail-part-list.h"
+
+#define E_MAIL_PART_HEADERS_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PART_HEADERS, EMailPartHeadersPrivate))
+
+struct _EMailPartHeadersPrivate {
+ GMutex property_lock;
+ gchar **default_headers;
+ GtkTreeModel *print_model;
+};
+
+enum {
+ PROP_0,
+ PROP_DEFAULT_HEADERS
+};
+
+G_DEFINE_TYPE (
+ EMailPartHeaders,
+ e_mail_part_headers,
+ E_TYPE_MAIL_PART)
+
+static const gchar *basic_headers[] = {
+ N_("From"),
+ N_("Reply-To"),
+ N_("To"),
+ N_("Cc"),
+ N_("Bcc"),
+ N_("Subject"),
+ N_("Date"),
+ N_("Newsgroups"),
+ N_("Face"),
+ NULL
+};
+
+static GtkTreeModel *
+mail_part_headers_build_print_model (EMailPartHeaders *part)
+{
+ GtkListStore *list_store;
+ EMailPartList *part_list;
+ CamelMimeMessage *message;
+ GArray *array;
+ gint default_position = 0;
+ guint ii, length = 0;
+
+ /* If the part list is NULL, it means the function was called
+ * too early. The part must be added to a part list first so
+ * we have access to the CamelMimeMessage. */
+ part_list = e_mail_part_ref_part_list (E_MAIL_PART (part));
+ g_return_val_if_fail (part_list != NULL, NULL);
+
+ list_store = gtk_list_store_new (
+ E_MAIL_PART_HEADERS_PRINT_MODEL_NUM_COLUMNS,
+ G_TYPE_BOOLEAN, /* INCLUDE */
+ G_TYPE_STRING, /* HEADER_NAME */
+ G_TYPE_STRING); /* HEADER_VALUE */
+
+ message = e_mail_part_list_get_message (part_list);
+ array = camel_medium_get_headers (CAMEL_MEDIUM (message));
+
+ if (array != NULL)
+ length = array->len;
+
+ for (ii = 0; ii < length; ii++) {
+ CamelMediumHeader *header;
+ GtkTreeIter iter;
+ gboolean include = FALSE;
+ gint position = -1;
+
+ header = &g_array_index (array, CamelMediumHeader, ii);
+
+ /* EMailFormatterPrintHeaders excludes "Subject" from
+ * its header table (because it puts it in an <h1> tag
+ * at the top of the page), so we'll exclude it too. */
+ if (g_ascii_strncasecmp (header->name, "Subject", 7) == 0)
+ continue;
+
+ /* Arrange default headers first and select them to be
+ * included in the final printout. All other headers
+ * are excluded by default in the final printout. */
+ if (e_mail_part_headers_is_default (part, header->name)) {
+ position = default_position++;
+ include = TRUE;
+ }
+
+ gtk_list_store_insert (list_store, &iter, position);
+
+ gtk_list_store_set (
+ list_store, &iter,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_INCLUDE,
+ include,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_HEADER_NAME,
+ header->name,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_HEADER_VALUE,
+ header->value,
+ -1);
+ }
+
+ if (array != NULL)
+ camel_medium_free_headers (CAMEL_MEDIUM (message), array);
+
+ g_object_unref (part_list);
+
+ /* Stash the print model internally. */
+
+ g_mutex_lock (&part->priv->property_lock);
+
+ g_clear_object (&part->priv->print_model);
+ part->priv->print_model = g_object_ref (list_store);
+
+ g_mutex_unlock (&part->priv->property_lock);
+
+ return GTK_TREE_MODEL (list_store);
+}
+
+static void
+mail_part_headers_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_DEFAULT_HEADERS:
+ e_mail_part_headers_set_default_headers (
+ E_MAIL_PART_HEADERS (object),
+ g_value_get_boxed (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_headers_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_DEFAULT_HEADERS:
+ g_value_take_boxed (
+ value,
+ e_mail_part_headers_dup_default_headers (
+ E_MAIL_PART_HEADERS (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_headers_dispose (GObject *object)
+{
+ EMailPartHeadersPrivate *priv;
+
+ priv = E_MAIL_PART_HEADERS_GET_PRIVATE (object);
+
+ g_clear_object (&priv->print_model);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_part_headers_parent_class)->dispose (object);
+}
+
+static void
+mail_part_headers_finalize (GObject *object)
+{
+ EMailPartHeadersPrivate *priv;
+
+ priv = E_MAIL_PART_HEADERS_GET_PRIVATE (object);
+
+ g_mutex_clear (&priv->property_lock);
+
+ g_strfreev (priv->default_headers);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_part_headers_parent_class)->finalize (object);
+}
+
+static void
+mail_part_headers_constructed (GObject *object)
+{
+ EMailPart *part;
+
+ part = E_MAIL_PART (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_part_headers_parent_class)->
+ constructed (object);
+
+ e_mail_part_set_mime_type (part, E_MAIL_PART_HEADERS_MIME_TYPE);
+}
+
+static void
+mail_part_headers_bind_dom_element (EMailPart *part,
+ WebKitDOMElement *element)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *photo;
+ gchar *addr, *uri;
+
+ document = webkit_dom_node_get_owner_document (
+ WEBKIT_DOM_NODE (element));
+ photo = webkit_dom_document_get_element_by_id (
+ document, "__evo-contact-photo");
+
+ /* Contact photos disabled, the <img> tag is not there. */
+ if (photo == NULL)
+ return;
+
+ addr = webkit_dom_element_get_attribute (photo, "data-mailaddr");
+ uri = g_strdup_printf ("mail://contact-photo?mailaddr=%s", addr);
+
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (photo), uri);
+
+ g_free (addr);
+ g_free (uri);
+}
+
+static void
+e_mail_part_headers_class_init (EMailPartHeadersClass *class)
+{
+ GObjectClass *object_class;
+ EMailPartClass *mail_part_class;
+
+ g_type_class_add_private (class, sizeof (EMailPartHeadersPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_part_headers_set_property;
+ object_class->get_property = mail_part_headers_get_property;
+ object_class->dispose = mail_part_headers_dispose;
+ object_class->finalize = mail_part_headers_finalize;
+ object_class->constructed = mail_part_headers_constructed;
+
+ mail_part_class = E_MAIL_PART_CLASS (class);
+ mail_part_class->bind_dom_element = mail_part_headers_bind_dom_element;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DEFAULT_HEADERS,
+ g_param_spec_boxed (
+ "default-headers",
+ "Default Headers",
+ "Headers to display by default",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_mail_part_headers_init (EMailPartHeaders *part)
+{
+ part->priv = E_MAIL_PART_HEADERS_GET_PRIVATE (part);
+
+ g_mutex_init (&part->priv->property_lock);
+}
+
+EMailPart *
+e_mail_part_headers_new (CamelMimePart *mime_part,
+ const gchar *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART_HEADERS,
+ "id", id, "mime-part", mime_part, NULL);
+}
+
+gchar **
+e_mail_part_headers_dup_default_headers (EMailPartHeaders *part)
+{
+ gchar **default_headers;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_HEADERS (part), NULL);
+
+ g_mutex_lock (&part->priv->property_lock);
+
+ default_headers = g_strdupv (part->priv->default_headers);
+
+ g_mutex_unlock (&part->priv->property_lock);
+
+ return default_headers;
+}
+
+void
+e_mail_part_headers_set_default_headers (EMailPartHeaders *part,
+ const gchar * const *default_headers)
+{
+ g_return_if_fail (E_IS_MAIL_PART_HEADERS (part));
+
+ if (default_headers == NULL)
+ default_headers = basic_headers;
+
+ g_mutex_lock (&part->priv->property_lock);
+
+ g_strfreev (part->priv->default_headers);
+ part->priv->default_headers = g_strdupv ((gchar **) default_headers);
+
+ g_mutex_unlock (&part->priv->property_lock);
+
+ g_object_notify (G_OBJECT (part), "default-headers");
+}
+
+gboolean
+e_mail_part_headers_is_default (EMailPartHeaders *part,
+ const gchar *header_name)
+{
+ gboolean is_default = FALSE;
+ guint ii, length = 0;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_HEADERS (part), FALSE);
+ g_return_val_if_fail (header_name != NULL, FALSE);
+
+ g_mutex_lock (&part->priv->property_lock);
+
+ if (part->priv->default_headers != NULL)
+ length = g_strv_length (part->priv->default_headers);
+
+ for (ii = 0; ii < length; ii++) {
+ const gchar *candidate;
+
+ /* g_strv_length() stops on the first NULL pointer,
+ * so we don't have to worry about this being NULL. */
+ candidate = part->priv->default_headers[ii];
+
+ if (g_ascii_strcasecmp (header_name, candidate) == 0) {
+ is_default = TRUE;
+ break;
+ }
+ }
+
+ g_mutex_unlock (&part->priv->property_lock);
+
+ return is_default;
+}
+
+GtkTreeModel *
+e_mail_part_headers_ref_print_model (EMailPartHeaders *part)
+{
+ GtkTreeModel *print_model = NULL;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_HEADERS (part), NULL);
+
+ g_mutex_lock (&part->priv->property_lock);
+
+ if (part->priv->print_model != NULL)
+ print_model = g_object_ref (part->priv->print_model);
+
+ g_mutex_unlock (&part->priv->property_lock);
+
+ if (print_model == NULL) {
+ /* The print model is built once on demand. */
+ print_model = mail_part_headers_build_print_model (part);
+ }
+
+ return print_model;
+}
+
diff --git a/em-format/e-mail-part-headers.h b/em-format/e-mail-part-headers.h
new file mode 100644
index 0000000000..c7da98f6b4
--- /dev/null
+++ b/em-format/e-mail-part-headers.h
@@ -0,0 +1,84 @@
+/*
+ * e-mail-part-headers.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_HEADERS_H
+#define E_MAIL_PART_HEADERS_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_HEADERS \
+ (e_mail_part_headers_get_type ())
+#define E_MAIL_PART_HEADERS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PART_HEADERS, EMailPartHeaders))
+#define E_MAIL_PART_HEADERS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PART_HEADERS, EMailPartHeadersClass))
+#define E_IS_MAIL_PART_HEADERS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PART_HEADERS))
+#define E_IS_MAIL_PART_HEADERS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PART_HEADERS))
+#define E_MAIL_PART_HEADERS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PART_HEADERS, EMailPartHeadersClass))
+
+#define E_MAIL_PART_HEADERS_MIME_TYPE \
+ "application/vnd.evolution.headers"
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartHeaders EMailPartHeaders;
+typedef struct _EMailPartHeadersClass EMailPartHeadersClass;
+typedef struct _EMailPartHeadersPrivate EMailPartHeadersPrivate;
+
+struct _EMailPartHeaders {
+ EMailPart parent;
+ EMailPartHeadersPrivate *priv;
+};
+
+struct _EMailPartHeadersClass {
+ EMailPartClass parent_class;
+};
+
+typedef enum {
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_INCLUDE,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_HEADER_NAME,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_HEADER_VALUE,
+ E_MAIL_PART_HEADERS_PRINT_MODEL_NUM_COLUMNS
+} EMailPartHeadersPrintModelColumns;
+
+GType e_mail_part_headers_get_type (void) G_GNUC_CONST;
+EMailPart * e_mail_part_headers_new (CamelMimePart *mime_part,
+ const gchar *id);
+gchar ** e_mail_part_headers_dup_default_headers
+ (EMailPartHeaders *part);
+void e_mail_part_headers_set_default_headers
+ (EMailPartHeaders *part,
+ const gchar * const *default_headers);
+gboolean e_mail_part_headers_is_default (EMailPartHeaders *part,
+ const gchar *header_name);
+GtkTreeModel * e_mail_part_headers_ref_print_model
+ (EMailPartHeaders *part);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_HEADERS_H */
+
diff --git a/em-format/e-mail-part-image.c b/em-format/e-mail-part-image.c
new file mode 100644
index 0000000000..2a70fe98b6
--- /dev/null
+++ b/em-format/e-mail-part-image.c
@@ -0,0 +1,100 @@
+/*
+ * e-mail-part-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-image.h"
+
+G_DEFINE_TYPE (
+ EMailPartImage,
+ e_mail_part_image,
+ E_TYPE_MAIL_PART)
+
+static void
+mail_part_image_constructed (GObject *object)
+{
+ EMailPart *part;
+ CamelMimePart *mime_part;
+ CamelContentType *content_type;
+ const gchar *content_id;
+ const gchar *disposition;
+
+ part = E_MAIL_PART (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_part_image_parent_class)->constructed (object);
+
+ e_mail_part_set_is_attachment (part, TRUE);
+
+ mime_part = e_mail_part_ref_mime_part (part);
+
+ content_id = camel_mime_part_get_content_id (mime_part);
+ content_type = camel_mime_part_get_content_type (mime_part);
+ disposition = camel_mime_part_get_disposition (mime_part);
+
+ if (content_id != NULL) {
+ gchar *cid;
+
+ cid = g_strconcat ("cid:", content_id, NULL);
+ e_mail_part_set_cid (part, cid);
+ g_free (cid);
+ }
+
+ if (content_type != NULL) {
+ gchar *mime_type;
+
+ mime_type = camel_content_type_simple (content_type);
+ e_mail_part_set_mime_type (part, mime_type);
+ g_free (mime_type);
+ } else {
+ e_mail_part_set_mime_type (part, "image/*");
+ }
+
+ if (disposition == NULL)
+ disposition = "inline";
+
+ part->is_hidden =
+ (content_id != NULL) &&
+ (g_ascii_strcasecmp (disposition, "attachment") != 0);
+
+ g_object_unref (mime_part);
+}
+
+static void
+e_mail_part_image_class_init (EMailPartImageClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = mail_part_image_constructed;
+}
+
+static void
+e_mail_part_image_init (EMailPartImage *part)
+{
+}
+
+EMailPart *
+e_mail_part_image_new (CamelMimePart *mime_part,
+ const gchar *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART_IMAGE,
+ "id", id, "mime-part", mime_part, NULL);
+}
+
diff --git a/em-format/e-mail-part-image.h b/em-format/e-mail-part-image.h
new file mode 100644
index 0000000000..0c3e7f437d
--- /dev/null
+++ b/em-format/e-mail-part-image.h
@@ -0,0 +1,65 @@
+/*
+ * e-mail-part-image.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_IMAGE_H
+#define E_MAIL_PART_IMAGE_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_IMAGE \
+ (e_mail_part_image_get_type ())
+#define E_MAIL_PART_IMAGE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PART_IMAGE, EMailPartImage))
+#define E_MAIL_PART_IMAGE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PART_IMAGE, EMailPartImageClass))
+#define E_IS_MAIL_PART_IMAGE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PART_IMAGE))
+#define E_IS_MAIL_PART_IMAGE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PART_IMAGE))
+#define E_MAIL_PART_IMAGE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PART_IMAGE, EMailPartImageClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartImage EMailPartImage;
+typedef struct _EMailPartImageClass EMailPartImageClass;
+typedef struct _EMailPartImagePrivate EMailPartImagePrivate;
+
+struct _EMailPartImage {
+ EMailPart parent;
+ EMailPartImagePrivate *priv;
+};
+
+struct _EMailPartImageClass {
+ EMailPartClass parent_class;
+};
+
+GType e_mail_part_image_get_type (void) G_GNUC_CONST;
+EMailPart * e_mail_part_image_new (CamelMimePart *mime_part,
+ const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_IMAGE_H */
+
diff --git a/em-format/e-mail-part-list.c b/em-format/e-mail-part-list.c
new file mode 100644
index 0000000000..bcf7490634
--- /dev/null
+++ b/em-format/e-mail-part-list.c
@@ -0,0 +1,417 @@
+/*
+ * e-mail-part-list.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <camel/camel.h>
+
+#include "e-mail-part-list.h"
+
+#define E_MAIL_PART_LIST_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PART_LIST, EMailPartListPrivate))
+
+struct _EMailPartListPrivate {
+ CamelFolder *folder;
+ CamelMimeMessage *message;
+ gchar *message_uid;
+
+ GQueue queue;
+ GMutex queue_lock;
+};
+
+enum {
+ PROP_0,
+ PROP_FOLDER,
+ PROP_MESSAGE,
+ PROP_MESSAGE_UID
+};
+
+G_DEFINE_TYPE (EMailPartList, e_mail_part_list, G_TYPE_OBJECT)
+
+static CamelObjectBag *registry = NULL;
+G_LOCK_DEFINE_STATIC (registry);
+
+static void
+mail_part_list_set_folder (EMailPartList *part_list,
+ CamelFolder *folder)
+{
+ g_return_if_fail (part_list->priv->folder == NULL);
+
+ /* The folder property is optional. */
+ if (folder != NULL) {
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ part_list->priv->folder = g_object_ref (folder);
+ }
+}
+
+static void
+mail_part_list_set_message (EMailPartList *part_list,
+ CamelMimeMessage *message)
+{
+ g_return_if_fail (part_list->priv->message == NULL);
+
+ /* The message property is optional. */
+ if (message != NULL) {
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+ part_list->priv->message = g_object_ref (message);
+ }
+}
+
+static void
+mail_part_list_set_message_uid (EMailPartList *part_list,
+ const gchar *message_uid)
+{
+ g_return_if_fail (part_list->priv->message_uid == NULL);
+
+ /* The message_uid property is optional. */
+ part_list->priv->message_uid = g_strdup (message_uid);
+}
+
+static void
+mail_part_list_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FOLDER:
+ mail_part_list_set_folder (
+ E_MAIL_PART_LIST (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_MESSAGE:
+ mail_part_list_set_message (
+ E_MAIL_PART_LIST (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_MESSAGE_UID:
+ mail_part_list_set_message_uid (
+ E_MAIL_PART_LIST (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_list_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FOLDER:
+ g_value_set_object (
+ value,
+ e_mail_part_list_get_folder (
+ E_MAIL_PART_LIST (object)));
+ return;
+
+ case PROP_MESSAGE:
+ g_value_set_object (
+ value,
+ e_mail_part_list_get_message (
+ E_MAIL_PART_LIST (object)));
+ return;
+
+ case PROP_MESSAGE_UID:
+ g_value_set_string (
+ value,
+ e_mail_part_list_get_message_uid (
+ E_MAIL_PART_LIST (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_list_dispose (GObject *object)
+{
+ EMailPartListPrivate *priv;
+
+ priv = E_MAIL_PART_LIST_GET_PRIVATE (object);
+
+ if (priv->folder != NULL) {
+ g_object_unref (priv->folder);
+ priv->folder = NULL;
+ }
+
+ if (priv->message != NULL) {
+ g_object_unref (priv->message);
+ priv->message = NULL;
+ }
+
+ g_mutex_lock (&priv->queue_lock);
+ while (!g_queue_is_empty (&priv->queue))
+ g_object_unref (g_queue_pop_head (&priv->queue));
+ g_mutex_unlock (&priv->queue_lock);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_part_list_parent_class)->dispose (object);
+}
+
+static void
+mail_part_list_finalize (GObject *object)
+{
+ EMailPartListPrivate *priv;
+
+ priv = E_MAIL_PART_LIST_GET_PRIVATE (object);
+
+ g_free (priv->message_uid);
+
+ g_warn_if_fail (g_queue_is_empty (&priv->queue));
+ g_mutex_clear (&priv->queue_lock);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_part_list_parent_class)->finalize (object);
+}
+
+static void
+e_mail_part_list_class_init (EMailPartListClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EMailPartListPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_part_list_set_property;
+ object_class->get_property = mail_part_list_get_property;
+ object_class->dispose = mail_part_list_dispose;
+ object_class->finalize = mail_part_list_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FOLDER,
+ g_param_spec_object (
+ "folder",
+ "Folder",
+ NULL,
+ CAMEL_TYPE_FOLDER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MESSAGE,
+ g_param_spec_object (
+ "message",
+ "Message",
+ NULL,
+ CAMEL_TYPE_MIME_MESSAGE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MESSAGE_UID,
+ g_param_spec_string (
+ "message-uid",
+ "Message UID",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_mail_part_list_init (EMailPartList *part_list)
+{
+ part_list->priv = E_MAIL_PART_LIST_GET_PRIVATE (part_list);
+
+ g_mutex_init (&part_list->priv->queue_lock);
+}
+
+EMailPartList *
+e_mail_part_list_new (CamelMimeMessage *message,
+ const gchar *message_uid,
+ CamelFolder *folder)
+{
+ if (message != NULL)
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+ if (folder != NULL)
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART_LIST,
+ "message", message,
+ "message-uid", message_uid,
+ "folder", folder, NULL);
+}
+
+CamelFolder *
+e_mail_part_list_get_folder (EMailPartList *part_list)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
+
+ return part_list->priv->folder;
+}
+
+CamelMimeMessage *
+e_mail_part_list_get_message (EMailPartList *part_list)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
+
+ return part_list->priv->message;
+}
+
+const gchar *
+e_mail_part_list_get_message_uid (EMailPartList *part_list)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
+
+ return part_list->priv->message_uid;
+}
+
+void
+e_mail_part_list_add_part (EMailPartList *part_list,
+ EMailPart *part)
+{
+ g_return_if_fail (E_IS_MAIL_PART_LIST (part_list));
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ g_mutex_lock (&part_list->priv->queue_lock);
+
+ g_queue_push_tail (
+ &part_list->priv->queue,
+ g_object_ref (part));
+
+ g_mutex_unlock (&part_list->priv->queue_lock);
+
+ e_mail_part_set_part_list (part, part_list);
+}
+
+EMailPart *
+e_mail_part_list_ref_part (EMailPartList *part_list,
+ const gchar *part_id)
+{
+ EMailPart *match = NULL;
+ GList *head, *link;
+ gboolean by_cid;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
+ g_return_val_if_fail (part_id != NULL, NULL);
+
+ by_cid = (g_ascii_strncasecmp (part_id, "cid:", 4) == 0);
+
+ g_mutex_lock (&part_list->priv->queue_lock);
+
+ head = g_queue_peek_head_link (&part_list->priv->queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *candidate = E_MAIL_PART (link->data);
+ const gchar *candidate_id;
+
+ if (by_cid)
+ candidate_id = e_mail_part_get_cid (candidate);
+ else
+ candidate_id = e_mail_part_get_id (candidate);
+
+ if (g_strcmp0 (candidate_id, part_id) == 0) {
+ match = g_object_ref (candidate);
+ break;
+ }
+ }
+
+ g_mutex_unlock (&part_list->priv->queue_lock);
+
+ return match;
+}
+
+/**
+ * e_mail_part_list_queue_parts:
+ * @part_list: an #EMailPartList
+ * @part_id: the #EMailPart ID to begin queueing from, or %NULL
+ * @result_queue: a #GQueue in which to deposit #EMailPart instances
+ *
+ * Populates @result_queue with a sequence of #EMailPart instances beginning
+ * with the part having @part_id. If @part_id is %NULL, the entire sequence
+ * of #EMailPart instances is queued.
+ *
+ * Each #EMailPart is referenced for thread-safety and should be unreferenced
+ * with g_object_unref().
+ *
+ * Returns: the number of parts added to @result_queue
+ **/
+guint
+e_mail_part_list_queue_parts (EMailPartList *part_list,
+ const gchar *part_id,
+ GQueue *result_queue)
+{
+ GList *link;
+ guint parts_queued = 0;
+
+ g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), FALSE);
+ g_return_val_if_fail (result_queue != NULL, FALSE);
+
+ g_mutex_lock (&part_list->priv->queue_lock);
+
+ link = g_queue_peek_head_link (&part_list->priv->queue);
+
+ if (part_id != NULL) {
+ for (; link != NULL; link = g_list_next (link)) {
+ EMailPart *candidate = E_MAIL_PART (link->data);
+ const gchar *candidate_id;
+
+ candidate_id = e_mail_part_get_id (candidate);
+
+ if (g_strcmp0 (candidate_id, part_id) == 0)
+ break;
+ }
+ }
+
+ /* We skip the loop entirely if link is NULL. */
+ for (; link != NULL; link = g_list_next (link)) {
+ EMailPart *part = link->data;
+
+ if (part == NULL)
+ continue;
+
+ g_queue_push_tail (result_queue, g_object_ref (part));
+ parts_queued++;
+ }
+
+ g_mutex_unlock (&part_list->priv->queue_lock);
+
+ return parts_queued;
+}
+
+/**
+ * e_mail_part_list_get_registry:
+ *
+ * Returns a #CamelObjectBag where parsed #EMailPartLists can be stored.
+ */
+CamelObjectBag *
+e_mail_part_list_get_registry (void)
+{
+ G_LOCK (registry);
+ if (registry == NULL) {
+ registry = camel_object_bag_new (
+ g_str_hash, g_str_equal,
+ (CamelCopyFunc) g_strdup, g_free);
+ }
+ G_UNLOCK (registry);
+
+ return registry;
+}
diff --git a/em-format/e-mail-part-list.h b/em-format/e-mail-part-list.h
new file mode 100644
index 0000000000..3694075100
--- /dev/null
+++ b/em-format/e-mail-part-list.h
@@ -0,0 +1,81 @@
+/*
+ * e-mail-part-list.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_LIST_H
+#define E_MAIL_PART_LIST_H
+
+#include <camel/camel.h>
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_LIST \
+ (e_mail_part_list_get_type ())
+#define E_MAIL_PART_LIST(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PART_LIST, EMailPartList))
+#define E_MAIL_PART_LIST_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PART_LIST, EMailPartListClass))
+#define E_IS_MAIL_PART_LIST(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PART_LIST))
+#define E_IS_MAIL_PART_LIST_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PART_LIST))
+#define E_MAIL_PART_LIST_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PART_LIST, EMailPartListClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartList EMailPartList;
+typedef struct _EMailPartListClass EMailPartListClass;
+typedef struct _EMailPartListPrivate EMailPartListPrivate;
+
+struct _EMailPartList {
+ GObject parent;
+ EMailPartListPrivate *priv;
+};
+
+struct _EMailPartListClass {
+ GObjectClass parent_class;
+};
+
+GType e_mail_part_list_get_type (void) G_GNUC_CONST;
+EMailPartList * e_mail_part_list_new (CamelMimeMessage *message,
+ const gchar *message_uid,
+ CamelFolder *folder);
+CamelFolder * e_mail_part_list_get_folder (EMailPartList *part_list);
+CamelMimeMessage *
+ e_mail_part_list_get_message (EMailPartList *part_list);
+const gchar * e_mail_part_list_get_message_uid
+ (EMailPartList *part_list);
+void e_mail_part_list_add_part (EMailPartList *part_list,
+ EMailPart *part);
+EMailPart * e_mail_part_list_ref_part (EMailPartList *part_list,
+ const gchar *part_id);
+guint e_mail_part_list_queue_parts (EMailPartList *part_list,
+ const gchar *part_id,
+ GQueue *result_queue);
+
+CamelObjectBag *
+ e_mail_part_list_get_registry (void);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_LIST_H */
diff --git a/em-format/e-mail-part-utils.c b/em-format/e-mail-part-utils.c
new file mode 100644
index 0000000000..0a24cf2ef4
--- /dev/null
+++ b/em-format/e-mail-part-utils.c
@@ -0,0 +1,582 @@
+/*
+ * e-mail-part-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include "e-mail-part-utils.h"
+#include "e-mail-parser-extension.h"
+
+#include <e-util/e-util.h>
+#include <gdk/gdk.h>
+
+#include <libsoup/soup.h>
+
+#include <string.h>
+
+#define d(x)
+
+/**
+ * e_mail_part_is_secured:
+ * @part: a #CamelMimePart
+ *
+ * Whether @part is signed or encrypted or not.
+ *
+ * Return Value: TRUE/FALSE
+ */
+gboolean
+e_mail_part_is_secured (CamelMimePart *part)
+{
+ CamelContentType *ct = camel_mime_part_get_content_type (part);
+
+ return (camel_content_type_is (ct, "multipart", "signed") ||
+ camel_content_type_is (ct, "multipart", "encrypted") ||
+ camel_content_type_is (ct, "application", "x-inlinepgp-signed") ||
+ camel_content_type_is (ct, "application", "x-inlinepgp-encrypted") ||
+ camel_content_type_is (ct, "application", "x-pkcs7-mime") ||
+ camel_content_type_is (ct, "application", "pkcs7-mime"));
+}
+
+/**
+ * e_mail_part_snoop_type:
+ * @part: a #CamelMimePart
+ *
+ * Tries to snoop the mime type of a part.
+ *
+ * Return value: %NULL if unknown (more likely application/octet-stream).
+ **/
+const gchar *
+e_mail_part_snoop_type (CamelMimePart *part)
+{
+ /* cache is here only to be able still return const gchar * */
+ static GHashTable *types_cache = NULL;
+
+ const gchar *filename;
+ gchar *name_type = NULL, *magic_type = NULL, *res, *tmp;
+ CamelDataWrapper *dw;
+
+ filename = camel_mime_part_get_filename (part);
+ if (filename != NULL)
+ name_type = e_util_guess_mime_type (filename, FALSE);
+
+ dw = camel_medium_get_content ((CamelMedium *) part);
+ if (!camel_data_wrapper_is_offline (dw)) {
+ GByteArray *byte_array;
+ CamelStream *stream;
+
+ byte_array = g_byte_array_new ();
+ stream = camel_stream_mem_new_with_byte_array (byte_array);
+
+ if (camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL) > 0) {
+ gchar *content_type;
+
+ content_type = g_content_type_guess (
+ filename, byte_array->data,
+ byte_array->len, NULL);
+
+ if (content_type != NULL)
+ magic_type = g_content_type_get_mime_type (content_type);
+
+ g_free (content_type);
+ }
+
+ g_object_unref (stream);
+ }
+
+ /* If gvfs doesn't recognize the data by magic, but it
+ * contains English words, it will call it text/plain. If the
+ * filename-based check came up with something different, use
+ * that instead and if it returns "application/octet-stream"
+ * try to do better with the filename check.
+ */
+
+ if (magic_type) {
+ if (name_type
+ && (!strcmp (magic_type, "text/plain")
+ || !strcmp (magic_type, "application/octet-stream")))
+ res = name_type;
+ else
+ res = magic_type;
+ } else
+ res = name_type;
+
+ if (res != name_type)
+ g_free (name_type);
+
+ if (res != magic_type)
+ g_free (magic_type);
+
+ if (!types_cache)
+ types_cache = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) NULL);
+
+ if (res) {
+ tmp = g_hash_table_lookup (types_cache, res);
+ if (tmp) {
+ g_free (res);
+ res = tmp;
+ } else {
+ g_hash_table_insert (types_cache, res, res);
+ }
+ }
+
+ d (printf ("Snooped mime type %s\n", res));
+ return res;
+
+ /* We used to load parts to check their type, we don't anymore,
+ * see bug #211778 for some discussion */
+}
+
+/**
+ * e_mail_part_is_attachment
+ * @part: Part to check.
+ *
+ * Returns true if the part is an attachment.
+ *
+ * A part is not considered an attachment if it is a
+ * multipart, or a text part with no filename. It is used
+ * to determine if an attachment header should be displayed for
+ * the part.
+ *
+ * Content-Disposition is not checked.
+ *
+ * Return value: TRUE/FALSE
+ **/
+gboolean
+e_mail_part_is_attachment (CamelMimePart *part)
+{
+ /*CamelContentType *ct = camel_mime_part_get_content_type(part);*/
+ CamelDataWrapper *dw = camel_medium_get_content ((CamelMedium *) part);
+
+ if (!dw)
+ return 0;
+
+ d (printf ("checking is attachment %s/%s\n", dw->mime_type->type, dw->mime_type->subtype));
+ return !(camel_content_type_is (dw->mime_type, "multipart", "*")
+ || camel_content_type_is (
+ dw->mime_type, "application", "x-pkcs7-mime")
+ || camel_content_type_is (
+ dw->mime_type, "application", "pkcs7-mime")
+ || camel_content_type_is (
+ dw->mime_type, "application", "x-inlinepgp-signed")
+ || camel_content_type_is (
+ dw->mime_type, "application", "x-inlinepgp-encrypted")
+ || camel_content_type_is (
+ dw->mime_type, "x-evolution", "evolution-rss-feed")
+ || camel_content_type_is (dw->mime_type, "text", "calendar")
+ || camel_content_type_is (dw->mime_type, "text", "x-calendar")
+ || (camel_content_type_is (dw->mime_type, "text", "*")
+ && camel_mime_part_get_filename (part) == NULL));
+}
+
+/**
+ * e_mail_part_preserve_charset_in_content_type:
+ * @ipart: Source #CamelMimePart
+ * @opart: Target #CamelMimePart
+ *
+ * Copies 'charset' part of content-type header from @ipart to @opart.
+ */
+void
+e_mail_part_preserve_charset_in_content_type (CamelMimePart *ipart,
+ CamelMimePart *opart)
+{
+ CamelDataWrapper *data_wrapper;
+ CamelContentType *content_type;
+ const gchar *charset;
+
+ g_return_if_fail (ipart != NULL);
+ g_return_if_fail (opart != NULL);
+
+ data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (ipart));
+ content_type = camel_data_wrapper_get_mime_type_field (data_wrapper);
+
+ if (content_type == NULL)
+ return;
+
+ charset = camel_content_type_param (content_type, "charset");
+
+ if (charset == NULL || *charset == '\0')
+ return;
+
+ data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (opart));
+ content_type = camel_data_wrapper_get_mime_type_field (data_wrapper);
+
+ if (content_type)
+ camel_content_type_set_param (content_type, "charset", charset);
+
+ /* update charset also on the part itself */
+ data_wrapper = CAMEL_DATA_WRAPPER (opart);
+ content_type = camel_data_wrapper_get_mime_type_field (data_wrapper);
+ if (content_type)
+ camel_content_type_set_param (content_type, "charset", charset);
+}
+
+/**
+ * e_mail_part_get_related_display_part:
+ * @part: a multipart/related or multipart/alternative #CamelMimePart
+ * @out_displayid: (out) returns index of the returned part
+ *
+ * Goes through all subparts of given @part and tries to determine which
+ * part should be displayed and which parts are just attachments to the
+ * part.
+ *
+ * Return Value: A #CamelMimePart that should be displayed
+ */
+CamelMimePart *
+e_mail_part_get_related_display_part (CamelMimePart *part,
+ gint *out_displayid)
+{
+ CamelMultipart *mp;
+ CamelMimePart *body_part, *display_part = NULL;
+ CamelContentType *content_type;
+ const gchar *start;
+ gint i, nparts, displayid = 0;
+
+ mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+ if (!CAMEL_IS_MULTIPART (mp))
+ return NULL;
+
+ nparts = camel_multipart_get_number (mp);
+ content_type = camel_mime_part_get_content_type (part);
+ start = camel_content_type_param (content_type, "start");
+ if (start && strlen (start) > 2) {
+ gint len;
+ const gchar *cid;
+
+ /* strip <>'s from CID */
+ len = strlen (start) - 2;
+ start++;
+
+ for (i = 0; i < nparts; i++) {
+ body_part = camel_multipart_get_part (mp, i);
+ cid = camel_mime_part_get_content_id (body_part);
+
+ if (cid && !strncmp (cid, start, len) && strlen (cid) == len) {
+ display_part = body_part;
+ displayid = i;
+ break;
+ }
+ }
+ } else {
+ display_part = camel_multipart_get_part (mp, 0);
+ }
+
+ if (out_displayid)
+ *out_displayid = displayid;
+
+ return display_part;
+}
+
+void
+e_mail_part_animation_extract_frame (const GByteArray *anim,
+ gchar **frame,
+ gsize *len)
+{
+ GdkPixbufLoader *loader;
+ GdkPixbufAnimation *animation;
+ GdkPixbuf *frame_buf;
+
+ /* GIF89a (GIF image signature) */
+ const gchar GIF_HEADER[] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 };
+ const gint GIF_HEADER_LEN = sizeof (GIF_HEADER);
+
+ /* NETSCAPE2.0 (extension describing animated GIF, starts on 0x310) */
+ const gchar GIF_APPEXT[] = { 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41,
+ 0x50, 0x45, 0x32, 0x2E, 0x30 };
+ const gint GIF_APPEXT_LEN = sizeof (GIF_APPEXT);
+
+ if ((anim == NULL) || (anim->data == NULL)) {
+ *frame = NULL;
+ *len = 0;
+ return;
+ }
+
+ /* Check if the image is an animated GIF. We don't care about any
+ * other animated formats (APNG or MNG) as WebKit does not support them
+ * and displays only the first frame. */
+ if ((anim->len < 0x331)
+ || (memcmp (anim->data, GIF_HEADER, GIF_HEADER_LEN) != 0)
+ || (memcmp (&anim->data[0x310], GIF_APPEXT, GIF_APPEXT_LEN) != 0)) {
+
+ *frame = g_memdup (anim->data, anim->len);
+ *len = anim->len;
+ return;
+ }
+
+ loader = gdk_pixbuf_loader_new ();
+ gdk_pixbuf_loader_write (loader, (guchar *) anim->data, anim->len, NULL);
+ gdk_pixbuf_loader_close (loader, NULL);
+ animation = gdk_pixbuf_loader_get_animation (loader);
+ if (!animation) {
+
+ *frame = g_memdup (anim->data, anim->len);
+ *len = anim->len;
+ g_object_unref (loader);
+ return;
+ }
+
+ /* Extract first frame */
+ frame_buf = gdk_pixbuf_animation_get_static_image (animation);
+ if (!frame_buf) {
+ *frame = g_memdup (anim->data, anim->len);
+ *len = anim->len;
+ g_object_unref (loader);
+ g_object_unref (animation);
+ return;
+ }
+
+ /* Unforunatelly, GdkPixbuf cannot save to GIF, but WebKit does not
+ * have any trouble displaying PNG image despite the part having
+ * image/gif mime-type */
+ gdk_pixbuf_save_to_buffer (frame_buf, frame, len, "png", NULL, NULL);
+
+ g_object_unref (loader);
+}
+
+/**
+ * e_mail_part_build_url:
+ * @folder: (allow-none) a #CamelFolder with the message or %NULL
+ * @message_uid: uid of the message within the @folder
+ * @first_param_name: Name of first query parameter followed by GType of it's value and value
+ * terminated by %NULL.
+ *
+ * Construct a URI for message.
+ *
+ * The URI can contain multiple query parameters. The list of parameters must be
+ * NULL-terminated. Each query must contain name, GType of value and value.
+ *
+ * Return Value: a URL of a message or part
+ */
+gchar *
+e_mail_part_build_uri (CamelFolder *folder,
+ const gchar *message_uid,
+ const gchar *first_param_name,
+ ...)
+{
+ CamelStore *store;
+ gchar *uri, *tmp;
+ va_list ap;
+ const gchar *name;
+ const gchar *service_uid, *folder_name;
+ gchar *encoded_message_uid;
+ gchar separator;
+
+ g_return_val_if_fail (message_uid && *message_uid, NULL);
+
+ if (!folder) {
+ folder_name = "generic";
+ service_uid = "generic";
+ } else {
+ tmp = (gchar *) camel_folder_get_full_name (folder);
+ folder_name = (const gchar *) soup_uri_encode (tmp, NULL);
+ store = camel_folder_get_parent_store (folder);
+ if (store)
+ service_uid = camel_service_get_uid (CAMEL_SERVICE (store));
+ else
+ service_uid = "generic";
+ }
+
+ encoded_message_uid = soup_uri_encode (message_uid, NULL);
+ tmp = g_strdup_printf (
+ "mail://%s/%s/%s",
+ service_uid,
+ folder_name,
+ encoded_message_uid);
+ g_free (encoded_message_uid);
+
+ if (folder) {
+ g_free ((gchar *) folder_name);
+ }
+
+ va_start (ap, first_param_name);
+ name = first_param_name;
+ separator = '?';
+ while (name) {
+ gchar *tmp2;
+ gint type = va_arg (ap, gint);
+ switch (type) {
+ case G_TYPE_INT:
+ case G_TYPE_BOOLEAN: {
+ gint val = va_arg (ap, gint);
+ tmp2 = g_strdup_printf (
+ "%s%c%s=%d", tmp,
+ separator, name, val);
+ break;
+ }
+ case G_TYPE_FLOAT:
+ case G_TYPE_DOUBLE: {
+ gdouble val = va_arg (ap, double);
+ tmp2 = g_strdup_printf (
+ "%s%c%s=%f", tmp,
+ separator, name, val);
+ break;
+ }
+ case G_TYPE_STRING: {
+ gchar *val = va_arg (ap, gchar *);
+ gchar *escaped = soup_uri_encode (val, NULL);
+ tmp2 = g_strdup_printf (
+ "%s%c%s=%s", tmp,
+ separator, name, escaped);
+ g_free (escaped);
+ break;
+ }
+ default:
+ g_warning ("Invalid param type %s", g_type_name (type));
+ va_end (ap);
+ return NULL;
+ }
+
+ g_free (tmp);
+ tmp = tmp2;
+
+ if (separator == '?')
+ separator = '&';
+
+ name = va_arg (ap, gchar *);
+ }
+ va_end (ap);
+
+ uri = tmp;
+ if (uri == NULL)
+ return NULL;
+
+ /* For some reason, webkit won't accept URL with username, but
+ * without password (mail://store@host/folder/mail), so we
+ * will replace the '@' symbol by '/' to get URL like
+ * mail://store/host/folder/mail which is OK
+ */
+ while ((tmp = strchr (uri, '@')) != NULL) {
+ tmp[0] = '/';
+ }
+
+ return uri;
+}
+
+/**
+ * e_mail_part_describe:
+ * @part: a #CamelMimePart
+ * @mime_type: MIME type of the content
+ *
+ * Generate a simple textual description of a part, @mime_type represents
+ * the content.
+ *
+ * Return value:
+ **/
+gchar *
+e_mail_part_describe (CamelMimePart *part,
+ const gchar *mime_type)
+{
+ GString *stext;
+ const gchar *filename, *description;
+ gchar *content_type, *desc;
+
+ stext = g_string_new ("");
+ content_type = g_content_type_from_mime_type (mime_type);
+ desc = g_content_type_get_description (
+ content_type != NULL ? content_type : mime_type);
+ g_free (content_type);
+ g_string_append_printf (
+ stext, _("%s attachment"), desc ? desc : mime_type);
+ g_free (desc);
+
+ filename = camel_mime_part_get_filename (part);
+ description = camel_mime_part_get_description (part);
+
+ if (!filename || !*filename) {
+ CamelDataWrapper *content;
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (part));
+
+ if (CAMEL_IS_MIME_MESSAGE (content))
+ filename = camel_mime_message_get_subject (
+ CAMEL_MIME_MESSAGE (content));
+ }
+
+ if (filename != NULL && *filename != '\0') {
+ gchar *basename = g_path_get_basename (filename);
+ g_string_append_printf (stext, " (%s)", basename);
+ g_free (basename);
+ }
+
+ if (description != NULL && *description != '\0' &&
+ g_strcmp0 (filename, description) != 0)
+ g_string_append_printf (stext, ", \"%s\"", description);
+
+ return g_string_free (stext, FALSE);
+}
+
+gboolean
+e_mail_part_is_inline (CamelMimePart *mime_part,
+ GQueue *extensions)
+{
+ const gchar *disposition;
+ EMailParserExtension *extension;
+ EMailParserExtensionClass *class;
+
+ if ((extensions == NULL) || g_queue_is_empty (extensions))
+ return FALSE;
+
+ extension = g_queue_peek_head (extensions);
+ class = E_MAIL_PARSER_EXTENSION_GET_CLASS (extension);
+
+ /* Some types need to override the disposition.
+ * e.g. application/x-pkcs7-mime */
+ if (class->flags & E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION)
+ return TRUE;
+
+ disposition = camel_mime_part_get_disposition (mime_part);
+ if (disposition != NULL)
+ return g_ascii_strcasecmp (disposition, "inline") == 0;
+
+ /* Otherwise, use the default for this handler type. */
+ return (class->flags & E_MAIL_PARSER_EXTENSION_INLINE) != 0;
+}
+
+/**
+ * e_mail_part_utils_body_refers:
+ * @body: text body to search for references in; can be %NULL, then returns %FALSE
+ * @cid: a Content-ID to search for; if found in body, it should be of form "cid:xxxxx"; can be %NULL
+ *
+ * Returns whether @body contains a reference to @cid enclosed in quotes;
+ * returns %FALSE if any of the arguments is %NULL.
+ **/
+gboolean
+e_mail_part_utils_body_refers (const gchar *body,
+ const gchar *cid)
+{
+ const gchar *ptr;
+
+ if (!body || !cid || !*cid)
+ return FALSE;
+
+ ptr = body;
+ while (ptr = strstr (ptr, cid), ptr != NULL) {
+ if (ptr - body > 1 && ptr[-1] == '\"' && ptr[strlen (cid)] == '\"')
+ return TRUE;
+
+ ptr++;
+ }
+
+ return FALSE;
+}
diff --git a/em-format/e-mail-part-utils.h b/em-format/e-mail-part-utils.h
new file mode 100644
index 0000000000..54d98e2c0c
--- /dev/null
+++ b/em-format/e-mail-part-utils.h
@@ -0,0 +1,60 @@
+/*
+ * e-mail-part-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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_UTILS_H_
+#define E_MAIL_PART_UTILS_H_
+
+#include <camel/camel.h>
+
+G_BEGIN_DECLS
+
+gboolean e_mail_part_is_secured (CamelMimePart *part);
+
+const gchar * e_mail_part_snoop_type (CamelMimePart *part);
+
+gboolean e_mail_part_is_attachment (CamelMimePart *part);
+
+void e_mail_part_preserve_charset_in_content_type
+ (CamelMimePart *ipart,
+ CamelMimePart *opart);
+
+CamelMimePart * e_mail_part_get_related_display_part
+ (CamelMimePart *part,
+ gint *out_displayid);
+
+void e_mail_part_animation_extract_frame (
+ const GByteArray *anim,
+ gchar **frame,
+ gsize *len);
+
+gchar * e_mail_part_build_uri (CamelFolder *folder,
+ const gchar *message_uid,
+ const gchar *first_param_name,
+ ...);
+
+gchar * e_mail_part_describe (CamelMimePart *part,
+ const gchar *mime_type);
+
+gboolean e_mail_part_is_inline (CamelMimePart *part,
+ GQueue *extensions);
+
+gboolean e_mail_part_utils_body_refers (const gchar *body,
+ const gchar *cid);
+G_END_DECLS
+
+#endif /* E_MAIL_PART_UTILS_H_ */
diff --git a/em-format/e-mail-part.c b/em-format/e-mail-part.c
new file mode 100644
index 0000000000..c7b07452eb
--- /dev/null
+++ b/em-format/e-mail-part.c
@@ -0,0 +1,613 @@
+/*
+ * e-mail-part.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/**
+ * EMailPart:
+ *
+ * The #EMailPart is a wrapper around #CamelMimePart which holds additional
+ * information about the mime part, like it's ID, encryption type etc.
+ *
+ * Each #EMailPart must have a unique ID. The ID is a dot-separated
+ * hierarchical description of the location of the part within the email
+ * message.
+ */
+
+#include "e-mail-part.h"
+
+#include <string.h>
+
+#include "e-mail-part-list.h"
+
+#define E_MAIL_PART_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PART, EMailPartPrivate))
+
+struct _EMailPartPrivate {
+ GWeakRef part_list;
+ CamelMimePart *mime_part;
+
+ gchar *id;
+ gchar *cid;
+ gchar *mime_type;
+
+ gboolean is_attachment;
+};
+
+enum {
+ PROP_0,
+ PROP_CID,
+ PROP_ID,
+ PROP_IS_ATTACHMENT,
+ PROP_MIME_PART,
+ PROP_MIME_TYPE,
+ PROP_PART_LIST
+};
+
+G_DEFINE_TYPE_WITH_CODE (
+ EMailPart,
+ e_mail_part,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_EXTENSIBLE, NULL))
+
+static void
+mail_part_validity_pair_free (gpointer ptr)
+{
+ EMailPartValidityPair *pair = ptr;
+
+ if (!pair)
+ return;
+
+ camel_cipher_validity_free (pair->validity);
+ g_free (pair);
+}
+
+static void
+mail_part_set_id (EMailPart *part,
+ const gchar *id)
+{
+ g_return_if_fail (part->priv->id == NULL);
+
+ part->priv->id = g_strdup (id);
+}
+
+static void
+mail_part_set_mime_part (EMailPart *part,
+ CamelMimePart *mime_part)
+{
+ g_return_if_fail (part->priv->mime_part == NULL);
+
+ /* The CamelMimePart is optional. */
+ if (mime_part != NULL)
+ part->priv->mime_part = g_object_ref (mime_part);
+}
+
+static void
+mail_part_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CID:
+ e_mail_part_set_cid (
+ E_MAIL_PART (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_ID:
+ mail_part_set_id (
+ E_MAIL_PART (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_IS_ATTACHMENT:
+ e_mail_part_set_is_attachment (
+ E_MAIL_PART (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_MIME_PART:
+ mail_part_set_mime_part (
+ E_MAIL_PART (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_MIME_TYPE:
+ e_mail_part_set_mime_type (
+ E_MAIL_PART (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_PART_LIST:
+ e_mail_part_set_part_list (
+ E_MAIL_PART (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CID:
+ g_value_set_string (
+ value,
+ e_mail_part_get_cid (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_ID:
+ g_value_set_string (
+ value,
+ e_mail_part_get_id (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_IS_ATTACHMENT:
+ g_value_set_boolean (
+ value,
+ e_mail_part_get_is_attachment (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_MIME_PART:
+ g_value_take_object (
+ value,
+ e_mail_part_ref_mime_part (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_MIME_TYPE:
+ g_value_set_string (
+ value,
+ e_mail_part_get_mime_type (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_PART_LIST:
+ g_value_take_object (
+ value,
+ e_mail_part_ref_part_list (
+ E_MAIL_PART (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_dispose (GObject *object)
+{
+ EMailPartPrivate *priv;
+
+ priv = E_MAIL_PART_GET_PRIVATE (object);
+
+ g_weak_ref_set (&priv->part_list, NULL);
+
+ g_clear_object (&priv->mime_part);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_part_parent_class)->dispose (object);
+}
+
+static void
+mail_part_finalize (GObject *object)
+{
+ EMailPart *part = E_MAIL_PART (object);
+ EMailPartValidityPair *pair;
+
+ g_free (part->priv->id);
+ g_free (part->priv->cid);
+ g_free (part->priv->mime_type);
+
+ while ((pair = g_queue_pop_head (&part->validities)) != NULL)
+ mail_part_validity_pair_free (pair);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_part_parent_class)->finalize (object);
+}
+
+static void
+mail_part_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_part_parent_class)->constructed (object);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (object));
+}
+
+static void
+e_mail_part_class_init (EMailPartClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EMailPartPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_part_set_property;
+ object_class->get_property = mail_part_get_property;
+ object_class->dispose = mail_part_dispose;
+ object_class->finalize = mail_part_finalize;
+ object_class->constructed = mail_part_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CID,
+ g_param_spec_string (
+ "cid",
+ "Content ID",
+ "The MIME Content-ID",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ID,
+ g_param_spec_string (
+ "id",
+ "Part ID",
+ "The part ID",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_IS_ATTACHMENT,
+ g_param_spec_boolean (
+ "is-attachment",
+ "Is Attachment",
+ "Format the part as an attachment",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MIME_PART,
+ g_param_spec_object (
+ "mime-part",
+ "MIME Part",
+ "The MIME part",
+ CAMEL_TYPE_MIME_PART,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MIME_TYPE,
+ g_param_spec_string (
+ "mime-type",
+ "MIME Type",
+ "The MIME type",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PART_LIST,
+ g_param_spec_object (
+ "part-list",
+ "Part List",
+ "The part list that owns the part",
+ E_TYPE_MAIL_PART_LIST,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_mail_part_init (EMailPart *part)
+{
+ part->priv = E_MAIL_PART_GET_PRIVATE (part);
+}
+
+/**
+ * e_mail_part_new:
+ * @mime_part: (allow-none) a #CamelMimePart or %NULL
+ * @id: part ID
+ *
+ * Creates a new #EMailPart for the given @mime_part.
+ *
+ * Return value: a new #EMailPart
+ */
+EMailPart *
+e_mail_part_new (CamelMimePart *mime_part,
+ const gchar *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART,
+ "id", id, "mime-part", mime_part, NULL);
+}
+
+const gchar *
+e_mail_part_get_id (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ return part->priv->id;
+}
+
+const gchar *
+e_mail_part_get_cid (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ return part->priv->cid;
+}
+
+void
+e_mail_part_set_cid (EMailPart *part,
+ const gchar *cid)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ g_free (part->priv->cid);
+ part->priv->cid = g_strdup (cid);
+
+ g_object_notify (G_OBJECT (part), "cid");
+}
+
+gboolean
+e_mail_part_id_has_prefix (EMailPart *part,
+ const gchar *prefix)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+ g_return_val_if_fail (prefix != NULL, FALSE);
+
+ return g_str_has_prefix (part->priv->id, prefix);
+}
+
+gboolean
+e_mail_part_id_has_suffix (EMailPart *part,
+ const gchar *suffix)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+ g_return_val_if_fail (suffix != NULL, FALSE);
+
+ return g_str_has_suffix (part->priv->id, suffix);
+}
+
+gboolean
+e_mail_part_id_has_substr (EMailPart *part,
+ const gchar *substr)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+ g_return_val_if_fail (substr != NULL, FALSE);
+
+ return (strstr (part->priv->id, substr) != NULL);
+}
+
+CamelMimePart *
+e_mail_part_ref_mime_part (EMailPart *part)
+{
+ CamelMimePart *mime_part = NULL;
+
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ if (part->priv->mime_part != NULL)
+ mime_part = g_object_ref (part->priv->mime_part);
+
+ return mime_part;
+}
+
+const gchar *
+e_mail_part_get_mime_type (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ return part->priv->mime_type;
+}
+
+void
+e_mail_part_set_mime_type (EMailPart *part,
+ const gchar *mime_type)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ if (g_strcmp0 (mime_type, part->priv->mime_type) == 0)
+ return;
+
+ g_free (part->priv->mime_type);
+ part->priv->mime_type = g_strdup (mime_type);
+
+ g_object_notify (G_OBJECT (part), "mime-type");
+}
+
+EMailPartList *
+e_mail_part_ref_part_list (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ return g_weak_ref_get (&part->priv->part_list);
+}
+
+void
+e_mail_part_set_part_list (EMailPart *part,
+ EMailPartList *part_list)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ if (part_list != NULL)
+ g_return_if_fail (E_IS_MAIL_PART_LIST (part_list));
+
+ g_weak_ref_set (&part->priv->part_list, part_list);
+
+ g_object_notify (G_OBJECT (part), "part-list");
+}
+
+gboolean
+e_mail_part_get_is_attachment (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+
+ return part->priv->is_attachment;
+}
+
+void
+e_mail_part_set_is_attachment (EMailPart *part,
+ gboolean is_attachment)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ if (is_attachment == part->priv->is_attachment)
+ return;
+
+ part->priv->is_attachment = is_attachment;
+
+ g_object_notify (G_OBJECT (part), "is-attachment");
+}
+
+void
+e_mail_part_bind_dom_element (EMailPart *part,
+ WebKitDOMElement *element)
+{
+ EMailPartClass *class;
+
+ g_return_if_fail (E_IS_MAIL_PART (part));
+ g_return_if_fail (WEBKIT_DOM_IS_ELEMENT (element));
+
+ class = E_MAIL_PART_GET_CLASS (part);
+
+ if (class->bind_dom_element != NULL)
+ class->bind_dom_element (part, element);
+}
+
+static EMailPartValidityPair *
+mail_part_find_validity_pair (EMailPart *part,
+ EMailPartValidityFlags validity_type)
+{
+ GList *head, *link;
+
+ head = g_queue_peek_head_link (&part->validities);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+
+ if (pair == NULL)
+ continue;
+
+ if ((pair->validity_type & validity_type) == validity_type)
+ return pair;
+ }
+
+ return NULL;
+}
+
+/**
+ * e_mail_part_update_validity:
+ * @part: An #EMailPart
+ * @validity_type: E_MAIL_PART_VALIDITY_* flags
+ * @validity: a #CamelCipherValidity
+ *
+ * Updates validity of the @part. When the part already has some validity
+ * set, the new @validity and @validity_type are just appended, preserving
+ * the original validity. Validities of the same type (PGP or S/MIME) are
+ * merged together.
+ */
+void
+e_mail_part_update_validity (EMailPart *part,
+ CamelCipherValidity *validity,
+ EMailPartValidityFlags validity_type)
+{
+ EMailPartValidityPair *pair;
+ EMailPartValidityFlags mask;
+
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ mask = E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SMIME;
+
+ pair = mail_part_find_validity_pair (part, validity_type & mask);
+ if (pair != NULL) {
+ pair->validity_type |= validity_type;
+ camel_cipher_validity_envelope (pair->validity, validity);
+ } else {
+ pair = g_new0 (EMailPartValidityPair, 1);
+ pair->validity_type = validity_type;
+ pair->validity = camel_cipher_validity_clone (validity);
+
+ g_queue_push_tail (&part->validities, pair);
+ }
+}
+
+/**
+ * e_mail_part_get_validity:
+ * @part: An #EMailPart
+ * @validity_type: E_MAIL_PART_VALIDITY_* flags
+ *
+ * Returns, validity of @part contains any validity with the same bits
+ * as @validity_type set. It should contain all bits of it.
+ *
+ * Returns: a #CamelCipherValidity of the given type, %NULL if not found
+ *
+ * Since: 3.8
+ */
+CamelCipherValidity *
+e_mail_part_get_validity (EMailPart *part,
+ EMailPartValidityFlags validity_type)
+{
+ EMailPartValidityPair *pair;
+
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ pair = mail_part_find_validity_pair (part, validity_type);
+
+ return (pair != NULL) ? pair->validity : NULL;
+}
+
+gboolean
+e_mail_part_has_validity (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+
+ return !g_queue_is_empty (&part->validities);
+}
+
+EMailPartValidityFlags
+e_mail_part_get_validity_flags (EMailPart *part)
+{
+ EMailPartValidityFlags flags = 0;
+ GList *head, *link;
+
+ g_return_val_if_fail (E_IS_MAIL_PART (part), 0);
+
+ head = g_queue_peek_head_link (&part->validities);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+
+ if (pair != NULL)
+ flags |= pair->validity_type;
+ }
+
+ return flags;
+}
+
diff --git a/em-format/e-mail-part.h b/em-format/e-mail-part.h
new file mode 100644
index 0000000000..75057c2ee5
--- /dev/null
+++ b/em-format/e-mail-part.h
@@ -0,0 +1,132 @@
+/*
+ * e-mail-part.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_H
+#define E_MAIL_PART_H
+
+#include <camel/camel.h>
+#include <webkit/webkitdom.h>
+
+#include <e-util/e-util.h>
+
+#include <em-format/e-mail-formatter-enums.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART \
+ (e_mail_part_get_type ())
+#define E_MAIL_PART(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PART, EMailPart))
+#define E_MAIL_PART_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PART, EMailPartClass))
+#define E_IS_MAIL_PART(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PART))
+#define E_IS_MAIL_PART_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PART))
+#define E_MAIL_PART_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PART, EMailPartClass))
+
+G_BEGIN_DECLS
+
+struct _EMailPartList;
+
+typedef struct _EMailPart EMailPart;
+typedef struct _EMailPartClass EMailPartClass;
+typedef struct _EMailPartPrivate EMailPartPrivate;
+
+typedef struct _EMailPartValidityPair EMailPartValidityPair;
+
+struct _EMailPartValidityPair {
+ EMailPartValidityFlags validity_type;
+ CamelCipherValidity *validity;
+};
+
+struct _EMailPart {
+ GObject parent;
+ EMailPartPrivate *priv;
+
+ GQueue validities; /* element-type: EMailPartValidityPair */
+
+ /* Whether the part should be rendered or not.
+ * This is used for example to prevent images
+ * related to text/html parts from being
+ * rendered as attachments. */
+ gint is_hidden: 1;
+
+ /* Force attachment to be expanded, even without
+ * content-disposition: inline */
+ gint force_inline: 1;
+
+ /* Force attachment to be collapsed, even with
+ * content-disposition: inline */
+ gint force_collapse: 1;
+
+ /* Does part contain an error message? */
+ gint is_error: 1;
+};
+
+struct _EMailPartClass {
+ GObjectClass parent_class;
+
+ void (*bind_dom_element) (EMailPart *part,
+ WebKitDOMElement *element);
+};
+
+GType e_mail_part_get_type (void) G_GNUC_CONST;
+EMailPart * e_mail_part_new (CamelMimePart *mime_part,
+ const gchar *id);
+const gchar * e_mail_part_get_id (EMailPart *part);
+const gchar * e_mail_part_get_cid (EMailPart *part);
+void e_mail_part_set_cid (EMailPart *part,
+ const gchar *cid);
+gboolean e_mail_part_id_has_prefix (EMailPart *part,
+ const gchar *prefix);
+gboolean e_mail_part_id_has_suffix (EMailPart *part,
+ const gchar *suffix);
+gboolean e_mail_part_id_has_substr (EMailPart *part,
+ const gchar *substr);
+CamelMimePart * e_mail_part_ref_mime_part (EMailPart *part);
+const gchar * e_mail_part_get_mime_type (EMailPart *part);
+void e_mail_part_set_mime_type (EMailPart *part,
+ const gchar *mime_type);
+struct _EMailPartList *
+ e_mail_part_ref_part_list (EMailPart *part);
+void e_mail_part_set_part_list (EMailPart *part,
+ struct _EMailPartList *part_list);
+gboolean e_mail_part_get_is_attachment (EMailPart *part);
+void e_mail_part_set_is_attachment (EMailPart *part,
+ gboolean is_attachment);
+void e_mail_part_bind_dom_element (EMailPart *part,
+ WebKitDOMElement *element);
+void e_mail_part_update_validity (EMailPart *part,
+ CamelCipherValidity *validity,
+ EMailPartValidityFlags validity_type);
+CamelCipherValidity *
+ e_mail_part_get_validity (EMailPart *part,
+ EMailPartValidityFlags validity_type);
+gboolean e_mail_part_has_validity (EMailPart *part);
+EMailPartValidityFlags
+ e_mail_part_get_validity_flags (EMailPart *part);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_H */
diff --git a/em-format/e-mail-stripsig-filter.c b/em-format/e-mail-stripsig-filter.c
new file mode 100644
index 0000000000..e861a13a53
--- /dev/null
+++ b/em-format/e-mail-stripsig-filter.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "e-mail-stripsig-filter.h"
+
+G_DEFINE_TYPE (EMailStripSigFilter, e_mail_stripsig_filter, CAMEL_TYPE_MIME_FILTER)
+
+static void
+strip_signature (CamelMimeFilter *filter,
+ const gchar *in,
+ gsize len,
+ gsize prespace,
+ gchar **out,
+ gsize *outlen,
+ gsize *outprespace,
+ gint flush)
+{
+ EMailStripSigFilter *stripsig = (EMailStripSigFilter *) filter;
+ register const gchar *inptr = in;
+ const gchar *inend = in + len;
+ const gchar *start = NULL;
+
+ if (stripsig->midline) {
+ while (inptr < inend && *inptr != '\n')
+ inptr++;
+
+ if (inptr < inend) {
+ stripsig->midline = FALSE;
+ inptr++;
+ }
+ }
+
+ while (inptr < inend) {
+ if ((inend - inptr) >= 4 && !strncmp (inptr, "-- \n", 4)) {
+ start = inptr;
+ inptr += 4;
+ } else if (!stripsig->text_plain_only &&
+ (inend - inptr) >= 7 &&
+ !g_ascii_strncasecmp (inptr, "-- <BR>", 7)) {
+ start = inptr;
+ inptr += 7;
+ } else {
+ while (inptr < inend && *inptr != '\n')
+ inptr++;
+
+ if (inptr == inend) {
+ stripsig->midline = TRUE;
+ break;
+ }
+
+ inptr++;
+ }
+ }
+
+ if (start != NULL) {
+ inptr = start;
+ stripsig->midline = FALSE;
+ }
+
+ if (!flush && inend > inptr)
+ camel_mime_filter_backup (filter, inptr, inend - inptr);
+ else if (!start)
+ inptr = inend;
+
+ *out = (gchar *)in;
+ *outlen = inptr - in;
+ *outprespace = prespace;
+}
+
+static void
+filter_filter (CamelMimeFilter *filter,
+ const gchar *in,
+ gsize len,
+ gsize prespace,
+ gchar **out,
+ gsize *outlen,
+ gsize *outprespace)
+{
+ strip_signature (
+ filter, in, len, prespace, out, outlen, outprespace, FALSE);
+}
+
+static void
+filter_complete (CamelMimeFilter *filter,
+ const gchar *in,
+ gsize len,
+ gsize prespace,
+ gchar **out,
+ gsize *outlen,
+ gsize *outprespace)
+{
+ strip_signature (
+ filter, in, len, prespace, out, outlen, outprespace, TRUE);
+}
+
+/* should this 'flush' outstanding state/data bytes? */
+static void
+filter_reset (CamelMimeFilter *filter)
+{
+ EMailStripSigFilter *stripsig = (EMailStripSigFilter *) filter;
+
+ stripsig->midline = FALSE;
+}
+
+static void
+e_mail_stripsig_filter_class_init (EMailStripSigFilterClass *class)
+{
+ CamelMimeFilterClass *mime_filter_class;
+
+ mime_filter_class = CAMEL_MIME_FILTER_CLASS (class);
+ mime_filter_class->filter = filter_filter;
+ mime_filter_class->complete = filter_complete;
+ mime_filter_class->reset = filter_reset;
+}
+
+static void
+e_mail_stripsig_filter_init (EMailStripSigFilter *filter)
+{
+}
+
+/**
+ * e_mail_stripsig_filter_new:
+ * @text_plain_only: Whether should look for a text/plain signature
+ * delimiter "-- \n" only or also an HTML signature delimiter "-- <BR>".
+ *
+ * Creates a new stripsig filter.
+ *
+ * Returns a new stripsig filter.
+ **/
+CamelMimeFilter *
+e_mail_stripsig_filter_new (gboolean text_plain_only)
+{
+ EMailStripSigFilter *filter = g_object_new (E_TYPE_MAIL_STRIPSIG_FILTER, NULL);
+
+ filter->text_plain_only = text_plain_only;
+
+ return CAMEL_MIME_FILTER (filter);
+}
diff --git a/em-format/e-mail-stripsig-filter.h b/em-format/e-mail-stripsig-filter.h
new file mode 100644
index 0000000000..75d3719133
--- /dev/null
+++ b/em-format/e-mail-stripsig-filter.h
@@ -0,0 +1,69 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_STRIPSIG_FILTER_H
+#define E_MAIL_STRIPSIG_FILTER_H
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_STRIPSIG_FILTER \
+ (e_mail_stripsig_filter_get_type ())
+#define E_MAIL_STRIPSIG_FILTER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_STRIPSIG_FILTER, EMailStripSigFilter))
+#define E_MAIL_STRIPSIG_FILTER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_STRIPSIG_FILTER, EMailStripSigFilterClass))
+#define E_IS_MAIL_STRIPSIG_FILTER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_STRIPSIG_FILTER))
+#define E_IS_MAIL_STRIPSIG_FILTER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_STRIPSIG_FILTER))
+#define E_MAIL_STRIPSIG_FILTER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_STRIPSIG_FILTER, EMailStripSigFilterClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailStripSigFilter EMailStripSigFilter;
+typedef struct _EMailStripSigFilterClass EMailStripSigFilterClass;
+
+struct _EMailStripSigFilter {
+ CamelMimeFilter parent;
+
+ guint32 midline : 1;
+ guint32 text_plain_only : 1;
+};
+
+struct _EMailStripSigFilterClass {
+ CamelMimeFilterClass parent_class;
+};
+
+GType e_mail_stripsig_filter_get_type (void);
+CamelMimeFilter *
+ e_mail_stripsig_filter_new (gboolean text_plain_only);
+
+G_END_DECLS
+
+#endif /* E_MAIL_STRIPSIG_FILTER_H */