aboutsummaryrefslogtreecommitdiffstats
path: root/em-format/e-mail-formatter-text-html.c
diff options
context:
space:
mode:
Diffstat (limited to 'em-format/e-mail-formatter-text-html.c')
-rw-r--r--em-format/e-mail-formatter-text-html.c376
1 files changed, 376 insertions, 0 deletions
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..28fb2644de
--- /dev/null
+++ b/em-format/e-mail-formatter-text-html.c
@@ -0,0 +1,376 @@
+/*
+ * 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 "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#include <ctype.h>
+#include <string.h>
+
+static const gchar *formatter_mime_types[] = { "text/html", NULL };
+
+typedef struct _EMailFormatterTextHTML {
+ GObject parent;
+} EMailFormatterTextHTML;
+
+typedef struct _EMailFormatterTextHTMLClass {
+ GObjectClass parent_class;
+} EMailFormatterTextHTMLClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+ EMailFormatterTextHTML,
+ e_mail_formatter_text_html,
+ G_TYPE_OBJECT,
+ 0,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_MAIL_EXTENSION,
+ e_mail_formatter_mail_extension_interface_init)
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_MAIL_FORMATTER_EXTENSION,
+ e_mail_formatter_formatter_extension_interface_init));
+
+static gchar *
+get_tag (const gchar *utf8_string,
+ const gchar *tag_name,
+ gchar *opening,
+ gchar *closing)
+{
+ gchar *t;
+ gunichar c;
+ gboolean has_end;
+
+ 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 == '<')
+ break;
+
+ t = g_utf8_find_next_char (t, NULL);
+ }
+
+ 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 g_strndup (opening, closing - opening + 1);
+
+ 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 g_strndup (opening, closing - opening + 1);
+}
+
+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) {
+ /* FORMATTER FIXME: Shouldn't we have some extra method for
+ * BASE64 and QP decoding?? */
+ 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);
+
+ tags = NULL;
+ pos = string->str;
+ valid = FALSE;
+
+ if (!g_utf8_validate (string->str, -1, NULL)) {
+ /* FIXME - What do we do if the string is not UTF-8 valid? */
+ }
+
+ 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);
+
+ if (tags)
+ printf("\n\n**%s**\n\n", (gchar *) tags->data);
+
+ /* Something's wrong, let's write the entire HTML and hope
+ * that WebKit can handle it */
+ if (!valid) {
+ EMailFormatterContext c = {
+ .folder = context->folder,
+ .message = context->message,
+ .message_uid = context->message_uid,
+ .parts = context->parts,
+ .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) {
+ 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;
+ }
+ }
+
+ if (valid)
+ g_string_truncate (string, tag - string->str);
+
+ camel_stream_write_string (stream, string->str, cancellable, NULL);
+
+ g_string_free (string, TRUE);
+ } else {
+ gchar *uri, *str;
+
+ uri = e_mail_part_build_uri (
+ context->folder, context->message_uid,
+ "part_id", G_TYPE_STRING, part->id,
+ "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+ NULL);
+
+ str = g_strdup_printf (
+ "<div class=\"part-container-nostyle\">"
+ "<iframe width=\"100%%\" height=\"10\" "
+ " frameborder=\"0\" src=\"%s\" "
+ " id=\"%s.iframe\" "
+ " style=\"border: 1px solid #%06x; background-color: #%06x;\">"
+ "</iframe>"
+ "</div>",
+ uri,
+ part->id,
+ e_color_to_value ((GdkColor *)
+ e_mail_formatter_get_color (
+ formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+ e_color_to_value ((GdkColor *)
+ 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 const gchar *
+emfe_text_html_get_display_name (EMailFormatterExtension *extension)
+{
+ return _("HTML");
+}
+
+static const gchar *
+emfe_text_html_get_description (EMailFormatterExtension *extension)
+{
+ return _("Format part as HTML");
+}
+
+static const gchar **
+emfe_text_html_mime_types (EMailExtension *extension)
+{
+ return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_text_html_class_init (EMailFormatterTextHTMLClass *klass)
+{
+ e_mail_formatter_text_html_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+ iface->format = emfe_text_html_format;
+ iface->get_display_name = emfe_text_html_get_display_name;
+ iface->get_description = emfe_text_html_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+ iface->mime_types = emfe_text_html_mime_types;
+}
+
+static void
+e_mail_formatter_text_html_init (EMailFormatterTextHTML *formatter)
+{
+
+}