#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 */
while (tag = g_utf8_find_next_char (pos, NULL), tag != 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, "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, "