aboutsummaryrefslogtreecommitdiffstats
path: root/em-format/e-mail-formatter.c
diff options
context:
space:
mode:
Diffstat (limited to 'em-format/e-mail-formatter.c')
-rw-r--r--em-format/e-mail-formatter.c1510
1 files changed, 1510 insertions, 0 deletions
diff --git a/em-format/e-mail-formatter.c b/em-format/e-mail-formatter.c
new file mode 100644
index 0000000000..a08504a21f
--- /dev/null
+++ b/em-format/e-mail-formatter.c
@@ -0,0 +1,1510 @@
+/*
+ * e-mail-formatter.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter.h"
+
+#include <camel/camel.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-formatter-utils.h"
+#include "e-mail-part.h"
+
+#include "e-mail-format-extensions.h"
+
+#include <e-util/e-util.h>
+#include <libebackend/libebackend.h>
+#include <gdk/gdk.h>
+#include <glib/gi18n.h>
+
+#define d(x)
+
+struct _EMailFormatterPrivate {
+ EMailImageLoadingPolicy image_loading_policy;
+
+ guint only_local_photos : 1;
+ guint show_sender_photo : 1;
+ guint show_real_date : 1;
+ guint animate_images : 1;
+
+ gchar *charset;
+ gchar *default_charset;
+
+ GQueue *header_list;
+};
+
+#define E_MAIL_FORMATTER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterPrivate))\
+
+static gpointer e_mail_formatter_parent_class = 0;
+
+enum {
+ PROP_0,
+ PROP_BODY_COLOR,
+ PROP_CITATION_COLOR,
+ PROP_CONTENT_COLOR,
+ PROP_FRAME_COLOR,
+ PROP_HEADER_COLOR,
+ PROP_TEXT_COLOR,
+ PROP_IMAGE_LOADING_POLICY,
+ PROP_FORCE_IMAGE_LOADING,
+ PROP_MARK_CITATIONS,
+ PROP_ONLY_LOCAL_PHOTOS,
+ PROP_SHOW_SENDER_PHOTO,
+ PROP_SHOW_REAL_DATE,
+ PROP_ANIMATE_IMAGES,
+ PROP_CHARSET,
+ PROP_DEFAULT_CHARSET
+};
+
+static void
+mail_formatter_run (EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ GSList *iter;
+ gchar *hdr;
+
+ hdr = e_mail_formatter_get_html_header (formatter);
+ camel_stream_write_string (stream, hdr, cancellable, NULL);
+ g_free (hdr);
+
+ for (iter = context->parts; iter; iter = iter->next) {
+
+ EMailPart *part;
+ gboolean ok;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ break;
+
+ part = iter->data;
+ if (!part)
+ continue;
+
+ if (part->is_hidden && !part->is_error) {
+ if (g_str_has_suffix (part->id, ".rfc822")) {
+ iter = e_mail_formatter_find_rfc822_end_iter (iter);
+ }
+
+ if (!iter)
+ break;
+
+ continue;
+ }
+
+ /* Force formatting as source if needed */
+ if (context->mode != E_MAIL_FORMATTER_MODE_SOURCE) {
+
+ if (!part->mime_type)
+ continue;
+
+ ok = e_mail_formatter_format_as (
+ formatter, context, part, stream,
+ part->mime_type, cancellable);
+
+ /* If the written part was message/rfc822 then
+ * jump to the end of the message, because content
+ * of the whole message has been formatted by
+ * message_rfc822 formatter */
+ if (ok && g_str_has_suffix (part->id, ".rfc822")) {
+ iter = e_mail_formatter_find_rfc822_end_iter (iter);
+
+ if (!iter)
+ break;
+
+ continue;
+ }
+
+ } else {
+ ok = FALSE;
+ }
+
+ if (!ok) {
+ /* We don't want to source these */
+ if (g_str_has_suffix (part->id, ".headers") ||
+ g_str_has_suffix (part->id, "attachment-bar"))
+ continue;
+
+ e_mail_formatter_format_as (
+ formatter, context, part, stream,
+ "application/vnd.evolution.source", cancellable);
+
+ /* .message is the entire message. There's nothing more
+ * to be written. */
+ if (g_strcmp0 (part->id, ".message") == 0)
+ break;
+
+ /* If we just wrote source of a rfc822 message, then jump
+ * behind the message (otherwise source of all parts
+ * would be rendered twice) */
+ if (g_str_has_suffix (part->id, ".rfc822")) {
+
+ do {
+ part = iter->data;
+ if (part && g_str_has_suffix (part->id, ".rfc822.end"))
+ break;
+
+ iter = iter->next;
+ } while (iter);
+ }
+ }
+ }
+
+ camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+}
+
+static EMailFormatterContext *
+mail_formatter_create_context (EMailFormatter *formatter)
+{
+ EMailFormatterClass *formatter_class;
+
+ formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+
+ if (formatter_class->create_context) {
+ if (!formatter_class->free_context) {
+ g_warning ("%s implements create_context() but "
+ "does not implement free_context()!",
+ G_OBJECT_TYPE_NAME (formatter));
+ }
+
+ return formatter_class->create_context (formatter);
+ }
+
+ return g_new0 (EMailFormatterContext, 1);
+}
+
+static void
+mail_formatter_free_context (EMailFormatter *formatter,
+ EMailFormatterContext *context)
+{
+ EMailFormatterClass *formatter_class;
+
+ formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+
+ if (formatter_class->free_context) {
+ formatter_class->free_context (formatter, context);
+ } else {
+ g_free (context);
+ }
+}
+
+static void
+mail_formatter_set_style (EMailFormatter *formatter,
+ GtkStyle *style,
+ GtkStateType state)
+{
+ GdkColor *color;
+ EMailFormatterColorType type;
+
+ g_object_freeze_notify (G_OBJECT (formatter));
+
+ color = &style->bg[state];
+ type = E_MAIL_FORMATTER_COLOR_BODY;
+ e_mail_formatter_set_color (formatter, type, color);
+
+ color = &style->base[GTK_STATE_NORMAL];
+ type = E_MAIL_FORMATTER_COLOR_CONTENT;
+ e_mail_formatter_set_color (formatter, type, color);
+
+ color = &style->dark[state];
+ type = E_MAIL_FORMATTER_COLOR_FRAME;
+ e_mail_formatter_set_color (formatter, type, color);
+
+ color = &style->fg[state];
+ type = E_MAIL_FORMATTER_COLOR_HEADER;
+ e_mail_formatter_set_color (formatter, type, color);
+
+ color = &style->text[state];
+ type = E_MAIL_FORMATTER_COLOR_TEXT;
+ e_mail_formatter_set_color (formatter, type, color);
+
+ g_object_thaw_notify (G_OBJECT (formatter));
+}
+
+static void
+e_mail_formatter_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BODY_COLOR:
+ e_mail_formatter_set_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_BODY,
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_CITATION_COLOR:
+ e_mail_formatter_set_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_CITATION,
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_CONTENT_COLOR:
+ e_mail_formatter_set_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_CONTENT,
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_FRAME_COLOR:
+ e_mail_formatter_set_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_FRAME,
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_HEADER_COLOR:
+ e_mail_formatter_set_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_HEADER,
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_IMAGE_LOADING_POLICY:
+ e_mail_formatter_set_image_loading_policy (
+ E_MAIL_FORMATTER (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_MARK_CITATIONS:
+ e_mail_formatter_set_mark_citations (
+ E_MAIL_FORMATTER (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_ONLY_LOCAL_PHOTOS:
+ e_mail_formatter_set_only_local_photos (
+ E_MAIL_FORMATTER (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SHOW_SENDER_PHOTO:
+ e_mail_formatter_set_show_sender_photo (
+ E_MAIL_FORMATTER (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SHOW_REAL_DATE:
+ e_mail_formatter_set_show_real_date (
+ E_MAIL_FORMATTER (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_TEXT_COLOR:
+ e_mail_formatter_set_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_TEXT,
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_ANIMATE_IMAGES:
+ e_mail_formatter_set_animate_images (
+ E_MAIL_FORMATTER (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_CHARSET:
+ e_mail_formatter_set_charset (
+ E_MAIL_FORMATTER (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_DEFAULT_CHARSET:
+ e_mail_formatter_set_default_charset (
+ E_MAIL_FORMATTER (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_formatter_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BODY_COLOR:
+ g_value_set_boxed (value,
+ e_mail_formatter_get_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_BODY));
+ return;
+
+ case PROP_CITATION_COLOR:
+ g_value_set_boxed (value,
+ e_mail_formatter_get_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_CITATION));
+ return;
+
+ case PROP_CONTENT_COLOR:
+ g_value_set_boxed (value,
+ e_mail_formatter_get_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_CONTENT));
+ return;
+
+ case PROP_FRAME_COLOR:
+ g_value_set_boxed (value,
+ e_mail_formatter_get_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_FRAME));
+ return;
+
+ case PROP_HEADER_COLOR:
+ g_value_set_boxed (value,
+ e_mail_formatter_get_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_HEADER));
+ return;
+
+ case PROP_IMAGE_LOADING_POLICY:
+ g_value_set_int (
+ value,
+ e_mail_formatter_get_image_loading_policy (
+ E_MAIL_FORMATTER (object)));
+ return;
+
+ case PROP_MARK_CITATIONS:
+ g_value_set_boolean (
+ value, e_mail_formatter_get_mark_citations (
+ E_MAIL_FORMATTER (object)));
+ return;
+
+ case PROP_ONLY_LOCAL_PHOTOS:
+ g_value_set_boolean (
+ value, e_mail_formatter_get_only_local_photos (
+ E_MAIL_FORMATTER (object)));
+ return;
+
+ case PROP_SHOW_SENDER_PHOTO:
+ g_value_set_boolean (
+ value, e_mail_formatter_get_show_sender_photo (
+ E_MAIL_FORMATTER (object)));
+ return;
+
+ case PROP_SHOW_REAL_DATE:
+ g_value_set_boolean (
+ value, e_mail_formatter_get_show_real_date (
+ E_MAIL_FORMATTER (object)));
+ return;
+
+ case PROP_TEXT_COLOR:
+ g_value_set_boxed (value,
+ e_mail_formatter_get_color (
+ E_MAIL_FORMATTER (object),
+ E_MAIL_FORMATTER_COLOR_TEXT));
+ return;
+
+ case PROP_ANIMATE_IMAGES:
+ g_value_set_boolean (
+ value, e_mail_formatter_get_animate_images (
+ E_MAIL_FORMATTER (object)));
+ return;
+
+ case PROP_CHARSET:
+ g_value_set_string (
+ value, e_mail_formatter_get_charset (
+ E_MAIL_FORMATTER (object)));
+ return;
+
+ case PROP_DEFAULT_CHARSET:
+ g_value_set_string (
+ value, e_mail_formatter_get_default_charset (
+ E_MAIL_FORMATTER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_formatter_init (EMailFormatter *formatter)
+{
+ formatter->priv = E_MAIL_FORMATTER_GET_PRIVATE (formatter);
+
+ formatter->priv->header_list = g_queue_new ();
+ e_mail_formatter_set_default_headers (formatter);
+}
+
+static void
+e_mail_formatter_finalize (GObject *object)
+{
+ EMailFormatterPrivate *priv;
+
+ priv = E_MAIL_FORMATTER (object)->priv;
+
+ if (priv->charset) {
+ g_free (priv->charset);
+ priv->charset = NULL;
+ }
+
+ if (priv->default_charset) {
+ g_free (priv->default_charset);
+ priv->default_charset = NULL;
+ }
+
+ if (priv->header_list) {
+ e_mail_formatter_clear_headers (E_MAIL_FORMATTER (object));
+ g_queue_free (priv->header_list);
+ priv->header_list = NULL;
+ }
+
+ /* Chain up to parent's finalize() */
+ G_OBJECT_CLASS (e_mail_formatter_parent_class)->finalize (object);
+}
+
+static void
+e_mail_formatter_base_init (EMailFormatterClass *klass)
+{
+ klass->extension_registry = g_object_new (
+ E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, NULL);
+
+ e_mail_formatter_internal_extensions_load (
+ E_MAIL_EXTENSION_REGISTRY (klass->extension_registry));
+
+ e_extensible_load_extensions (
+ E_EXTENSIBLE (klass->extension_registry));
+
+ klass->text_html_flags =
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+ CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+}
+
+static void
+e_mail_formatter_base_finalize (EMailFormatterClass *klass)
+{
+ g_object_unref (klass->extension_registry);
+}
+
+static void
+e_mail_formatter_constructed (GObject *object)
+{
+ G_OBJECT_CLASS (e_mail_formatter_parent_class)->constructed (object);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (object));
+}
+
+static void
+e_mail_formatter_class_init (EMailFormatterClass *klass)
+{
+ GObjectClass *object_class;
+ GdkColor *color;
+
+ e_mail_formatter_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (EMailFormatterPrivate));
+
+ klass->run = mail_formatter_run;
+
+ /* EMailFormatter calls these directly */
+ klass->create_context = NULL;
+ klass->free_context = NULL;
+ klass->set_style = mail_formatter_set_style;
+
+ color = &klass->colors[E_MAIL_FORMATTER_COLOR_BODY];
+ gdk_color_parse ("#eeeeee", color);
+
+ color = &klass->colors[E_MAIL_FORMATTER_COLOR_CONTENT];
+ gdk_color_parse ("#ffffff", color);
+
+ color = &klass->colors[E_MAIL_FORMATTER_COLOR_FRAME];
+ gdk_color_parse ("#3f3f3f", color);
+
+ color = &klass->colors[E_MAIL_FORMATTER_COLOR_HEADER];
+ gdk_color_parse ("#eeeeee", color);
+
+ color = &klass->colors[E_MAIL_FORMATTER_COLOR_TEXT];
+ gdk_color_parse ("#000000", color);
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->constructed = e_mail_formatter_constructed;
+ object_class->get_property = e_mail_formatter_get_property;
+ object_class->set_property = e_mail_formatter_set_property;
+ object_class->finalize = e_mail_formatter_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BODY_COLOR,
+ g_param_spec_boxed (
+ "body-color",
+ "Body Color",
+ NULL,
+ GDK_TYPE_COLOR,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CITATION_COLOR,
+ g_param_spec_boxed (
+ "citation-color",
+ "Citation Color",
+ NULL,
+ GDK_TYPE_COLOR,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CONTENT_COLOR,
+ g_param_spec_boxed (
+ "content-color",
+ "Content Color",
+ NULL,
+ GDK_TYPE_COLOR,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FRAME_COLOR,
+ g_param_spec_boxed (
+ "frame-color",
+ "Frame Color",
+ NULL,
+ GDK_TYPE_COLOR,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_HEADER_COLOR,
+ g_param_spec_boxed (
+ "header-color",
+ "Header Color",
+ NULL,
+ GDK_TYPE_COLOR,
+ G_PARAM_READWRITE));
+
+ /* FIXME Make this a proper enum property. */
+ g_object_class_install_property (
+ object_class,
+ PROP_IMAGE_LOADING_POLICY,
+ g_param_spec_int (
+ "image-loading-policy",
+ "Image Loading Policy",
+ NULL,
+ E_MAIL_IMAGE_LOADING_POLICY_NEVER,
+ E_MAIL_IMAGE_LOADING_POLICY_ALWAYS,
+ E_MAIL_IMAGE_LOADING_POLICY_NEVER,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MARK_CITATIONS,
+ g_param_spec_boolean (
+ "mark-citations",
+ "Mark Citations",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ONLY_LOCAL_PHOTOS,
+ g_param_spec_boolean (
+ "only-local-photos",
+ "Only Local Photos",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_SENDER_PHOTO,
+ g_param_spec_boolean (
+ "show-sender-photo",
+ "Show Sender Photo",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_REAL_DATE,
+ g_param_spec_boolean (
+ "show-real-date",
+ "Show real Date header value",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_TEXT_COLOR,
+ g_param_spec_boxed (
+ "text-color",
+ "Text Color",
+ NULL,
+ GDK_TYPE_COLOR,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ANIMATE_IMAGES,
+ g_param_spec_boolean (
+ "animate-images",
+ "Animate images",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CHARSET,
+ g_param_spec_string (
+ "charset",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DEFAULT_CHARSET,
+ g_param_spec_string (
+ "default-charset",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+}
+
+static void
+e_mail_formatter_extensible_interface_init (EExtensibleInterface *interface)
+{
+
+}
+
+EMailFormatter *
+e_mail_formatter_new (void)
+{
+ return g_object_new (E_TYPE_MAIL_FORMATTER, NULL);
+}
+
+GType
+e_mail_formatter_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (EMailFormatterClass),
+ (GBaseInitFunc) e_mail_formatter_base_init,
+ (GBaseFinalizeFunc) e_mail_formatter_base_finalize,
+ (GClassInitFunc) e_mail_formatter_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailFormatter),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) e_mail_formatter_init,
+ NULL /* value_table */
+ };
+
+ const GInterfaceInfo e_extensible_interface_info = {
+ (GInterfaceInitFunc) e_mail_formatter_extensible_interface_init
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "EMailFormatter", &type_info, 0);
+
+ g_type_add_interface_static (type,
+ E_TYPE_EXTENSIBLE, &e_extensible_interface_info);
+ }
+
+ return type;
+}
+
+void
+e_mail_formatter_format_sync (EMailFormatter *formatter,
+ EMailPartList *parts,
+ CamelStream *stream,
+ guint32 flags,
+ EMailFormatterMode mode,
+ GCancellable *cancellable)
+{
+ EMailFormatterContext *context;
+ EMailFormatterClass *formatter_class;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+ formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+ g_return_if_fail (formatter_class->run != NULL);
+
+ context = mail_formatter_create_context (formatter);
+ context->message = parts->message;
+ context->folder = parts->folder;
+ context->message_uid = parts->message_uid;
+ context->parts = parts->list;
+ context->flags = flags;
+ context->mode = mode;
+
+ formatter_class->run (
+ formatter, context, stream, cancellable);
+
+ mail_formatter_free_context (formatter, context);
+}
+
+static void
+mail_format_async_prepare (GSimpleAsyncResult *result,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ EMailFormatterContext *context;
+ EMailFormatterClass *formatter_class;
+ CamelStream *stream;
+
+ context = g_object_get_data (G_OBJECT (result), "context");
+ stream = g_object_get_data (G_OBJECT (result), "stream");
+
+ formatter_class = E_MAIL_FORMATTER_GET_CLASS (object);
+ formatter_class->run (
+ E_MAIL_FORMATTER (object), context, stream, cancellable);
+}
+
+void
+e_mail_formatter_format (EMailFormatter *formatter,
+ EMailPartList *parts,
+ CamelStream *stream,
+ guint32 flags,
+ EMailFormatterMode mode,
+ GAsyncReadyCallback callback,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ EMailFormatterContext *context;
+ EMailFormatterClass *formatter_class;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+ formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+ g_return_if_fail (formatter_class->run != NULL);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (formatter), callback,
+ user_data, e_mail_formatter_format);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ if (!parts && callback) {
+ callback (G_OBJECT (formatter), G_ASYNC_RESULT (simple), user_data);
+ g_object_unref (simple);
+ return;
+ }
+
+ context = mail_formatter_create_context (formatter);
+ context->message = g_object_ref (parts->message);
+ context->folder = g_object_ref (parts->folder);
+ context->message_uid = g_strdup (parts->message_uid);
+ context->parts = g_slist_copy (parts->list);
+ g_slist_foreach (context->parts, (GFunc) e_mail_part_ref, NULL);
+ context->flags = flags;
+ context->mode = mode;
+
+ g_object_set_data (G_OBJECT (simple), "context", context);
+ g_object_set_data (G_OBJECT (simple), "stream", stream);
+
+ g_simple_async_result_run_in_thread (
+ simple, mail_format_async_prepare,
+ G_PRIORITY_DEFAULT, cancellable);
+
+ g_object_unref (simple);
+}
+
+CamelStream *
+e_mail_formatter_format_finished (EMailFormatter *formatter,
+ GAsyncResult *result,
+ GError *error)
+{
+ EMailFormatterContext *context;
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+ context = g_object_get_data (G_OBJECT (result), "context");
+
+ g_free (context->message_uid);
+ g_object_unref (context->message);
+ g_object_unref (context->folder);
+ g_slist_foreach (context->parts, (GFunc) e_mail_part_unref, NULL);
+ g_slist_free (context->parts);
+ mail_formatter_free_context (formatter, context);
+
+ return g_object_get_data (G_OBJECT (result), "stream");
+}
+
+/**
+ * e_mail_formatter_format_as:
+ * @formatter: an #EMailFormatter
+ * @context: an #EMailFormatterContext
+ * @part: an #EMailPart
+ * @stream: a #CamelStream
+ * @as_mime_type: (allow-none) mime-type to use for formatting, or %NULL
+ * @cancellable: (allow-none) an optional #GCancellable
+ *
+ * Formats given @part using a @formatter extension for given mime type. When
+ * the mime type is %NULL, the function will try to lookup the best formatter
+ * for given @part by it's default mime type.
+ *
+ * Return Value: %TRUE on success, %FALSE when no suitable formatter is found or
+ * when it fails to format the part.
+ */
+gboolean
+e_mail_formatter_format_as (EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ CamelStream *stream,
+ const gchar *as_mime_type,
+ GCancellable *cancellable)
+{
+ EMailExtensionRegistry *reg;
+ GQueue *formatters;
+ GList *iter;
+ gboolean ok;
+ d (
+ gint _call_i;
+ static gint _call = 0;
+ G_LOCK_DEFINE_STATIC (_call);
+ G_LOCK (_call);
+ _call++;
+ _call_i = _call;
+ G_UNLOCK (_call)
+ );
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+ g_return_val_if_fail (part, FALSE);
+ g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE);
+
+ if (!as_mime_type || !*as_mime_type)
+ as_mime_type = part->mime_type;
+
+ if (!as_mime_type || !*as_mime_type)
+ return FALSE;
+
+ reg = e_mail_formatter_get_extension_registry (formatter);
+ formatters = e_mail_extension_registry_get_for_mime_type (
+ reg, as_mime_type);
+ if (!formatters) {
+ formatters = e_mail_extension_registry_get_fallback (
+ reg, as_mime_type);
+ }
+
+ ok = FALSE;
+
+ d(printf("(%d) Formatting for part %s of type %s (found %d formatters)\n",
+ _call_i, part->id, as_mime_type,
+ formatters ? g_queue_get_length (formatters) : 0));
+
+ if (formatters) {
+ for (iter = formatters->head; iter; iter = iter->next) {
+
+ EMailFormatterExtension *extension;
+
+ extension = iter->data;
+ if (!extension)
+ continue;
+
+ ok = e_mail_formatter_extension_format (
+ extension, formatter, context,
+ part, stream, cancellable);
+
+ d(printf("\t(%d) trying %s...%s\n", _call_i,
+ G_OBJECT_TYPE_NAME (extension),
+ ok ? "OK" : "failed"));
+
+ if (ok)
+ break;
+ }
+ }
+
+ return ok;
+}
+
+/**
+ * em_format_format_text:
+ * @part: an #EMailPart to decode
+ * @formatter: an #EMailFormatter
+ * @stream: Where to write the converted text
+ * @cancellable: optional #GCancellable object, or %NULL
+ *
+ * Decode/output a part's content to @stream.
+ **/
+void
+e_mail_formatter_format_text (EMailFormatter *formatter,
+ EMailPart *part,
+ CamelStream *stream,
+ GCancellable *cancellable)
+{
+ CamelStream *filter_stream;
+ CamelMimeFilter *filter;
+ const gchar *charset = NULL;
+ CamelMimeFilterWindows *windows = NULL;
+ CamelStream *mem_stream = NULL;
+ CamelDataWrapper *dw;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ dw = CAMEL_DATA_WRAPPER (part->part);
+
+ if (formatter->priv->charset) {
+ charset = formatter->priv->charset;
+ } else if (dw->mime_type
+ && (charset = camel_content_type_param (dw->mime_type, "charset"))
+ && g_ascii_strncasecmp(charset, "iso-8859-", 9) == 0) {
+ CamelStream *null;
+
+ /* Since a few Windows mailers like to claim they sent
+ * out iso-8859-# encoded text when they really sent
+ * out windows-cp125#, do some simple sanity checking
+ * before we move on... */
+
+ null = camel_stream_null_new ();
+ filter_stream = camel_stream_filter_new (null);
+ g_object_unref (null);
+
+ windows = (CamelMimeFilterWindows *) camel_mime_filter_windows_new (charset);
+ camel_stream_filter_add (
+ CAMEL_STREAM_FILTER (filter_stream),
+ CAMEL_MIME_FILTER (windows));
+
+ camel_data_wrapper_decode_to_stream_sync (
+ dw, (CamelStream *) filter_stream, cancellable, NULL);
+ camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL);
+ g_object_unref (filter_stream);
+
+ charset = camel_mime_filter_windows_real_charset (windows);
+ } else if (charset == NULL) {
+ charset = formatter->priv->default_charset;
+ }
+
+ mem_stream = (CamelStream *) camel_stream_mem_new ();
+ filter_stream = camel_stream_filter_new (mem_stream);
+
+ if ((filter = camel_mime_filter_charset_new (charset, "UTF-8"))) {
+ camel_stream_filter_add (
+ CAMEL_STREAM_FILTER (filter_stream),
+ CAMEL_MIME_FILTER (filter));
+ g_object_unref (filter);
+ }
+
+ camel_data_wrapper_decode_to_stream_sync (
+ camel_medium_get_content ((CamelMedium *) dw),
+ (CamelStream *) filter_stream, cancellable, NULL);
+ camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL);
+ g_object_unref (filter_stream);
+
+ g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, NULL, NULL);
+
+ camel_stream_write_to_stream (
+ mem_stream, (CamelStream *) stream, cancellable, NULL);
+ camel_stream_flush ((CamelStream *) mem_stream, cancellable, NULL);
+
+ if (windows) {
+ g_object_unref (windows);
+ }
+
+ g_object_unref (mem_stream);
+}
+
+gchar *
+e_mail_formatter_get_html_header (EMailFormatter *formatter)
+{
+ return g_strdup_printf (
+ "<!DOCTYPE HTML>\n<html>\n"
+ "<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\" />\n"
+ "<title>Evolution Mail Display</title>\n"
+ "<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\" />\n"
+ "<style type=\"text/css\">\n"
+ " table th { color: #000; font-weight: bold; }\n"
+ "</style>\n"
+ "</head><body bgcolor=\"#%06x\">",
+ e_color_to_value ((GdkColor *)
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_BODY)));
+}
+
+EMailExtensionRegistry *
+e_mail_formatter_get_extension_registry (EMailFormatter *formatter)
+{
+ EMailFormatterClass * formatter_class;
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+ formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+ return E_MAIL_EXTENSION_REGISTRY (formatter_class->extension_registry);
+}
+
+guint32
+e_mail_formatter_get_text_format_flags (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), 0);
+
+ return E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags;
+}
+
+const GdkColor *
+e_mail_formatter_get_color (EMailFormatter *formatter,
+ EMailFormatterColorType type)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+ g_return_val_if_fail (type < E_MAIL_FORMATTER_NUM_COLOR_TYPES, NULL);
+
+ return &E_MAIL_FORMATTER_GET_CLASS (formatter)->colors[type];
+}
+
+void
+e_mail_formatter_set_color (EMailFormatter *formatter,
+ EMailFormatterColorType type,
+ const GdkColor *color)
+{
+ GdkColor *format_color;
+ const gchar *property_name;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (type < E_MAIL_FORMATTER_NUM_COLOR_TYPES);
+ g_return_if_fail (color != NULL);
+
+ format_color = &E_MAIL_FORMATTER_GET_CLASS (formatter)->colors[type];
+
+ if (gdk_color_equal (color, format_color))
+ return;
+
+ format_color->red = color->red;
+ format_color->green = color->green;
+ format_color->blue = color->blue;
+
+ switch (type) {
+ case E_MAIL_FORMATTER_COLOR_BODY:
+ property_name = "body-color";
+ break;
+ case E_MAIL_FORMATTER_COLOR_CITATION:
+ property_name = "citation-color";
+ break;
+ case E_MAIL_FORMATTER_COLOR_CONTENT:
+ property_name = "content-color";
+ break;
+ case E_MAIL_FORMATTER_COLOR_FRAME:
+ property_name = "frame-color";
+ break;
+ case E_MAIL_FORMATTER_COLOR_HEADER:
+ property_name = "header-color";
+ break;
+ case E_MAIL_FORMATTER_COLOR_TEXT:
+ property_name = "text-color";
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ g_object_notify (G_OBJECT (formatter), property_name);
+}
+
+void
+e_mail_formatter_set_style (EMailFormatter *formatter,
+ GtkStyle *style,
+ GtkStateType state)
+{
+ EMailFormatterClass *formatter_class;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (GTK_IS_STYLE (style));
+
+ formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+ g_return_if_fail (formatter_class->set_style != NULL);
+
+ formatter_class->set_style (formatter, style, state);
+}
+
+EMailImageLoadingPolicy
+e_mail_formatter_get_image_loading_policy (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), 0);
+
+ return formatter->priv->image_loading_policy;
+}
+
+void
+e_mail_formatter_set_image_loading_policy (EMailFormatter *formatter,
+ EMailImageLoadingPolicy policy)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ if (policy == formatter->priv->image_loading_policy)
+ return;
+
+ formatter->priv->image_loading_policy = policy;
+
+ g_object_notify (G_OBJECT (formatter), "image-loading-policy");
+}
+
+gboolean
+e_mail_formatter_get_mark_citations (EMailFormatter *formatter)
+{
+ guint32 flags;
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+ flags = E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags;
+
+ return ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0);
+}
+
+void
+e_mail_formatter_set_mark_citations (EMailFormatter *formatter,
+ gboolean mark_citations)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ if (mark_citations)
+ E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags |=
+ CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+ else
+ E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags &=
+ ~CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+
+ g_object_notify (G_OBJECT (formatter), "mark-citations");
+}
+
+gboolean
+e_mail_formatter_get_only_local_photos (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+ return formatter->priv->only_local_photos;
+}
+
+void
+e_mail_formatter_set_only_local_photos (EMailFormatter *formatter,
+ gboolean only_local_photos)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ formatter->priv->only_local_photos = only_local_photos;
+
+ g_object_notify (G_OBJECT (formatter), "only-local-photos");
+}
+
+gboolean
+e_mail_formatter_get_show_sender_photo (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+ return formatter->priv->show_sender_photo;
+}
+
+void
+e_mail_formatter_set_show_sender_photo (EMailFormatter *formatter,
+ gboolean show_sender_photo)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ formatter->priv->show_sender_photo = show_sender_photo;
+
+ g_object_notify (G_OBJECT (formatter), "show-sender-photo");
+}
+
+gboolean
+e_mail_formatter_get_show_real_date (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+ return formatter->priv->show_real_date;
+}
+
+void
+e_mail_formatter_set_show_real_date (EMailFormatter *formatter,
+ gboolean show_real_date)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ formatter->priv->show_real_date = show_real_date;
+
+ g_object_notify (G_OBJECT (formatter), "show-real-date");
+}
+
+gboolean
+e_mail_formatter_get_animate_images (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+ return formatter->priv->animate_images;
+}
+
+void
+e_mail_formatter_set_animate_images (EMailFormatter *formatter,
+ gboolean animate_images)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ formatter->priv->animate_images = animate_images;
+
+ g_object_notify (G_OBJECT (formatter), "animate-images");
+}
+
+const gchar *
+e_mail_formatter_get_charset (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+ return formatter->priv->charset;
+}
+
+void
+e_mail_formatter_set_charset (EMailFormatter *formatter,
+ const gchar *charset)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (charset && *charset);
+
+ if (formatter->priv->charset)
+ g_free (formatter->priv->charset);
+
+ formatter->priv->charset = g_strdup (charset);
+
+ g_object_notify (G_OBJECT (formatter), "charset");
+}
+
+const gchar *
+e_mail_formatter_get_default_charset (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+ return formatter->priv->default_charset;
+}
+
+void
+e_mail_formatter_set_default_charset (EMailFormatter *formatter,
+ const gchar *default_charset)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (default_charset && *default_charset);
+
+ if (formatter->priv->default_charset)
+ g_free (formatter->priv->default_charset);
+
+ formatter->priv->default_charset = g_strdup (default_charset);
+
+ g_object_notify (G_OBJECT (formatter), "default-charset");
+}
+
+/* note: also copied in em-mailer-prefs.c */
+static const struct {
+ const gchar *name;
+ guint32 flags;
+} default_headers[] = {
+ { N_("From"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+ { N_("Reply-To"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+ { N_("To"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+ { N_("Cc"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+ { N_("Bcc"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+ { N_("Subject"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+ { N_("Date"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+ { N_("Newsgroups"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+ { N_("Face"), 0 },
+};
+
+/**
+ * e_mail_formatter_get_headers:
+ * @formatter: an #EMailFormatter
+ *
+ * Returns list of currently set headers.
+ *
+ * Return Value: A #GQueue of headers which you should not modify or unref
+ */
+const GQueue *
+e_mail_formatter_get_headers (EMailFormatter *formatter)
+{
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+ return formatter->priv->header_list;
+}
+
+/**
+ * e_mail_formatter_clear_headers:
+ * @formatter: an #EMailFormatter
+ *
+ * Clear the list of headers to be displayed. This will force all headers to
+ * be shown.
+ **/
+void
+e_mail_formatter_clear_headers (EMailFormatter *formatter)
+{
+ EMailFormatterHeader *header;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ while ((header = g_queue_pop_head (formatter->priv->header_list)) != NULL) {
+ e_mail_formatter_header_free (header);
+ }
+}
+
+/**
+ * e_mail_formatter_set_default_headers:
+ * @formatter: an #EMailFormatter
+ *
+ * Clear the list of headers and sets the default ones, e.g. "To", "From", "Cc"
+ * "Subject", etc...
+ */
+void
+e_mail_formatter_set_default_headers (EMailFormatter *formatter)
+{
+ gint ii;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+ /* Set the default headers */
+ e_mail_formatter_clear_headers (formatter);
+ for (ii = 0; ii < G_N_ELEMENTS (default_headers); ii++) {
+ e_mail_formatter_add_header (
+ formatter, default_headers[ii].name, NULL,
+ default_headers[ii].flags);
+ }
+}
+
+/**
+ * e_mail_formatter_add_header:
+ * @formatter:
+ * @name: The name of the header, as it will appear during output.
+ * @value: Value of the header. Can be %NULL.
+ * @flags: EM_FORMAT_HEAD_* defines to control display attributes.
+ *
+ * Add a specific header to show. If any headers are set, they will
+ * be displayed in the order set by this function. Certain known
+ * headers included in this list will be shown using special
+ * formatting routines.
+ **/
+void
+e_mail_formatter_add_header (EMailFormatter *formatter,
+ const gchar *name,
+ const gchar *value,
+ guint32 flags)
+{
+ EMailFormatterHeader *h;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (name && *name);
+
+ h = e_mail_formatter_header_new (name, value);
+ h->flags = flags;
+ g_queue_push_tail (formatter->priv->header_list, h);
+}
+
+void
+e_mail_formatter_add_header_struct (EMailFormatter *formatter,
+ const EMailFormatterHeader *header)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (header && header->name);
+
+ e_mail_formatter_add_header (formatter, header->name, header->value, header->flags);
+}
+
+void e_mail_formatter_remove_header (EMailFormatter *formatter,
+ const gchar *name,
+ const gchar *value)
+{
+ GList *iter = NULL;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (name && *name);
+
+ iter = g_queue_peek_head_link (formatter->priv->header_list);
+ while (iter) {
+ EMailFormatterHeader *header = iter->data;
+
+ if (!header->value || !*header->value) {
+ GList *next = iter->next;
+ if (g_strcmp0 (name, header->name) == 0)
+ g_queue_delete_link (formatter->priv->header_list, iter);
+
+ iter = next;
+ continue;
+ }
+
+ if (value && *value) {
+ if ((g_strcmp0 (name, header->name) == 0) &&
+ (g_strcmp0 (value, header->value) == 0))
+ break;
+ } else {
+ if (g_strcmp0 (name, header->name) == 0)
+ break;
+ }
+
+ iter = iter->next;
+ }
+
+ if (iter) {
+ e_mail_formatter_header_free (iter->data);
+ g_queue_delete_link (formatter->priv->header_list, iter);
+ }
+}
+
+void
+e_mail_formatter_remove_header_struct (EMailFormatter *formatter,
+ const EMailFormatterHeader *header)
+{
+ g_return_if_fail (header != NULL);
+
+ e_mail_formatter_remove_header (formatter, header->name, header->value);
+}
+
+EMailFormatterHeader *
+e_mail_formatter_header_new (const gchar *name,
+ const gchar *value)
+{
+ EMailFormatterHeader *header;
+
+ g_return_val_if_fail (name && *name, NULL);
+
+ header = g_new0 (EMailFormatterHeader, 1);
+ header->name = g_strdup (name);
+ if (value && *value)
+ header->value = g_strdup (value);
+
+ return header;
+}
+
+void
+e_mail_formatter_header_free (EMailFormatterHeader *header)
+{
+ g_return_if_fail (header);
+
+ if (header->name) {
+ g_free (header->name);
+ header->name = NULL;
+ }
+
+ if (header->value) {
+ g_free (header->value);
+ header->value = NULL;
+ }
+
+ g_free (header);
+}