em-format: Format text/markdown with cmark library

Use the cmark library to format text/markdown into HTML and show
it as such, instead of the raw markdown. The dependency on cmark
is optional and can be turned off in the configure time.

Related to https://gitlab.gnome.org/GNOME/evolution/-/issues/449
This commit is contained in:
Milan Crha
2021-09-23 18:05:12 +02:00
parent c99f1c8c7b
commit 02e762d964
8 changed files with 314 additions and 0 deletions
+13
View File
@@ -705,6 +705,19 @@ if(WITH_GLADE_CATALOG)
pkg_check_modules_for_option(WITH_GLADE_CATALOG "Glade 3 catalog files" GLADEUI gladeui-2.0>=${gladeui_minimum_version})
endif(WITH_GLADE_CATALOG)
# ******************************
# cmark for CommonMarkdown
# ******************************
add_printable_option(ENABLE_MARKDOWN "Enable markdown support" ON)
if(ENABLE_MARKDOWN)
pkg_check_modules_for_option(ENABLE_MARKDOWN "markdown support" MARKDOWN
libcmark
)
set(HAVE_MARKDOWN ON)
endif(ENABLE_MARKDOWN)
# Generate the ${PROJECT_NAME}-config.h file
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.in ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-config.h)
+3
View File
@@ -119,3 +119,6 @@
/* D-Bus service name of the evolution-source-registry, as provided by evolution-data-server-1.2.pc */
#define EDS_SOURCES_DBUS_SERVICE_NAME "@EDS_SOURCES_DBUS_SERVICE_NAME@"
/* Define if markdown support is enabled */
#cmakedefine HAVE_MARKDOWN 1
+1
View File
@@ -141,6 +141,7 @@ src/em-format/e-mail-formatter-secure-button.c
src/em-format/e-mail-formatter-source.c
src/em-format/e-mail-formatter-text-enriched.c
src/em-format/e-mail-formatter-text-html.c
src/em-format/e-mail-formatter-text-markdown.c
src/em-format/e-mail-formatter-text-plain.c
src/em-format/e-mail-formatter-utils.c
src/em-format/e-mail-parser-application-mbox.c
+9
View File
@@ -78,6 +78,13 @@ if(ENABLE_SMIME)
)
endif(ENABLE_SMIME)
if(ENABLE_MARKDOWN)
list(APPEND SOURCES
e-mail-formatter-text-markdown.c
e-mail-parser-text-markdown.c
)
endif(ENABLE_MARKDOWN)
set(HEADERS
e-mail-extension-registry.h
e-mail-formatter-extension.h
@@ -130,12 +137,14 @@ target_include_directories(evolution-mail-formatter PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${EVOLUTION_DATA_SERVER_INCLUDE_DIRS}
${GNOME_PLATFORM_INCLUDE_DIRS}
${MARKDOWN_INCLUDE_DIRS}
)
target_link_libraries(evolution-mail-formatter
${DEPENDENCIES}
${EVOLUTION_DATA_SERVER_LDFLAGS}
${GNOME_PLATFORM_LDFLAGS}
${MARKDOWN_LDFLAGS}
)
install(TARGETS evolution-mail-formatter
@@ -0,0 +1,186 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "evolution-config.h"
#include <cmark.h>
#include <glib/gi18n-lib.h>
#include <e-util/e-util.h>
#include "e-mail-formatter-extension.h"
#include "e-mail-inline-filter.h"
#include "e-mail-part-utils.h"
typedef EMailFormatterExtension EMailFormatterTextMarkdown;
typedef EMailFormatterExtensionClass EMailFormatterTextMarkdownClass;
GType e_mail_formatter_text_markdown_get_type (void);
G_DEFINE_TYPE (EMailFormatterTextMarkdown, e_mail_formatter_text_markdown, E_TYPE_MAIL_FORMATTER_EXTENSION)
static const gchar *formatter_mime_types[] = {
"text/markdown",
NULL
};
static gboolean
emfe_text_markdown_format (EMailFormatterExtension *extension,
EMailFormatter *formatter,
EMailFormatterContext *context,
EMailPart *part,
GOutputStream *stream,
GCancellable *cancellable)
{
if (g_cancellable_is_cancelled (cancellable))
return FALSE;
if ((context->mode == E_MAIL_FORMATTER_MODE_RAW) ||
(context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) {
CamelMimePart *mime_part;
CamelDataWrapper *dw;
GOutputStream *output_stream;
gchar *html;
mime_part = e_mail_part_ref_mime_part (part);
dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
if (dw == NULL) {
g_object_unref (mime_part);
return FALSE;
}
output_stream = g_memory_output_stream_new_resizable ();
e_mail_formatter_format_text (formatter, part, output_stream, cancellable);
g_output_stream_flush (output_stream, cancellable, NULL);
html = cmark_markdown_to_html ((const gchar *) g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output_stream)),
g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (output_stream)),
CMARK_OPT_VALIDATE_UTF8);
g_object_unref (output_stream);
g_object_unref (mime_part);
if (html) {
const gchar *string;
if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
string = e_mail_formatter_get_sub_html_header (formatter);
g_output_stream_write_all (
stream, string, strlen (string),
NULL, cancellable, NULL);
/* No need for body margins within <iframe> */
string = "<style>body{ margin: 0; }</style>";
g_output_stream_write_all (
stream, string, strlen (string),
NULL, cancellable, NULL);
}
string =
"<div class=\"part-container "
"-e-web-view-background-color -e-web-view-text-color\" "
"style=\"border: none; padding: 8px; margin: 0;\">";
g_output_stream_write_all (
stream, string, strlen (string),
NULL, cancellable, NULL);
g_output_stream_write_all (stream, html, strlen (html), NULL, cancellable, NULL);
g_free (html);
string = "</div>\n";
g_output_stream_write_all (
stream, string, strlen (string),
NULL, cancellable, NULL);
if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
string = "</body></html>";
g_output_stream_write_all (
stream, string, strlen (string),
NULL, cancellable, NULL);
}
return TRUE;
}
return FALSE;
} else {
CamelFolder *folder;
const gchar *message_uid;
gchar *uri, *str;
const gchar *default_charset, *charset;
folder = e_mail_part_list_get_folder (context->part_list);
message_uid = e_mail_part_list_get_message_uid (context->part_list);
default_charset = e_mail_formatter_get_default_charset (formatter);
charset = e_mail_formatter_get_charset (formatter);
if (!default_charset)
default_charset = "";
if (!charset)
charset = "";
uri = e_mail_part_build_uri (
folder, message_uid,
"part_id", G_TYPE_STRING, e_mail_part_get_id (part),
"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
"formatter_default_charset", G_TYPE_STRING, default_charset,
"formatter_charset", G_TYPE_STRING, charset,
NULL);
str = g_strdup_printf (
"<div class=\"part-container-nostyle\" >"
"<iframe width=\"100%%\" height=\"10\""
" id=\"%s.iframe\" name=\"%s\" "
" frameborder=\"0\" src=\"%s\" "
" class=\"-e-mail-formatter-frame-color %s"
" -e-web-view-text-color\" >"
"</iframe>"
"</div>",
e_mail_part_get_id (part),
e_mail_part_get_id (part),
uri,
e_mail_part_get_frame_security_style (part));
g_output_stream_write_all (
stream, str, strlen (str),
NULL, cancellable, NULL);
g_free (str);
g_free (uri);
}
return TRUE;
}
static void
e_mail_formatter_text_markdown_class_init (EMailFormatterExtensionClass *class)
{
class->display_name = _("Markdown Text");
class->description = _("Format part as markdown text");
class->mime_types = formatter_mime_types;
class->priority = G_PRIORITY_LOW;
class->format = emfe_text_markdown_format;
}
static void
e_mail_formatter_text_markdown_init (EMailFormatterExtension *extension)
{
}
+8
View File
@@ -15,6 +15,8 @@
*
*/
#include "evolution-config.h"
#include "e-mail-formatter.h"
#include <string.h>
@@ -72,6 +74,9 @@ 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);
#ifdef HAVE_MARKDOWN
GType e_mail_formatter_text_markdown_get_type (void);
#endif
static gpointer e_mail_formatter_parent_class = 0;
@@ -561,6 +566,9 @@ e_mail_formatter_base_init (EMailFormatterClass *class)
g_type_ensure (e_mail_formatter_text_enriched_get_type ());
g_type_ensure (e_mail_formatter_text_html_get_type ());
g_type_ensure (e_mail_formatter_text_plain_get_type ());
#ifdef HAVE_MARKDOWN
g_type_ensure (e_mail_formatter_text_markdown_get_type ());
#endif
class->extension_registry = g_object_new (
E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, NULL);
@@ -0,0 +1,88 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "evolution-config.h"
#include "e-mail-parser-extension.h"
#include "e-mail-part-utils.h"
typedef EMailParserExtension EMailParserTextMarkdown;
typedef EMailParserExtensionClass EMailParserTextMarkdownClass;
GType e_mail_parser_text_markdown_get_type (void);
G_DEFINE_TYPE (EMailParserTextMarkdown, e_mail_parser_text_markdown, E_TYPE_MAIL_PARSER_EXTENSION)
static const gchar *parser_mime_types[] = {
"text/markdown",
NULL
};
static gboolean
empe_text_markdown_parse (EMailParserExtension *extension,
EMailParser *parser,
CamelMimePart *part,
GString *part_id,
GCancellable *cancellable,
GQueue *out_mail_parts)
{
CamelContentType *type;
EMailPart *mail_part;
GQueue work_queue = G_QUEUE_INIT;
gint s_len = part_id->len;
gchar *mime_type;
gboolean is_attachment;
if (!camel_medium_get_content ((CamelMedium *) part))
return FALSE;
is_attachment = e_mail_part_is_attachment (part);
type = camel_mime_part_get_content_type (part);
if (!camel_content_type_is (type, "text", "markdown"))
return FALSE;
g_string_append_printf (part_id, ".markdown_text.%d", 0);
mail_part = e_mail_part_new (part, part_id->str);
mime_type = camel_content_type_simple (type);
e_mail_part_set_mime_type (mail_part, mime_type);
g_free (mime_type);
g_string_truncate (part_id, s_len);
g_queue_push_tail (&work_queue, mail_part);
if (is_attachment)
e_mail_parser_wrap_as_attachment (parser, part, part_id, &work_queue);
e_queue_transfer (&work_queue, out_mail_parts);
return TRUE;
}
static void
e_mail_parser_text_markdown_class_init (EMailParserExtensionClass *class)
{
class->mime_types = parser_mime_types;
class->priority = G_PRIORITY_LOW;
class->parse = empe_text_markdown_parse;
}
static void
e_mail_parser_text_markdown_init (EMailParserExtension *extension)
{
}
+6
View File
@@ -76,6 +76,9 @@ GType e_mail_parser_text_plain_get_type (void);
#ifdef ENABLE_SMIME
GType e_mail_parser_application_smime_get_type (void);
#endif
#ifdef HAVE_MARKDOWN
GType e_mail_parser_text_markdown_get_type (void);
#endif
static gpointer parent_class;
@@ -323,6 +326,9 @@ e_mail_parser_base_init (EMailParserClass *class)
#ifdef ENABLE_SMIME
g_type_ensure (e_mail_parser_application_smime_get_type ());
#endif
#ifdef HAVE_MARKDOWN
g_type_ensure (e_mail_parser_text_markdown_get_type ());
#endif
class->extension_registry = g_object_new (
E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, NULL);