/*
* 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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see .
*
*/
#include "e-mail-formatter.h"
#include
#include
#include
#include
#include "e-mail-formatter-enumtypes.h"
#include "e-mail-formatter-extension.h"
#include "e-mail-formatter-utils.h"
#include "e-mail-part.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 {
GOutputStream *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_audio_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,
GOutputStream *stream,
GCancellable *cancellable)
{
GQueue queue = G_QUEUE_INIT;
GList *head, *link;
gchar *hdr;
const gchar *string;
hdr = e_mail_formatter_get_html_header (formatter);
g_output_stream_write_all (
stream, hdr, strlen (hdr), NULL, 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));
string = "