Commit 5b834056 authored by Dan Vrátil's avatar Dan Vrátil
Browse files

Mail formatter rewrite

All mail-parsing and formatting code has been moved to em-format.
Parsing is handeled by EMailParser class, formatting by EMailFormatter.
Both classes have registry which hold extensions - simple classes
that do actual parsing and formatting. Each supported mime-type
has it's own parser and formatter extension class.
parent 26a4f241
......@@ -40,11 +40,15 @@
#include <libevolution-utils/e-alert-dialog.h>
#include <e-util/e-dialog-utils.h>
#include <e-util/e-util-private.h>
#include <em-format/em-format.h>
#include <em-format/em-format-quote.h>
#include "e-composer-private.h"
#include <em-format/e-mail-part.h>
#include <em-format/e-mail-parser.h>
#include <em-format/e-mail-formatter-quote.h>
#include <shell/e-shell.h>
typedef struct _AsyncContext AsyncContext;
struct _AsyncContext {
......@@ -179,49 +183,50 @@ static gchar *
emcu_part_to_html (CamelSession *session,
CamelMimePart *part,
gssize *len,
EMFormat *source,
GCancellable *cancellable)
{
EMFormatQuote *emfq;
CamelStreamMem *mem;
GByteArray *buf;
gchar *text;
EMFormatParserInfo p_info = { 0 };
EMFormatWriterInfo w_info = { 0 };
EMailParser *parser;
EMailFormatter *formatter;
EMailPartList *part_list;
GString *part_id;
EShell *shell;
GtkWindow *window;
shell = e_shell_get_default ();
window = e_shell_get_active_window (shell);
buf = g_byte_array_new ();
mem = (CamelStreamMem *) camel_stream_mem_new ();
camel_stream_mem_set_byte_array (mem, buf);
emfq = em_format_quote_new (
session, NULL, (CamelStream *) mem,
EM_FORMAT_QUOTE_KEEP_SIG);
em_format_set_composer ((EMFormat *) emfq, TRUE);
if (source) {
/* Copy over things we can, other things are internal.
* XXX Perhaps need different api than 'clone'. */
if (em_format_get_default_charset (source))
em_format_set_default_charset (
(EMFormat *) emfq, em_format_get_default_charset (source));
if (em_format_get_charset (source))
em_format_set_charset (
(EMFormat *) emfq, em_format_get_charset (source));
}
part_list = e_mail_part_list_new ();
part_id = g_string_sized_new (0);
em_format_parse_part (EM_FORMAT (emfq), part, part_id, &p_info, cancellable);
em_format_write (EM_FORMAT (emfq), CAMEL_STREAM (mem), &w_info, cancellable);
parser = e_mail_parser_new (session);
part_list->list = e_mail_parser_parse_part (parser, part, part_id, cancellable);
g_string_free (part_id, TRUE);
g_object_unref (parser);
formatter = e_mail_formatter_quote_new (NULL, E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG);
e_mail_formatter_set_style (formatter,
gtk_widget_get_style (GTK_WIDGET (window)),
gtk_widget_get_state (GTK_WIDGET (window)));
g_object_unref (emfq);
e_mail_formatter_format_sync (
formatter, part_list, (CamelStream *) mem,
0, E_MAIL_FORMATTER_MODE_PRINTING, cancellable);
g_object_unref (formatter);
g_object_unref (part_list);
camel_stream_write((CamelStream *) mem, "", 1, cancellable, NULL);
g_object_unref (mem);
text = (gchar *) buf->data;
if (len)
*len = buf->len-1;
*len = buf->len - 1;
g_byte_array_free (buf, FALSE);
return text;
......@@ -2711,7 +2716,7 @@ handle_multipart_signed (EMsgComposer *composer,
gssize length;
html = emcu_part_to_html (
session, mime_part, &length, NULL, cancellable);
session, mime_part, &length, cancellable);
e_msg_composer_set_pending_body (composer, html, length);
} else {
e_msg_composer_attach (composer, mime_part);
......@@ -2799,7 +2804,7 @@ handle_multipart_encrypted (EMsgComposer *composer,
gssize length;
html = emcu_part_to_html (
session, mime_part, &length, NULL, cancellable);
session, mime_part, &length, cancellable);
e_msg_composer_set_pending_body (composer, html, length);
} else {
e_msg_composer_attach (composer, mime_part);
......@@ -2880,7 +2885,7 @@ handle_multipart_alternative (EMsgComposer *composer,
gssize length;
html = emcu_part_to_html (
session, text_part, &length, NULL, cancellable);
session, text_part, &length, cancellable);
e_msg_composer_set_pending_body (composer, html, length);
}
}
......@@ -2948,7 +2953,7 @@ handle_multipart (EMsgComposer *composer,
/* Since the first part is not multipart/alternative,
* this must be the body. */
html = emcu_part_to_html (
session, mime_part, &length, NULL, cancellable);
session, mime_part, &length, cancellable);
e_msg_composer_set_pending_body (composer, html, length);
} else if (camel_mime_part_get_content_id (mime_part) ||
camel_mime_part_get_content_location (mime_part)) {
......@@ -3325,7 +3330,7 @@ e_msg_composer_new_with_message (EShell *shell,
html = emcu_part_to_html (
session, CAMEL_MIME_PART (message),
&length, NULL, cancellable);
&length, cancellable);
e_msg_composer_set_pending_body (composer, html, length);
}
......
......@@ -58,13 +58,13 @@ img.navigable {
}
.part-container {
width: 100%;
height: 100%;
background: #FFF;
margin-top: 2px;
margin-bottom: 3px;
border-width: 1px;
border-style: solid;
right: 0;
}
.part-container-inner-margin {
......
......@@ -3,33 +3,118 @@ emformatincludedir = $(privincludedir)/em-format
privsolib_LTLIBRARIES = libemformat.la
emformatinclude_HEADERS = \
em-format.h \
em-format-quote.h \
em-inline-filter.h \
em-stripsig-filter.h
e-mail-extension-registry.h \
e-mail-extension.h \
e-mail-formatter-extension.h \
e-mail-formatter.h \
e-mail-formatter-print.h \
e-mail-formatter-quote.h \
e-mail-formatter-utils.h \
e-mail-inline-filter.h \
e-mail-parser-extension.h \
e-mail-parser.h \
e-mail-part.h \
e-mail-part-attachment.h \
e-mail-part-attachment-bar.h \
e-mail-part-list.h \
e-mail-part-utils.h \
e-mail-stripsig-filter.h
libemformat_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir) \
-I$(top_srcdir)/em-format \
-I$(top_srcdir)/smime/lib \
-I$(top_srcdir)/smime/gui \
-I$(top_srcdir)/widgets \
$(EVOLUTION_DATA_SERVER_CFLAGS) \
$(GNOME_PLATFORM_CFLAGS) \
$(LIBSOUP_CFLAGS)
$(LIBSOUP_CFLAGS) \
-DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
-DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\"
if ENABLE_SMIME
SMIME_EXTENSIONS = e-mail-parser-application-smime.c
endif
libemformat_la_SOURCES = \
$(emformatinclude_HEADERS) \
em-format.c \
em-format-quote.c \
em-inline-filter.c \
em-stripsig-filter.c
$(emformatextensions_SOURCES) \
e-mail-extension-registry.c \
e-mail-extension.c \
e-mail-inline-filter.c \
e-mail-format-extensions.c \
e-mail-formatter.c \
e-mail-formatter-print.c \
e-mail-formatter-quote.c \
e-mail-formatter-utils.c \
e-mail-formatter-attachment.c \
e-mail-formatter-attachment-bar.c \
e-mail-formatter-error.c \
e-mail-formatter-extension.c \
e-mail-formatter-headers.c \
e-mail-formatter-image.c \
e-mail-formatter-message-rfc822.c \
e-mail-formatter-secure-button.c \
e-mail-formatter-source.c \
e-mail-formatter-text-enriched.c \
e-mail-formatter-text-html.c \
e-mail-formatter-text-plain.c \
e-mail-formatter-print-headers.c \
e-mail-formatter-quote-attachment.c \
e-mail-formatter-quote-headers.c \
e-mail-formatter-quote-message-rfc822.c \
e-mail-formatter-quote-text-enriched.c \
e-mail-formatter-quote-text-html.c \
e-mail-formatter-quote-text-plain.c \
e-mail-parser-extension.c \
e-mail-parser.c \
e-mail-parser-application-mbox.c \
e-mail-parser-attachment-bar.c \
e-mail-parser-headers.c \
e-mail-parser-image.c \
e-mail-parser-inlinepgp-encrypted.c \
e-mail-parser-inlinepgp-signed.c \
e-mail-parser-message.c \
e-mail-parser-message-deliverystatus.c \
e-mail-parser-message-external.c \
e-mail-parser-message-rfc822.c \
e-mail-parser-multipart-alternative.c \
e-mail-parser-multipart-appledouble.c \
e-mail-parser-multipart-digest.c \
e-mail-parser-multipart-encrypted.c \
e-mail-parser-multipart-mixed.c \
e-mail-parser-multipart-related.c \
e-mail-parser-multipart-signed.c \
e-mail-parser-secure-button.c \
e-mail-parser-source.c \
e-mail-parser-text-enriched.c \
e-mail-parser-text-html.c \
e-mail-parser-text-plain.c \
e-mail-part.c \
e-mail-part-attachment.c \
e-mail-part-list.c \
e-mail-part-utils.c \
e-mail-stripsig-filter.c \
$(SMIME_EXTENSIONS)
libemformat_la_LDFLAGS = -avoid-version $(NO_UNDEFINED)
if ENABLE_SMIME
SMIME_LIBS = \
$(top_builddir)/smime/lib/libessmime.la \
$(top_builddir)/smime/gui/libevolution-smime.la
endif
libemformat_la_LIBADD = \
$(top_builddir)/e-util/libeutil.la \
$(top_builddir)/shell/libeshell.la \
$(top_builddir)/libemail-utils/libemail-utils.la \
$(top_builddir)/libemail-engine/libemail-engine.la \
$(EVOLUTION_DATA_SERVER_LIBS) \
$(GNOME_PLATFORM_LIBS) \
$(LIBSOUP_LIBS)
$(LIBSOUP_LIBS) \
$(SMIME_LIBS)
-include $(top_srcdir)/git.mk
/*
* 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 <glib-object.h>
#include "e-mail-extension-registry.h"
#include "e-mail-extension.h"
#include "e-mail-format-extensions.h"
#include <libebackend/libebackend.h>
#include <camel/camel.h>
#include <glib-object.h>
#include <string.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;
};
static gconstpointer parent_class = 0;
G_DEFINE_ABSTRACT_TYPE (
EMailExtensionRegistry,
e_mail_extension_registry,
G_TYPE_OBJECT)
/**
* EMailExtensionRegistry:
*
* The #EMailExtensionRegistry is an abstract class representing a registry
* for #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
mail_extension_registry_finalize (GObject *object)
{
EMailExtensionRegistry *reg = E_MAIL_EXTENSION_REGISTRY (object);
if (reg->priv->table) {
g_hash_table_destroy (reg->priv->table);
reg->priv->table = NULL;
}
/* Chain up to parent's finalize() */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
void
e_mail_extension_registry_class_init (EMailExtensionRegistryClass *klass)
{
GObjectClass *object_class;
g_type_class_add_private (klass, sizeof (EMailExtensionRegistryPrivate));
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = mail_extension_registry_finalize;
}
static void
destroy_queue (GQueue *queue)
{
g_queue_free_full (queue, g_object_unref);
}
void
e_mail_extension_registry_init (EMailExtensionRegistry *reg)
{
reg->priv = E_MAIL_EXTENSION_REGISTRY_GET_PRIVATE (reg);
reg->priv->table = g_hash_table_new_full (
g_str_hash, g_str_equal, NULL, (GDestroyNotify) destroy_queue);
}
/**
* e_mail_extension_registry_add_extension:
* @reg: An #EMailExtensionRegistry
* @extension: An #EMailExtension
*
* Registrys the @extension as a handler for all mime-types that it is able
* to handle.
*/
void
e_mail_extension_registry_add_extension (EMailExtensionRegistry *reg,
EMailExtension *extension)
{
gint i;
const gchar **types;
g_return_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg));
g_return_if_fail (E_IS_MAIL_EXTENSION (extension));
/* One reference per extension is enough */
g_object_ref (extension);
types = e_mail_extension_get_mime_types (extension);
for (i = 0; types && types[i]; i++) {
GQueue *queue;
queue = g_hash_table_lookup (reg->priv->table, types[i]);
if (!queue) {
queue = g_queue_new ();
g_queue_push_head (queue, extension);
g_hash_table_insert (reg->priv->table, (gchar *) types[i], queue);
} else {
g_queue_push_head (queue, extension);
}
if (camel_debug ("emformat:registry")) {
printf("Added extension '%s' for type '%s'\n",
G_OBJECT_TYPE_NAME (extension), types[i]);
}
}
}
/**
* e_mail_extension_registry_remove_extension:
* @reg: An #EMailExtensionRegistry
* @extension: An #EMailExtension
*
* Removes @extension from the registry.
*/
void
e_mail_extension_registry_remove_extension (EMailExtensionRegistry *reg,
EMailExtension *extension)
{
gint i;
const gchar **types;
g_return_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg));
g_return_if_fail (E_IS_MAIL_EXTENSION (extension));
types = e_mail_extension_get_mime_types (extension);
for (i = 0; types && types[i]; i++) {
GQueue *queue;
queue = g_hash_table_lookup (reg->priv->table, types[i]);
if (!queue) {
i++;
continue;
}
g_queue_remove (queue, extension);
if (camel_debug ("emformat:registry")) {
printf("Removed extension '%s' from type '%s'\n",
G_OBJECT_TYPE_NAME (extension), types[i]);
}
}
g_object_unref (extension);
}
/**
* e_mail_extension_registry_get_for_mime_type:
* @reg: An #EMailExtensionRegistry
* @mime_type: A string with mime-type to look up
*
* Tries to lookup list of #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 *reg,
const gchar *mime_type)
{
g_return_val_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg), NULL);
g_return_val_if_fail (mime_type && *mime_type, NULL);
return g_hash_table_lookup (reg->priv->table, mime_type);
}
/**
* e_mail_extension_registry_get_fallback:
* @reg: An #EMailExtensionRegistry
* @mime_type: A string with mime-type whose fallback to look up
*
* Tries to lookup fallback parsers for given mime type. For instance, for
* multipart/alternative, it will try to lookup multipart/ * parser.
*
* Return Value: Returns #QGueue of #EMailExtension<!-//>>s or %NULL when there
* are no extensions registryed for the fallback type.
*/
GQueue *
e_mail_extension_registry_get_fallback (EMailExtensionRegistry *reg,
const gchar *mime_type)
{
gchar *s, *type;
gsize len;
GQueue *parsers;
g_return_val_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg), NULL);
g_return_val_if_fail (mime_type && *mime_type, NULL);
s = strchr (mime_type, '/');
len = s - mime_type;
s = g_alloca (len);
strncpy (s, mime_type, len);
type = g_ascii_strdown (s, len);
s = g_strdup_printf ("%s/*", type);
parsers = g_hash_table_lookup (reg->priv->table, s);
g_free (type);
g_free (s);
return parsers;
}
/******************************************************************************/
static void e_mail_parser_extension_registry_extensible_interface_init (EExtensibleInterface *iface);
G_DEFINE_TYPE_WITH_CODE (
EMailParserExtensionRegistry,
e_mail_parser_extension_registry,
E_TYPE_MAIL_EXTENSION_REGISTRY,
G_IMPLEMENT_INTERFACE (
E_TYPE_EXTENSIBLE,
e_mail_parser_extension_registry_extensible_interface_init));
static void
e_mail_parser_extension_registry_init (EMailParserExtensionRegistry *parser_ereg)
{
}
static void
e_mail_parser_extension_registry_class_init (EMailParserExtensionRegistryClass *klass)
{
e_mail_parser_extension_registry_parent_class = g_type_class_peek_parent (klass);
}
static void
e_mail_parser_extension_registry_extensible_interface_init (EExtensibleInterface *interface)
{
}
/******************************************************************************/
static void e_mail_formatter_extension_registry_extensible_interface_init (EExtensibleInterface *iface);
G_DEFINE_TYPE_WITH_CODE (
EMailFormatterExtensionRegistry,
e_mail_formatter_extension_registry,
E_TYPE_MAIL_EXTENSION_REGISTRY,
G_IMPLEMENT_INTERFACE (
E_TYPE_EXTENSIBLE,
e_mail_formatter_extension_registry_extensible_interface_init));
static void
e_mail_formatter_extension_registry_init (EMailFormatterExtensionRegistry *formatter_ereg)
{
}
static void
e_mail_formatter_extension_registry_class_init (EMailFormatterExtensionRegistryClass *klass)
{
e_mail_formatter_extension_registry_parent_class = g_type_class_peek_parent (klass);
}
static void
e_mail_formatter_extension_registry_extensible_interface_init (EExtensibleInterface *interface)
{
}
/*
* 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 <em-format/e-mail-extension.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 _EMailExtensionRegistryClass {
GObjectClass parent_class;
};
struct _EMailExtensionRegistry {