diff --git a/src/em-format/e-mail-formatter-utils.c b/src/em-format/e-mail-formatter-utils.c
index abd5155..50dae71 100644
--- a/src/em-format/e-mail-formatter-utils.c
+++ b/src/em-format/e-mail-formatter-utils.c
@@ -549,71 +549,136 @@ e_mail_formatter_format_security_header (EMailFormatter *formatter,
EMailPart *part,
guint32 flags)
{
- const gchar* part_id;
- gchar* part_id_prefix;
- GString* tmp;
+ struct _validity_flags {
+ guint32 flags;
+ const gchar *description_complete;
+ const gchar *description_partial;
+ } validity_flags[] = {
+ { E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SIGNED, N_("GPG signed"), N_("partially GPG signed") },
+ { E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_ENCRYPTED, N_("GPG encrypted"), N_("partially GPG encrypted") },
+ { E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_SIGNED, N_("S/MIME signed"), N_("partially S/MIME signed") },
+ { E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_ENCRYPTED, N_("S/MIME encrypted"), N_("partially S/MIME encrypted") }
+ };
+ const gchar *part_id;
+ gchar *part_id_prefix;
GQueue queue = G_QUEUE_INIT;
GList *head, *link;
+ guint32 check_valid_flags = 0;
+ gint part_id_prefix_len;
+ gboolean is_partial = FALSE;
+ guint ii;
g_return_if_fail (E_IS_MAIL_PART_HEADERS (part));
/* Get prefix of this PURI */
part_id = e_mail_part_get_id (part);
part_id_prefix = g_strndup (part_id, g_strrstr (part_id, ".") - part_id);
-
- /* Add encryption/signature header */
- tmp = g_string_new ("");
+ part_id_prefix_len = strlen (part_id_prefix);
e_mail_part_list_queue_parts (context->part_list, NULL, &queue);
head = g_queue_peek_head_link (&queue);
- /* Find first secured part. */
- for (link = head; link != NULL; link = g_list_next(link)) {
+ /* Ignore the main message, the headers and the end parts */
+ #define should_skip_part(_id) \
+ (g_strcmp0 (_id, part_id_prefix) == 0 || \
+ (_id && g_str_has_suffix (_id, ".rfc822.end")) || \
+ (_id && strlen (_id) == part_id_prefix_len + 8 /* strlen (".headers") */ && \
+ g_strcmp0 (_id + part_id_prefix_len, ".headers") == 0))
+
+ /* Check parts for this ID. */
+ for (link = head; link != NULL; link = g_list_next (link)) {
EMailPart *mail_part = link->data;
+ const gchar *id = e_mail_part_get_id (mail_part);
- if (!e_mail_part_has_validity (mail_part))
+ if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix))
continue;
- if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix))
+ if (should_skip_part (id))
continue;
- if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SIGNED)) {
- g_string_append (tmp, _("GPG signed"));
+ if (!e_mail_part_has_validity (mail_part)) {
+ /* A part without validity, thus it's partially signed/encrypted */
+ is_partial = TRUE;
+ } else {
+ guint32 validies = 0;
+ for (ii = 0; ii < G_N_ELEMENTS (validity_flags); ii++) {
+ if (e_mail_part_get_validity (mail_part, validity_flags[ii].flags))
+ validies |= validity_flags[ii].flags;
+ }
+ check_valid_flags |= validies;
}
- if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_ENCRYPTED)) {
- if (tmp->len > 0)
- g_string_append (tmp, ", ");
- g_string_append (tmp, _("GPG encrypted"));
- }
+ /* Do not traverse sub-messages */
+ if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822") &&
+ !g_str_equal (e_mail_part_get_id (mail_part), part_id_prefix))
+ link = e_mail_formatter_find_rfc822_end_iter (link);
+ }
+
+ if (check_valid_flags) {
+ GString *tmp;
+
+ if (!is_partial) {
+ for (link = head; link != NULL && !is_partial; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+ const gchar *id = e_mail_part_get_id (mail_part);
- if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_SIGNED)) {
- if (tmp->len > 0)
- g_string_append (tmp, ", ");
- g_string_append (tmp, _("S/MIME signed"));
+ if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix))
+ continue;
+
+ if (should_skip_part (id))
+ continue;
+
+ if (!e_mail_part_has_validity (mail_part)) {
+ /* A part without validity, thus it's partially signed/encrypted */
+ is_partial = TRUE;
+ break;
+ }
+
+ is_partial = !e_mail_part_get_validity (mail_part, check_valid_flags);
+
+ /* Do not traverse sub-messages */
+ if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822") &&
+ !g_str_equal (e_mail_part_get_id (mail_part), part_id_prefix))
+ link = e_mail_formatter_find_rfc822_end_iter (link);
+ }
}
- if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_ENCRYPTED)) {
- if (tmp->len > 0)
- g_string_append (tmp, ", ");
- g_string_append (tmp, _("S/MIME encrypted"));
+ /* Add encryption/signature header */
+ tmp = g_string_new ("");
+
+ for (link = head; link; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+ const gchar *id = e_mail_part_get_id (mail_part);
+
+ if (!e_mail_part_has_validity (mail_part) ||
+ !e_mail_part_id_has_prefix (mail_part, part_id_prefix))
+ continue;
+
+ if (should_skip_part (id))
+ continue;
+
+ for (ii = 0; ii < G_N_ELEMENTS (validity_flags); ii++) {
+ if (e_mail_part_get_validity (mail_part, validity_flags[ii].flags)) {
+ if (tmp->len > 0)
+ g_string_append (tmp, ", ");
+ g_string_append (tmp, is_partial ? _(validity_flags[ii].description_partial) : _(validity_flags[ii].description_complete));
+ }
+ }
+
+ break;
}
- break;
- }
+ if (tmp->len > 0)
+ e_mail_formatter_format_header (formatter, buffer, _("Security"), tmp->str, flags, "UTF-8");
- if (tmp->len > 0) {
- e_mail_formatter_format_header (
- formatter, buffer,
- _("Security"), tmp->str,
- flags,
- "UTF-8");
+ g_string_free (tmp, TRUE);
}
+ #undef should_skip_part
+
while (!g_queue_is_empty (&queue))
g_object_unref (g_queue_pop_head (&queue));
- g_string_free (tmp, TRUE);
g_free (part_id_prefix);
}
diff --git a/src/em-format/e-mail-formatter-utils.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-formatter-utils.c.cve-2018-15587-reposition-signature-bar
new file mode 100644
index 0000000..abd5155
--- /dev/null
+++ b/src/em-format/e-mail-formatter-utils.c.cve-2018-15587-reposition-signature-bar
@@ -0,0 +1,619 @@
+/*
+ * e-mail-formatter-utils.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.
+ *
+ * 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 "evolution-config.h"
+
+#include "e-mail-formatter-utils.h"
+#include "e-mail-part-headers.h"
+
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+static const gchar *addrspec_hdrs[] = {
+ "Sender", "From", "Reply-To", "To", "Cc", "Bcc",
+ "Resent-Sender", "Resent-From", "Resent-Reply-To",
+ "Resent-To", "Resent-Cc", "Resent-Bcc", NULL
+};
+
+void
+e_mail_formatter_format_text_header (EMailFormatter *formatter,
+ GString *buffer,
+ const gchar *label,
+ const gchar *value,
+ guint32 flags)
+{
+ GtkTextDirection direction;
+ const gchar *fmt, *html;
+ const gchar *display;
+ gchar *mhtml = NULL;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (buffer != NULL);
+ g_return_if_fail (label != NULL);
+
+ if (value == NULL)
+ return;
+
+ while (*value == ' ')
+ value++;
+
+ if (!(flags & E_MAIL_FORMATTER_HEADER_FLAG_HTML)) {
+ CamelMimeFilterToHTMLFlags text_format_flags;
+
+ text_format_flags =
+ e_mail_formatter_get_text_format_flags (formatter);
+ html = mhtml = camel_text_to_html (
+ value, text_format_flags, 0);
+ } else {
+ html = value;
+ }
+
+ direction = gtk_widget_get_default_direction ();
+
+ if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS) {
+ if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) {
+ fmt = ""
+ "%s: %s |
";
+ } else {
+ fmt = ""
+ "%s: %s |
";
+ }
+ } else if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NODEC) {
+ if (direction == GTK_TEXT_DIR_RTL)
+ fmt = "";
+ else
+ fmt = "";
+ } else {
+ if (direction == GTK_TEXT_DIR_RTL)
+ fmt = "";
+ else
+ fmt = "";
+ }
+
+ if (flags & E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN)
+ display = "none";
+ else
+ display = "table-row";
+
+ g_string_append_printf (buffer, fmt, display, label, html);
+
+ g_free (mhtml);
+}
+
+gchar *
+e_mail_formatter_format_address (EMailFormatter *formatter,
+ GString *out,
+ struct _camel_header_address *a,
+ const gchar *field,
+ gboolean no_links,
+ gboolean elipsize)
+{
+ CamelMimeFilterToHTMLFlags flags;
+ gchar *name, *mailto, *addr;
+ gint i = 0;
+ gchar *str = NULL;
+ gint limit = mail_config_get_address_count ();
+
+ g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+ g_return_val_if_fail (out != NULL, NULL);
+ g_return_val_if_fail (field != NULL, NULL);
+
+ flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
+
+ while (a != NULL) {
+ if (a->name)
+ name = camel_text_to_html (a->name, flags, 0);
+ else
+ name = NULL;
+
+ switch (a->type) {
+ case CAMEL_HEADER_ADDRESS_NAME:
+ if (name != NULL && *name != '\0') {
+ gchar *real, *mailaddr;
+
+ if (strchr (a->name, ',') || strchr (a->name, ';'))
+ g_string_append_printf (out, ""%s"", name);
+ else
+ g_string_append (out, name);
+
+ g_string_append (out, " <");
+
+ /* rfc2368 for mailto syntax and url encoding extras */
+ if ((real = camel_header_encode_phrase ((guchar *) a->name))) {
+ mailaddr = g_strdup_printf ("%s <%s>", real, a->v.addr);
+ g_free (real);
+ mailto = camel_url_encode (mailaddr, "?=&()");
+ g_free (mailaddr);
+ } else {
+ mailto = camel_url_encode (a->v.addr, "?=&()");
+ }
+ } else {
+ mailto = camel_url_encode (a->v.addr, "?=&()");
+ }
+ addr = camel_text_to_html (a->v.addr, flags, 0);
+ if (no_links)
+ g_string_append_printf (out, "%s", addr);
+ else
+ g_string_append_printf (out, "%s", mailto, addr);
+ g_free (mailto);
+ g_free (addr);
+
+ if (name != NULL && *name != '\0')
+ g_string_append (out, ">");
+ break;
+ case CAMEL_HEADER_ADDRESS_GROUP:
+ g_string_append_printf (out, "%s: ", name);
+ e_mail_formatter_format_address (
+ formatter, out, a->v.members, field,
+ no_links, elipsize);
+ g_string_append_printf (out, ";");
+ break;
+ default:
+ g_warning ("Invalid address type");
+ break;
+ }
+
+ g_free (name);
+
+ i++;
+ a = a->next;
+ if (a != NULL)
+ g_string_append (out, ", ");
+
+ if (!elipsize)
+ continue;
+
+ /* Let us add a '...' if we have more addresses */
+ if (limit > 0 && i == limit && a != NULL) {
+ if (strcmp (field, _("To")) == 0 ||
+ strcmp (field, _("Cc")) == 0 ||
+ strcmp (field, _("Bcc")) == 0) {
+
+ g_string_append (
+ out,
+ "");
+ str = g_strdup_printf (
+ "",
+ EVOLUTION_IMAGESDIR);
+ }
+ }
+ }
+
+ if (elipsize && str) {
+ if (strcmp (field, _("To")) == 0 ||
+ strcmp (field, _("Cc")) == 0 ||
+ strcmp (field, _("Bcc")) == 0) {
+
+ g_string_append (
+ out,
+ ""
+ "...");
+ }
+ }
+
+ return str;
+}
+
+void
+e_mail_formatter_canon_header_name (gchar *name)
+{
+ gchar *inptr = name;
+
+ g_return_if_fail (name != NULL);
+
+ /* canonicalise the header name... first letter is
+ * capitalised and any letter following a '-' also gets
+ * capitalised */
+
+ if (*inptr >= 'a' && *inptr <= 'z')
+ *inptr -= 0x20;
+
+ inptr++;
+
+ while (*inptr) {
+ if (inptr[-1] == '-' && *inptr >= 'a' && *inptr <= 'z')
+ *inptr -= 0x20;
+ else if (inptr[-1] != '-' && *inptr >= 'A' && *inptr <= 'Z')
+ *inptr += 0x20;
+
+ inptr++;
+ }
+}
+
+void
+e_mail_formatter_format_header (EMailFormatter *formatter,
+ GString *buffer,
+ const gchar *header_name,
+ const gchar *header_value,
+ guint32 flags,
+ const gchar *charset)
+{
+ gchar *canon_name, *buf, *value = NULL;
+ const gchar *label, *txt;
+ gboolean addrspec = FALSE;
+ gchar *str_field = NULL;
+ gint i;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (buffer != NULL);
+ g_return_if_fail (header_name != NULL);
+ g_return_if_fail (header_value != NULL);
+
+ canon_name = g_alloca (strlen (header_name) + 1);
+ strcpy (canon_name, header_name);
+ e_mail_formatter_canon_header_name (canon_name);
+
+ for (i = 0; addrspec_hdrs[i]; i++) {
+ if (g_ascii_strcasecmp (canon_name, addrspec_hdrs[i]) == 0) {
+ addrspec = TRUE;
+ break;
+ }
+ }
+
+ label = _(canon_name);
+
+ if (addrspec) {
+ struct _camel_header_address *addrs;
+ GString *html;
+ gchar *img;
+ gchar *fmt_charset;
+
+ fmt_charset = e_mail_formatter_dup_charset (formatter);
+ if (fmt_charset == NULL)
+ fmt_charset = e_mail_formatter_dup_default_charset (formatter);
+
+ buf = camel_header_unfold (header_value);
+ addrs = camel_header_address_decode (buf, fmt_charset);
+ if (addrs == NULL) {
+ g_free (fmt_charset);
+ g_free (buf);
+ return;
+ }
+
+ g_free (fmt_charset);
+ g_free (buf);
+
+ html = g_string_new ("");
+ img = e_mail_formatter_format_address (
+ formatter, html, addrs, label,
+ (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS),
+ !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
+
+ if (img != NULL) {
+ str_field = g_strdup_printf ("%s: %s", label, img);
+ label = str_field;
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_NODEC;
+ g_free (img);
+ }
+
+ camel_header_address_list_clear (&addrs);
+ txt = value = html->str;
+ g_string_free (html, FALSE);
+
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML;
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_name, "Subject")) {
+ buf = camel_header_unfold (header_value);
+ txt = value = camel_header_decode_string (buf, charset);
+ g_free (buf);
+
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_name, "X-Evolution-Mailer")) {
+ /* pseudo-header */
+ label = _("Mailer");
+ txt = value = camel_header_format_ctext (header_value, charset);
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_name, "Date") ||
+ g_str_equal (canon_name, "Resent-Date")) {
+ CamelMimeFilterToHTMLFlags text_format_flags;
+ gint msg_offset, local_tz;
+ time_t msg_date;
+ struct tm local;
+ gchar *html;
+ gboolean hide_real_date;
+
+ hide_real_date = !e_mail_formatter_get_show_real_date (formatter);
+
+ txt = header_value;
+ while (*txt == ' ' || *txt == '\t')
+ txt++;
+
+ text_format_flags =
+ e_mail_formatter_get_text_format_flags (formatter);
+
+ html = camel_text_to_html (txt, text_format_flags, 0);
+
+ msg_date = camel_header_decode_date (txt, &msg_offset);
+ e_localtime_with_offset (msg_date, &local, &local_tz);
+
+ /* Convert message offset to minutes (e.g. -0400 --> -240) */
+ msg_offset = ((msg_offset / 100) * 60) + (msg_offset % 100);
+ /* Turn into offset from localtime, not UTC */
+ msg_offset -= local_tz / 60;
+
+ /* value will be freed at the end */
+ if (!hide_real_date && !msg_offset) {
+ /* No timezone difference; just
+ * show the real Date: header. */
+ txt = value = html;
+ } else {
+ gchar *date_str;
+
+ date_str = e_datetime_format_format (
+ "mail", "header",
+ DTFormatKindDateTime, msg_date);
+
+ if (hide_real_date) {
+ /* Show only the local-formatted date, losing
+ * all timezone information like Outlook does.
+ * Should we attempt to show it somehow? */
+ txt = value = date_str;
+ } else {
+ txt = value = g_strdup_printf (
+ "%s (%s)", html, date_str);
+ g_free (date_str);
+ }
+ g_free (html);
+ }
+
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML;
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_name, "Newsgroups")) {
+ GSList *ng, *scan;
+ GString *html;
+
+ buf = camel_header_unfold (header_value);
+
+ if (!(ng = camel_header_newsgroups_decode (buf))) {
+ g_free (buf);
+ return;
+ }
+
+ g_free (buf);
+
+ html = g_string_new ("");
+ scan = ng;
+ while (scan) {
+ const gchar *newsgroup = scan->data;
+
+ if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS)
+ g_string_append_printf (
+ html, "%s", newsgroup);
+ else
+ g_string_append_printf (
+ html, "%s",
+ newsgroup, newsgroup);
+ scan = g_slist_next (scan);
+ if (scan)
+ g_string_append_printf (html, ", ");
+ }
+
+ g_slist_free_full (ng, g_free);
+
+ txt = html->str;
+ value = g_string_free (html, FALSE);
+
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML;
+ flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+
+ } else if (g_str_equal (canon_name, "Received") ||
+ g_str_has_prefix (canon_name, "X-")) {
+ /* don't unfold Received nor extension headers */
+ txt = value = camel_header_decode_string (header_value, charset);
+
+ } else {
+ /* don't unfold Received nor extension headers */
+ buf = camel_header_unfold (header_value);
+ txt = value = camel_header_decode_string (buf, charset);
+ g_free (buf);
+ }
+
+ e_mail_formatter_format_text_header (
+ formatter, buffer, label, txt, flags);
+
+ g_free (value);
+ g_free (str_field);
+}
+
+GList *
+e_mail_formatter_find_rfc822_end_iter (GList *rfc822_start_iter)
+{
+ GList *link = rfc822_start_iter;
+ EMailPart *part;
+ const gchar *part_id;
+ gchar *end;
+
+ g_return_val_if_fail (rfc822_start_iter != NULL, NULL);
+
+ part = E_MAIL_PART (link->data);
+
+ part_id = e_mail_part_get_id (part);
+ g_return_val_if_fail (part_id != NULL, NULL);
+
+ end = g_strconcat (part_id, ".end", NULL);
+
+ while (link != NULL) {
+ part = E_MAIL_PART (link->data);
+
+ part_id = e_mail_part_get_id (part);
+ g_return_val_if_fail (part_id != NULL, NULL);
+
+ if (g_strcmp0 (part_id, end) == 0)
+ break;
+
+ link = g_list_next (link);
+ }
+
+ g_free (end);
+
+ return link;
+}
+
+gchar *
+e_mail_formatter_parse_html_mnemonics (const gchar *label,
+ gchar **out_access_key)
+{
+ const gchar *pos = NULL;
+ GString *html_label = NULL;
+
+ g_return_val_if_fail (label != NULL, NULL);
+
+ if (out_access_key != NULL)
+ *out_access_key = NULL;
+
+ if (!g_utf8_validate (label, -1, NULL)) {
+ gchar *res = g_strdup (label);
+
+ g_return_val_if_fail (g_utf8_validate (label, -1, NULL), res);
+
+ return res;
+ }
+
+ pos = strstr (label, "_");
+ if (pos != NULL) {
+ gunichar uk;
+
+ html_label = g_string_new ("");
+ g_string_append_len (html_label, label, pos - label);
+
+ pos++;
+ uk = g_utf8_get_char (pos);
+
+ pos = g_utf8_next_char (pos);
+
+ g_string_append (html_label, "");
+ g_string_append_unichar (html_label, uk);
+ g_string_append (html_label, "");
+ g_string_append (html_label, pos);
+
+ if (out_access_key != NULL && uk != 0) {
+ gchar ukstr[10];
+ gint len;
+
+ len = g_unichar_to_utf8 (g_unichar_toupper (uk), ukstr);
+ if (len > 0)
+ *out_access_key = g_strndup (ukstr, len);
+ }
+
+ } else {
+ html_label = g_string_new (label);
+ }
+
+ return g_string_free (html_label, FALSE);
+}
+
+void
+e_mail_formatter_format_security_header (EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ GString *buffer,
+ EMailPart *part,
+ guint32 flags)
+{
+ const gchar* part_id;
+ gchar* part_id_prefix;
+ GString* tmp;
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+
+ g_return_if_fail (E_IS_MAIL_PART_HEADERS (part));
+
+ /* Get prefix of this PURI */
+ part_id = e_mail_part_get_id (part);
+ part_id_prefix = g_strndup (part_id, g_strrstr (part_id, ".") - part_id);
+
+ /* Add encryption/signature header */
+ tmp = g_string_new ("");
+
+ e_mail_part_list_queue_parts (context->part_list, NULL, &queue);
+
+ head = g_queue_peek_head_link (&queue);
+
+ /* Find first secured part. */
+ for (link = head; link != NULL; link = g_list_next(link)) {
+ EMailPart *mail_part = link->data;
+
+ if (!e_mail_part_has_validity (mail_part))
+ continue;
+
+ if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix))
+ continue;
+
+ if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SIGNED)) {
+ g_string_append (tmp, _("GPG signed"));
+ }
+
+ if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_ENCRYPTED)) {
+ if (tmp->len > 0)
+ g_string_append (tmp, ", ");
+ g_string_append (tmp, _("GPG encrypted"));
+ }
+
+ if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_SIGNED)) {
+ if (tmp->len > 0)
+ g_string_append (tmp, ", ");
+ g_string_append (tmp, _("S/MIME signed"));
+ }
+
+ if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_ENCRYPTED)) {
+ if (tmp->len > 0)
+ g_string_append (tmp, ", ");
+ g_string_append (tmp, _("S/MIME encrypted"));
+ }
+
+ break;
+ }
+
+ if (tmp->len > 0) {
+ e_mail_formatter_format_header (
+ formatter, buffer,
+ _("Security"), tmp->str,
+ flags,
+ "UTF-8");
+ }
+
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
+ g_string_free (tmp, TRUE);
+ g_free (part_id_prefix);
+}
diff --git a/src/em-format/e-mail-parser-application-smime.c b/src/em-format/e-mail-parser-application-smime.c
index 87f25b3..e569cd7 100644
--- a/src/em-format/e-mail-parser-application-smime.c
+++ b/src/em-format/e-mail-parser-application-smime.c
@@ -22,6 +22,7 @@
#include
+#include "e-mail-formatter-utils.h"
#include "e-mail-parser-extension.h"
#include "e-mail-part-utils.h"
@@ -104,6 +105,10 @@ empe_app_smime_parse (EMailParserExtension *extension,
mail_part, valid,
E_MAIL_PART_VALIDITY_ENCRYPTED |
E_MAIL_PART_VALIDITY_SMIME);
+
+ /* Do not traverse sub-messages */
+ if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822"))
+ link = e_mail_formatter_find_rfc822_end_iter (link);
}
e_queue_transfer (&work_queue, out_mail_parts);
diff --git a/src/em-format/e-mail-parser-application-smime.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-application-smime.c.cve-2018-15587-reposition-signature-bar
new file mode 100644
index 0000000..87f25b3
--- /dev/null
+++ b/src/em-format/e-mail-parser-application-smime.c.cve-2018-15587-reposition-signature-bar
@@ -0,0 +1,158 @@
+/*
+ * e-mail-parser-application-xpkcs7mime.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 "evolution-config.h"
+
+#include
+#include
+
+#include
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserApplicationSMIME;
+typedef EMailParserExtensionClass EMailParserApplicationSMIMEClass;
+
+GType e_mail_parser_application_smime_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserApplicationSMIME,
+ e_mail_parser_application_smime,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/xpkcs7mime",
+ "application/x-pkcs7-mime",
+ "application/pkcs7-mime",
+ "application/pkcs7-signature",
+ "application/xpkcs7-signature",
+ "application/x-pkcs7-signature",
+ NULL
+};
+
+static gboolean
+empe_app_smime_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelCipherContext *context;
+ CamelMimePart *opart;
+ CamelCipherValidity *valid;
+ CamelContentType *ct;
+ GError *local_error = NULL;
+
+ ct = camel_mime_part_get_content_type (part);
+ if (camel_content_type_is (ct, "application", "pkcs7-signature") ||
+ camel_content_type_is (ct, "application", "xpkcs7-signature") ||
+ camel_content_type_is (ct, "application", "x-pkcs7-signature")) {
+ return TRUE;
+ }
+
+ context = camel_smime_context_new (e_mail_parser_get_session (parser));
+
+ opart = camel_mime_part_new ();
+ valid = camel_cipher_context_decrypt_sync (
+ context, part, opart,
+ cancellable, &local_error);
+
+ e_mail_part_preserve_charset_in_content_type (part, opart);
+
+ if (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse S/MIME message: %s"),
+ local_error->message);
+ g_error_free (local_error);
+
+ } else {
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ gint len = part_id->len;
+
+ g_string_append (part_id, ".encrypted");
+
+ e_mail_parser_parse_part (
+ parser, opart, part_id, cancellable, &work_queue);
+
+ g_string_truncate (part_id, len);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ /* Update validity flags of all the involved subp-arts */
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_SMIME);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ /* Add a widget with details about the encryption, but only
+ * when the encrypted isn't itself secured, in that case it
+ * has created the button itself. */
+ if (!e_mail_part_is_secured (opart)) {
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".encrypted.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_SMIME);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ camel_cipher_validity_free (valid);
+ }
+
+ g_object_unref (opart);
+ g_object_unref (context);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_application_smime_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->flags = E_MAIL_PARSER_EXTENSION_INLINE;
+ class->parse = empe_app_smime_parse;
+}
+
+static void
+e_mail_parser_application_smime_init (EMailParserExtension *extension)
+{
+}
diff --git a/src/em-format/e-mail-parser-inlinepgp-encrypted.c b/src/em-format/e-mail-parser-inlinepgp-encrypted.c
index c66195c..e342825 100644
--- a/src/em-format/e-mail-parser-inlinepgp-encrypted.c
+++ b/src/em-format/e-mail-parser-inlinepgp-encrypted.c
@@ -22,6 +22,7 @@
#include
+#include "e-mail-formatter-utils.h"
#include "e-mail-parser-extension.h"
#include "e-mail-part-utils.h"
@@ -135,6 +136,10 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
mail_part, valid,
E_MAIL_PART_VALIDITY_ENCRYPTED |
E_MAIL_PART_VALIDITY_PGP);
+
+ /* Do not traverse sub-messages */
+ if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822"))
+ link = e_mail_formatter_find_rfc822_end_iter (link);
}
e_queue_transfer (&work_queue, out_mail_parts);
diff --git a/src/em-format/e-mail-parser-inlinepgp-encrypted.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-inlinepgp-encrypted.c.cve-2018-15587-reposition-signature-bar
new file mode 100644
index 0000000..c66195c
--- /dev/null
+++ b/src/em-format/e-mail-parser-inlinepgp-encrypted.c.cve-2018-15587-reposition-signature-bar
@@ -0,0 +1,186 @@
+/*
+ * e-mail-parser-inlinepgp-encrypted.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 "evolution-config.h"
+
+#include
+#include
+
+#include
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserInlinePGPEncrypted;
+typedef EMailParserExtensionClass EMailParserInlinePGPEncryptedClass;
+
+GType e_mail_parser_inline_pgp_encrypted_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserInlinePGPEncrypted,
+ e_mail_parser_inline_pgp_encrypted,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/x-inlinepgp-encrypted",
+ NULL
+};
+
+static gboolean
+empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelCipherContext *cipher;
+ CamelCipherValidity *valid;
+ CamelMimePart *opart;
+ CamelDataWrapper *dw;
+ gchar *mime_type;
+ gint len;
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ GError *local_error = NULL;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ cipher = camel_gpg_context_new (e_mail_parser_get_session (parser));
+
+ opart = camel_mime_part_new ();
+
+ /* Decrypt the message */
+ valid = camel_cipher_context_decrypt_sync (
+ cipher, part, opart, cancellable, &local_error);
+
+ if (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse PGP message: %s"),
+ local_error->message);
+ g_error_free (local_error);
+
+ e_mail_parser_parse_part_as (
+ parser,
+ part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ g_object_unref (cipher);
+ g_object_unref (opart);
+
+ return TRUE;
+ }
+
+ dw = camel_medium_get_content ((CamelMedium *) opart);
+ mime_type = camel_data_wrapper_get_mime_type (dw);
+
+ /* this ensures to show the 'opart' as inlined, if possible */
+ if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) {
+ const gchar *snoop;
+
+ snoop = e_mail_part_snoop_type (opart);
+
+ if (snoop != NULL) {
+ camel_data_wrapper_set_mime_type (dw, snoop);
+
+ /* Set the MIME type on the 'opart' itself as well.
+ * If it's "text/plain", then we want the TextPlain
+ * parser extension to treat it as "text/plain" and
+ * NOT wrap it as an attachment. */
+ camel_data_wrapper_set_mime_type (
+ CAMEL_DATA_WRAPPER (opart), snoop);
+ }
+ }
+
+ e_mail_part_preserve_charset_in_content_type (part, opart);
+ g_free (mime_type);
+
+ /* Pass it off to the real formatter */
+ len = part_id->len;
+ g_string_append (part_id, ".inlinepgp_encrypted");
+
+ mime_type = camel_data_wrapper_get_mime_type (dw);
+
+ g_warn_if_fail (e_mail_parser_parse_part_as (
+ parser, opart, part_id, mime_type,
+ cancellable, &work_queue));
+
+ g_free (mime_type);
+
+ g_string_truncate (part_id, len);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_PGP);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ /* Add a widget with details about the encryption, but only when
+ * the encrypted isn't itself secured, in that case it has created
+ * the button itself */
+ if (!e_mail_part_is_secured (opart)) {
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".inlinepgp_encrypted.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_PGP);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ /* Clean Up */
+ camel_cipher_validity_free (valid);
+ g_object_unref (opart);
+ g_object_unref (cipher);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_inline_pgp_encrypted_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_inlinepgp_encrypted_parse;
+}
+
+static void
+e_mail_parser_inline_pgp_encrypted_init (EMailParserExtension *extension)
+{
+}
diff --git a/src/em-format/e-mail-parser-inlinepgp-signed.c b/src/em-format/e-mail-parser-inlinepgp-signed.c
index 2ac8c3a..3235a1c 100644
--- a/src/em-format/e-mail-parser-inlinepgp-signed.c
+++ b/src/em-format/e-mail-parser-inlinepgp-signed.c
@@ -22,6 +22,7 @@
#include
+#include "e-mail-formatter-utils.h"
#include "e-mail-parser-extension.h"
#include "e-mail-part-utils.h"
@@ -142,6 +143,10 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension,
mail_part, valid,
E_MAIL_PART_VALIDITY_SIGNED |
E_MAIL_PART_VALIDITY_PGP);
+
+ /* Do not traverse sub-messages */
+ if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822"))
+ link = e_mail_formatter_find_rfc822_end_iter (link);
}
e_queue_transfer (&work_queue, out_mail_parts);
diff --git a/src/em-format/e-mail-parser-inlinepgp-signed.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-inlinepgp-signed.c.cve-2018-15587-reposition-signature-bar
new file mode 100644
index 0000000..2ac8c3a
--- /dev/null
+++ b/src/em-format/e-mail-parser-inlinepgp-signed.c.cve-2018-15587-reposition-signature-bar
@@ -0,0 +1,196 @@
+/*
+ * e-mail-parser-inlinepgp-signed.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 "evolution-config.h"
+
+#include
+#include
+
+#include
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserInlinePGPSigned;
+typedef EMailParserExtensionClass EMailParserInlinePGPSignedClass;
+
+GType e_mail_parser_inline_pgp_signed_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserInlinePGPSigned,
+ e_mail_parser_inline_pgp_signed,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "application/x-inlinepgp-signed",
+ NULL
+};
+
+static gboolean
+empe_inlinepgp_signed_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelStream *filtered_stream;
+ CamelMimeFilterPgp *pgp_filter;
+ CamelContentType *content_type;
+ CamelCipherContext *cipher;
+ CamelCipherValidity *valid;
+ CamelDataWrapper *dw;
+ CamelMimePart *opart;
+ CamelStream *ostream;
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ gchar *type;
+ gint len;
+ GError *local_error = NULL;
+ GByteArray *ba;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ cipher = camel_gpg_context_new (e_mail_parser_get_session (parser));
+
+ /* Verify the signature of the message */
+ valid = camel_cipher_context_verify_sync (
+ cipher, part, cancellable, &local_error);
+
+ if (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Error verifying signature: %s"),
+ local_error->message);
+
+ g_error_free (local_error);
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ g_object_unref (cipher);
+
+ return TRUE;
+ }
+
+ /* Setup output stream */
+ ostream = camel_stream_mem_new ();
+ filtered_stream = camel_stream_filter_new (ostream);
+
+ /* Add PGP header / footer filter */
+ pgp_filter = (CamelMimeFilterPgp *) camel_mime_filter_pgp_new ();
+ camel_stream_filter_add (
+ CAMEL_STREAM_FILTER (filtered_stream),
+ CAMEL_MIME_FILTER (pgp_filter));
+ g_object_unref (pgp_filter);
+
+ /* Pass through the filters that have been setup */
+ dw = camel_medium_get_content ((CamelMedium *) part);
+ camel_data_wrapper_decode_to_stream_sync (
+ dw, (CamelStream *) filtered_stream, cancellable, NULL);
+ camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL);
+ g_object_unref (filtered_stream);
+
+ /* Create a new text/plain MIME part containing the signed
+ * content preserving the original part's Content-Type params. */
+ content_type = camel_mime_part_get_content_type (part);
+ type = camel_content_type_format (content_type);
+ content_type = camel_content_type_decode (type);
+ g_free (type);
+
+ g_free (content_type->type);
+ content_type->type = g_strdup ("text");
+ g_free (content_type->subtype);
+ content_type->subtype = g_strdup ("plain");
+ type = camel_content_type_format (content_type);
+ camel_content_type_unref (content_type);
+
+ ba = camel_stream_mem_get_byte_array ((CamelStreamMem *) ostream);
+ opart = camel_mime_part_new ();
+ camel_mime_part_set_content (opart, (gchar *) ba->data, ba->len, type);
+ g_free (type);
+
+ len = part_id->len;
+ g_string_append (part_id, ".inlinepgp_signed");
+
+ g_warn_if_fail (e_mail_parser_parse_part (
+ parser, opart, part_id, cancellable, &work_queue));
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_SIGNED |
+ E_MAIL_PART_VALIDITY_PGP);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+
+ /* Add a widget with details about the encryption, but only when
+ * the encrypted isn't itself secured, in that case it has created
+ * the button itself */
+ if (!e_mail_part_is_secured (opart)) {
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".inlinepgp_signed.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_SIGNED |
+ E_MAIL_PART_VALIDITY_PGP);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ /* Clean Up */
+ camel_cipher_validity_free (valid);
+ g_object_unref (opart);
+ g_object_unref (ostream);
+ g_object_unref (cipher);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_inline_pgp_signed_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_inlinepgp_signed_parse;
+}
+
+static void
+e_mail_parser_inline_pgp_signed_init (EMailParserExtension *extension)
+{
+}
diff --git a/src/em-format/e-mail-parser-multipart-encrypted.c b/src/em-format/e-mail-parser-multipart-encrypted.c
index 2baa98f..818214c 100644
--- a/src/em-format/e-mail-parser-multipart-encrypted.c
+++ b/src/em-format/e-mail-parser-multipart-encrypted.c
@@ -21,6 +21,7 @@
#include
+#include "e-mail-formatter-utils.h"
#include "e-mail-parser-extension.h"
#include "e-mail-part-utils.h"
@@ -126,6 +127,10 @@ empe_mp_encrypted_parse (EMailParserExtension *extension,
mail_part, valid,
E_MAIL_PART_VALIDITY_ENCRYPTED |
E_MAIL_PART_VALIDITY_PGP);
+
+ /* Do not traverse sub-messages */
+ if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822"))
+ link = e_mail_formatter_find_rfc822_end_iter (link);
}
e_queue_transfer (&work_queue, out_mail_parts);
diff --git a/src/em-format/e-mail-parser-multipart-encrypted.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-multipart-encrypted.c.cve-2018-15587-reposition-signature-bar
new file mode 100644
index 0000000..2baa98f
--- /dev/null
+++ b/src/em-format/e-mail-parser-multipart-encrypted.c.cve-2018-15587-reposition-signature-bar
@@ -0,0 +1,179 @@
+/*
+ * e-mail-parser-multipart-encrypted.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 "evolution-config.h"
+
+#include
+
+#include
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMultipartEncrypted;
+typedef EMailParserExtensionClass EMailParserMultipartEncryptedClass;
+
+GType e_mail_parser_multipart_encrypted_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartEncrypted,
+ e_mail_parser_multipart_encrypted,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/encrypted",
+ NULL
+};
+
+static gboolean
+empe_mp_encrypted_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelCipherContext *context;
+ const gchar *protocol;
+ CamelMimePart *opart;
+ CamelCipherValidity *valid;
+ CamelMultipartEncrypted *mpe;
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ GError *local_error = NULL;
+ gint len;
+
+ mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part);
+ if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse MIME message. "
+ "Displaying as source."));
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution/source",
+ cancellable, out_mail_parts);
+
+ return TRUE;
+ }
+
+ /* Currently we only handle RFC2015-style PGP encryption. */
+ protocol = camel_content_type_param (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (mpe)), "protocol");
+ if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Unsupported encryption type for multipart/encrypted"));
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ return TRUE;
+ }
+
+ context = camel_gpg_context_new (e_mail_parser_get_session (parser));
+
+ opart = camel_mime_part_new ();
+ valid = camel_cipher_context_decrypt_sync (
+ context, part, opart, cancellable, &local_error);
+
+ e_mail_part_preserve_charset_in_content_type (part, opart);
+
+ if (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse PGP/MIME message: %s"),
+ local_error->message);
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ g_object_unref (opart);
+ g_object_unref (context);
+ g_error_free (local_error);
+
+ return TRUE;
+ }
+
+ len = part_id->len;
+ g_string_append (part_id, ".encrypted");
+
+ g_warn_if_fail (e_mail_parser_parse_part (
+ parser, opart, part_id, cancellable, &work_queue));
+
+ g_string_truncate (part_id, len);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ /* Update validity of all encrypted sub-parts */
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_PGP);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ /* Add a widget with details about the encryption, but only when
+ * the decrypted part isn't itself secured, in that case it has
+ * created the button itself. */
+ if (!e_mail_part_is_secured (opart)) {
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".encrypted.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ E_MAIL_PART_VALIDITY_ENCRYPTED |
+ E_MAIL_PART_VALIDITY_PGP);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ camel_cipher_validity_free (valid);
+
+ /* TODO: Make sure when we finalize this part, it is zero'd out */
+ g_object_unref (opart);
+ g_object_unref (context);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_encrypted_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_mp_encrypted_parse;
+}
+
+static void
+e_mail_parser_multipart_encrypted_init (EMailParserExtension *extension)
+{
+}
diff --git a/src/em-format/e-mail-parser-multipart-signed.c b/src/em-format/e-mail-parser-multipart-signed.c
index a76ca61..ca0133a 100644
--- a/src/em-format/e-mail-parser-multipart-signed.c
+++ b/src/em-format/e-mail-parser-multipart-signed.c
@@ -21,6 +21,7 @@
#include
+#include "e-mail-formatter-utils.h"
#include "e-mail-parser-extension.h"
#include "e-mail-part-utils.h"
@@ -170,6 +171,10 @@ empe_mp_signed_parse (EMailParserExtension *extension,
e_mail_part_update_validity (
mail_part, valid,
validity_type | E_MAIL_PART_VALIDITY_SIGNED);
+
+ /* Do not traverse sub-messages */
+ if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822"))
+ link = e_mail_formatter_find_rfc822_end_iter (link);
}
e_queue_transfer (&work_queue, out_mail_parts);
diff --git a/src/em-format/e-mail-parser-multipart-signed.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-multipart-signed.c.cve-2018-15587-reposition-signature-bar
new file mode 100644
index 0000000..a76ca61
--- /dev/null
+++ b/src/em-format/e-mail-parser-multipart-signed.c.cve-2018-15587-reposition-signature-bar
@@ -0,0 +1,222 @@
+/*
+ * e-mail-parser-multipart-signed.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 "evolution-config.h"
+
+#include
+
+#include
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-utils.h"
+
+typedef EMailParserExtension EMailParserMultipartSigned;
+typedef EMailParserExtensionClass EMailParserMultipartSignedClass;
+
+GType e_mail_parser_multipart_signed_get_type (void);
+
+G_DEFINE_TYPE (
+ EMailParserMultipartSigned,
+ e_mail_parser_multipart_signed,
+ E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+ "multipart/signed",
+ "application/pgp-signature",
+ NULL
+};
+
+static gboolean
+empe_mp_signed_parse (EMailParserExtension *extension,
+ EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelMimePart *cpart = NULL;
+ CamelMultipart *multipart;
+ CamelCipherContext *cipher = NULL;
+ CamelContentType *content_type;
+ CamelSession *session;
+ guint32 validity_type;
+ CamelCipherValidity *valid;
+ const gchar *protocol = NULL;
+ GError *local_error = NULL;
+ gint i, nparts, len;
+ gboolean secured;
+
+ /* If the part is application/pgp-signature sub-part then skip it. */
+ if (!CAMEL_IS_MULTIPART (part)) {
+ content_type = camel_mime_part_get_content_type (part);
+ if (camel_content_type_is (
+ content_type, "application", "pgp-signature")) {
+ return TRUE;
+ }
+ }
+
+ multipart = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+ if (CAMEL_IS_MULTIPART_SIGNED (multipart)) {
+ cpart = camel_multipart_get_part (
+ multipart, CAMEL_MULTIPART_SIGNED_CONTENT);
+ }
+
+ if (cpart == NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Could not parse MIME message. "
+ "Displaying as source."));
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.source",
+ cancellable, out_mail_parts);
+
+ return TRUE;
+ }
+
+ content_type = camel_data_wrapper_get_mime_type_field (
+ CAMEL_DATA_WRAPPER (multipart));
+ if (content_type != NULL)
+ protocol = camel_content_type_param (content_type, "protocol");
+
+ session = e_mail_parser_get_session (parser);
+ /* FIXME: Should be done via a plugin interface */
+ /* FIXME: duplicated in em-format-html-display.c */
+ if (protocol != NULL) {
+#ifdef ENABLE_SMIME
+ if (g_ascii_strcasecmp ("application/x-pkcs7-signature", protocol) == 0
+ || g_ascii_strcasecmp ("application/pkcs7-signature", protocol) == 0) {
+ cipher = camel_smime_context_new (session);
+ validity_type = E_MAIL_PART_VALIDITY_SMIME;
+ } else {
+#endif
+ if (g_ascii_strcasecmp ("application/pgp-signature", protocol) == 0) {
+ cipher = camel_gpg_context_new (session);
+ validity_type = E_MAIL_PART_VALIDITY_PGP;
+ }
+#ifdef ENABLE_SMIME
+ }
+#endif
+ }
+
+ if (cipher == NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Unsupported signature format"));
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ return TRUE;
+ }
+
+ valid = camel_cipher_context_verify_sync (
+ cipher, part, cancellable, &local_error);
+
+ if (local_error != NULL) {
+ e_mail_parser_error (
+ parser, out_mail_parts,
+ _("Error verifying signature: %s"),
+ local_error->message);
+ e_mail_parser_parse_part_as (
+ parser, part, part_id, "multipart/mixed",
+ cancellable, out_mail_parts);
+
+ g_object_unref (cipher);
+ g_error_free (local_error);
+
+ return TRUE;
+ }
+
+ nparts = camel_multipart_get_number (multipart);
+ secured = FALSE;
+ len = part_id->len;
+ for (i = 0; i < nparts; i++) {
+ GQueue work_queue = G_QUEUE_INIT;
+ GList *head, *link;
+ CamelMimePart *subpart;
+
+ subpart = camel_multipart_get_part (multipart, i);
+
+ g_string_append_printf (part_id, ".signed.%d", i);
+
+ g_warn_if_fail (e_mail_parser_parse_part (
+ parser, subpart, part_id, cancellable, &work_queue));
+
+ g_string_truncate (part_id, len);
+
+ if (!secured)
+ secured = e_mail_part_is_secured (subpart);
+
+ head = g_queue_peek_head_link (&work_queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *mail_part = link->data;
+
+ e_mail_part_update_validity (
+ mail_part, valid,
+ validity_type | E_MAIL_PART_VALIDITY_SIGNED);
+ }
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+ }
+
+ /* Add a widget with details about the encryption, but only when
+ * the encrypted isn't itself secured, in that case it has created
+ * the button itself. */
+ if (!secured) {
+ GQueue work_queue = G_QUEUE_INIT;
+ EMailPart *mail_part;
+
+ g_string_append (part_id, ".signed.button");
+
+ e_mail_parser_parse_part_as (
+ parser, part, part_id,
+ "application/vnd.evolution.secure-button",
+ cancellable, &work_queue);
+
+ mail_part = g_queue_peek_head (&work_queue);
+
+ if (mail_part != NULL)
+ e_mail_part_update_validity (
+ mail_part, valid,
+ validity_type | E_MAIL_PART_VALIDITY_SIGNED);
+
+ e_queue_transfer (&work_queue, out_mail_parts);
+
+ g_string_truncate (part_id, len);
+ }
+
+ camel_cipher_validity_free (valid);
+
+ g_object_unref (cipher);
+
+ return TRUE;
+}
+
+static void
+e_mail_parser_multipart_signed_class_init (EMailParserExtensionClass *class)
+{
+ class->mime_types = parser_mime_types;
+ class->priority = G_PRIORITY_LOW;
+ class->parse = empe_mp_signed_parse;
+}
+
+static void
+e_mail_parser_multipart_signed_init (EMailParserExtension *extension)
+{
+}
diff --git a/src/em-format/e-mail-parser.c b/src/em-format/e-mail-parser.c
index 96c603f..b1f1511 100644
--- a/src/em-format/e-mail-parser.c
+++ b/src/em-format/e-mail-parser.c
@@ -79,6 +79,67 @@ GType e_mail_parser_application_smime_get_type (void);
static gpointer parent_class;
static void
+mail_parser_move_security_before_headers (GQueue *part_queue)
+{
+ GList *link, *last_headers = NULL;
+ GSList *headers_stack = NULL;
+
+ link = g_queue_peek_head_link (part_queue);
+ while (link) {
+ EMailPart *part = link->data;
+ const gchar *id;
+
+ if (!part) {
+ link = g_list_next (link);
+ continue;
+ }
+
+ id = e_mail_part_get_id (part);
+ if (!id) {
+ link = g_list_next (link);
+ continue;
+ }
+
+ if (g_str_has_suffix (id, ".rfc822")) {
+ headers_stack = g_slist_prepend (headers_stack, last_headers);
+ last_headers = NULL;
+ } else if (g_str_has_suffix (id, ".rfc822.end")) {
+ g_warn_if_fail (headers_stack != NULL);
+
+ if (headers_stack) {
+ last_headers = headers_stack->data;
+ headers_stack = g_slist_remove (headers_stack, last_headers);
+ } else {
+ last_headers = NULL;
+ }
+ }
+
+ if (g_strcmp0 (e_mail_part_get_mime_type (part), "application/vnd.evolution.headers") == 0) {
+ last_headers = link;
+ link = g_list_next (link);
+ } else if (g_strcmp0 (e_mail_part_get_mime_type (part), "application/vnd.evolution.secure-button") == 0) {
+ g_warn_if_fail (last_headers != NULL);
+
+ if (last_headers) {
+ GList *next = g_list_next (link);
+
+ g_warn_if_fail (g_queue_remove (part_queue, part));
+ g_queue_insert_before (part_queue, last_headers, part);
+
+ link = next;
+ } else {
+ link = g_list_next (link);
+ }
+ } else {
+ link = g_list_next (link);
+ }
+ }
+
+ g_warn_if_fail (headers_stack == NULL);
+ g_slist_free (headers_stack);
+}
+
+static void
mail_parser_run (EMailParser *parser,
EMailPartList *part_list,
GCancellable *cancellable)
@@ -132,6 +193,8 @@ mail_parser_run (EMailParser *parser,
break;
}
+ mail_parser_move_security_before_headers (&mail_part_queue);
+
while (!g_queue_is_empty (&mail_part_queue)) {
mail_part = g_queue_pop_head (&mail_part_queue);
e_mail_part_list_add_part (part_list, mail_part);
diff --git a/src/em-format/e-mail-parser.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser.c.cve-2018-15587-reposition-signature-bar
new file mode 100644
index 0000000..96c603f
--- /dev/null
+++ b/src/em-format/e-mail-parser.c.cve-2018-15587-reposition-signature-bar
@@ -0,0 +1,832 @@
+/*
+ * e-mail-parser.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 "evolution-config.h"
+
+#include "e-mail-parser.h"
+
+#include
+
+#include
+
+#include
+#include
+
+#include "e-mail-parser-extension.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-utils.h"
+
+#define E_MAIL_PARSER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PARSER, EMailParserPrivate))
+
+#define d(x)
+
+struct _EMailParserPrivate {
+ GMutex mutex;
+
+ gint last_error;
+
+ CamelSession *session;
+};
+
+enum {
+ PROP_0,
+ PROP_SESSION
+};
+
+/* internal parser extensions */
+GType e_mail_parser_application_mbox_get_type (void);
+GType e_mail_parser_audio_get_type (void);
+GType e_mail_parser_headers_get_type (void);
+GType e_mail_parser_message_get_type (void);
+GType e_mail_parser_secure_button_get_type (void);
+GType e_mail_parser_source_get_type (void);
+GType e_mail_parser_image_get_type (void);
+GType e_mail_parser_inline_pgp_encrypted_get_type (void);
+GType e_mail_parser_inline_pgp_signed_get_type (void);
+GType e_mail_parser_message_delivery_status_get_type (void);
+GType e_mail_parser_message_external_get_type (void);
+GType e_mail_parser_message_rfc822_get_type (void);
+GType e_mail_parser_multipart_alternative_get_type (void);
+GType e_mail_parser_multipart_apple_double_get_type (void);
+GType e_mail_parser_multipart_digest_get_type (void);
+GType e_mail_parser_multipart_encrypted_get_type (void);
+GType e_mail_parser_multipart_mixed_get_type (void);
+GType e_mail_parser_multipart_related_get_type (void);
+GType e_mail_parser_multipart_signed_get_type (void);
+GType e_mail_parser_text_enriched_get_type (void);
+GType e_mail_parser_text_html_get_type (void);
+GType e_mail_parser_text_plain_get_type (void);
+#ifdef ENABLE_SMIME
+GType e_mail_parser_application_smime_get_type (void);
+#endif
+
+static gpointer parent_class;
+
+static void
+mail_parser_run (EMailParser *parser,
+ EMailPartList *part_list,
+ GCancellable *cancellable)
+{
+ EMailExtensionRegistry *reg;
+ CamelMimeMessage *message;
+ EMailPart *mail_part;
+ GQueue *parsers;
+ GQueue mail_part_queue = G_QUEUE_INIT;
+ GList *iter;
+ GString *part_id;
+
+ message = e_mail_part_list_get_message (part_list);
+
+ reg = e_mail_parser_get_extension_registry (parser);
+
+ parsers = e_mail_extension_registry_get_for_mime_type (
+ reg, "application/vnd.evolution.message");
+
+ if (parsers == NULL)
+ parsers = e_mail_extension_registry_get_for_mime_type (
+ reg, "message/*");
+
+ /* No parsers means the internal Evolution parser
+ * extensions were not loaded. Something is terribly wrong! */
+ g_return_if_fail (parsers != NULL);
+
+ part_id = g_string_new (".message");
+
+ mail_part = e_mail_part_new (CAMEL_MIME_PART (message), ".message");
+ e_mail_part_list_add_part (part_list, mail_part);
+ g_object_unref (mail_part);
+
+ for (iter = parsers->head; iter; iter = iter->next) {
+ EMailParserExtension *extension;
+ gboolean message_handled;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ break;
+
+ extension = iter->data;
+ if (!extension)
+ continue;
+
+ message_handled = e_mail_parser_extension_parse (
+ extension, parser,
+ CAMEL_MIME_PART (message),
+ part_id, cancellable, &mail_part_queue);
+
+ if (message_handled)
+ break;
+ }
+
+ while (!g_queue_is_empty (&mail_part_queue)) {
+ mail_part = g_queue_pop_head (&mail_part_queue);
+ e_mail_part_list_add_part (part_list, mail_part);
+ g_object_unref (mail_part);
+ }
+
+ g_string_free (part_id, TRUE);
+}
+
+static void
+shell_gone_cb (gpointer user_data,
+ GObject *gone_extension_registry)
+{
+ EMailParserClass *class = user_data;
+
+ g_return_if_fail (class != NULL);
+
+ g_clear_object (&class->extension_registry);
+}
+
+static void
+mail_parser_set_session (EMailParser *parser,
+ CamelSession *session)
+{
+ g_return_if_fail (CAMEL_IS_SESSION (session));
+ g_return_if_fail (parser->priv->session == NULL);
+
+ parser->priv->session = g_object_ref (session);
+}
+
+static void
+e_mail_parser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SESSION:
+ mail_parser_set_session (
+ E_MAIL_PARSER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_parser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SESSION:
+ g_value_set_object (
+ value,
+ e_mail_parser_get_session (
+ E_MAIL_PARSER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_parser_finalize (GObject *object)
+{
+ EMailParserPrivate *priv;
+
+ priv = E_MAIL_PARSER_GET_PRIVATE (object);
+
+ g_clear_object (&priv->session);
+ g_mutex_clear (&priv->mutex);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+e_mail_parser_base_init (EMailParserClass *class)
+{
+ EShell *shell;
+
+ /* Register internal extensions. */
+ g_type_ensure (e_mail_parser_application_mbox_get_type ());
+ /* This is currently disabled, because the WebKit player requires javascript,
+ which is disabled in Evolution. */
+ /* g_type_ensure (e_mail_parser_audio_get_type ()); */
+ g_type_ensure (e_mail_parser_headers_get_type ());
+ g_type_ensure (e_mail_parser_message_get_type ());
+ g_type_ensure (e_mail_parser_secure_button_get_type ());
+ g_type_ensure (e_mail_parser_source_get_type ());
+ g_type_ensure (e_mail_parser_image_get_type ());
+ g_type_ensure (e_mail_parser_inline_pgp_encrypted_get_type ());
+ g_type_ensure (e_mail_parser_inline_pgp_signed_get_type ());
+ g_type_ensure (e_mail_parser_message_delivery_status_get_type ());
+ g_type_ensure (e_mail_parser_message_external_get_type ());
+ g_type_ensure (e_mail_parser_message_rfc822_get_type ());
+ g_type_ensure (e_mail_parser_multipart_alternative_get_type ());
+ g_type_ensure (e_mail_parser_multipart_apple_double_get_type ());
+ g_type_ensure (e_mail_parser_multipart_digest_get_type ());
+ g_type_ensure (e_mail_parser_multipart_encrypted_get_type ());
+ g_type_ensure (e_mail_parser_multipart_mixed_get_type ());
+ g_type_ensure (e_mail_parser_multipart_related_get_type ());
+ g_type_ensure (e_mail_parser_multipart_signed_get_type ());
+ g_type_ensure (e_mail_parser_text_enriched_get_type ());
+ g_type_ensure (e_mail_parser_text_html_get_type ());
+ g_type_ensure (e_mail_parser_text_plain_get_type ());
+#ifdef ENABLE_SMIME
+ g_type_ensure (e_mail_parser_application_smime_get_type ());
+#endif
+
+ class->extension_registry = g_object_new (
+ E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, NULL);
+
+ e_mail_parser_extension_registry_load (class->extension_registry);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (class->extension_registry));
+
+ shell = e_shell_get_default ();
+ g_object_weak_ref (G_OBJECT (shell), shell_gone_cb, class);
+}
+
+static void
+e_mail_parser_class_init (EMailParserClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailParserPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = e_mail_parser_finalize;
+ object_class->set_property = e_mail_parser_set_property;
+ object_class->get_property = e_mail_parser_get_property;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SESSION,
+ g_param_spec_object (
+ "session",
+ "Camel Session",
+ NULL,
+ CAMEL_TYPE_SESSION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+e_mail_parser_init (EMailParser *parser)
+{
+ parser->priv = E_MAIL_PARSER_GET_PRIVATE (parser);
+
+ g_mutex_init (&parser->priv->mutex);
+}
+
+GType
+e_mail_parser_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailParserClass),
+ (GBaseInitFunc) e_mail_parser_base_init,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) e_mail_parser_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailParser),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) e_mail_parser_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EMailParser",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+EMailParser *
+e_mail_parser_new (CamelSession *session)
+{
+ g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PARSER,
+ "session", session, NULL);
+}
+
+/**
+ * e_mail_parser_parse_sync:
+ * @parser: an #EMailParser
+ * @folder: (allow none) a #CamelFolder containing the @message or %NULL
+ * @message_uid: (allow none) UID of the @message within the @folder or %NULL
+ * @message: a #CamelMimeMessage
+ * @cancellable: (allow-none) a #GCancellable
+ *
+ * Parses the @message synchronously. Returns a list of #EMailParts which
+ * represents structure of the message and additional properties of each part.
+ *
+ * Note that this function can block for a while, so it's not a good idea to call
+ * it from main thread.
+ *
+ * Return Value: An #EMailPartsList
+ */
+EMailPartList *
+e_mail_parser_parse_sync (EMailParser *parser,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ GCancellable *cancellable)
+{
+ EMailPartList *part_list;
+
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+ part_list = e_mail_part_list_new (message, message_uid, folder);
+
+ mail_parser_run (parser, part_list, cancellable);
+
+ if (camel_debug_start ("emformat:parser")) {
+ GQueue queue = G_QUEUE_INIT;
+
+ printf (
+ "%s finished with EMailPartList:\n",
+ G_OBJECT_TYPE_NAME (parser));
+
+ e_mail_part_list_queue_parts (part_list, NULL, &queue);
+
+ while (!g_queue_is_empty (&queue)) {
+ EMailPart *part;
+
+ part = g_queue_pop_head (&queue);
+
+ printf (
+ " id: %s | cid: %s | mime_type: %s | "
+ "is_hidden: %d | is_attachment: %d\n",
+ e_mail_part_get_id (part),
+ e_mail_part_get_cid (part),
+ e_mail_part_get_mime_type (part),
+ part->is_hidden ? 1 : 0,
+ e_mail_part_get_is_attachment (part) ? 1 : 0);
+
+ g_object_unref (part);
+ }
+
+ camel_debug_end ();
+ }
+
+ return part_list;
+}
+
+static void
+mail_parser_parse_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EMailPartList *part_list;
+
+ part_list = g_simple_async_result_get_op_res_gpointer (simple);
+
+ mail_parser_run (
+ E_MAIL_PARSER (source_object),
+ part_list, cancellable);
+}
+
+/**
+ * e_mail_parser_parse:
+ * @parser: an #EMailParser
+ * @message: a #CamelMimeMessage
+ * @callback: a #GAsyncReadyCallback
+ * @cancellable: (allow-none) a #GCancellable
+ * @user_data: (allow-none) user data passed to the callback
+ *
+ * Asynchronous version of e_mail_parser_parse_sync().
+ */
+void
+e_mail_parser_parse (EMailParser *parser,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ GAsyncReadyCallback callback,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ EMailPartList *part_list;
+
+ g_return_if_fail (E_IS_MAIL_PARSER (parser));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ part_list = e_mail_part_list_new (message, message_uid, folder);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (parser), callback,
+ user_data, e_mail_parser_parse);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, part_list, (GDestroyNotify) g_object_unref);
+
+ g_simple_async_result_run_in_thread (
+ simple, mail_parser_parse_thread,
+ G_PRIORITY_DEFAULT, cancellable);
+
+ g_object_unref (simple);
+}
+
+EMailPartList *
+e_mail_parser_parse_finish (EMailParser *parser,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ EMailPartList *part_list;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (parser), e_mail_parser_parse), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ part_list = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (camel_debug_start ("emformat:parser")) {
+ GQueue queue = G_QUEUE_INIT;
+
+ printf (
+ "%s finished with EMailPartList:\n",
+ G_OBJECT_TYPE_NAME (parser));
+
+ e_mail_part_list_queue_parts (part_list, NULL, &queue);
+
+ while (!g_queue_is_empty (&queue)) {
+ EMailPart *part;
+
+ part = g_queue_pop_head (&queue);
+
+ printf (
+ " id: %s | cid: %s | mime_type: %s | "
+ "is_hidden: %d | is_attachment: %d\n",
+ e_mail_part_get_id (part),
+ e_mail_part_get_cid (part),
+ e_mail_part_get_mime_type (part),
+ part->is_hidden ? 1 : 0,
+ e_mail_part_get_is_attachment (part) ? 1 : 0);
+
+ g_object_unref (part);
+ }
+
+ camel_debug_end ();
+ }
+
+ return g_object_ref (part_list);
+}
+
+GQueue *
+e_mail_parser_get_parsers_for_part (EMailParser *parser,
+ CamelMimePart *part)
+{
+ CamelContentType *ct;
+ gchar *mime_type;
+ GQueue *parsers;
+
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+ g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
+
+ ct = camel_mime_part_get_content_type (part);
+ if (!ct) {
+ mime_type = (gchar *) "application/vnd.evolution.error";
+ } else {
+ gchar *tmp;
+ tmp = camel_content_type_simple (ct);
+ mime_type = g_ascii_strdown (tmp, -1);
+ g_free (tmp);
+ }
+
+ parsers = e_mail_parser_get_parsers (parser, mime_type);
+
+ if (ct)
+ g_free (mime_type);
+
+ return parsers;
+}
+
+GQueue *
+e_mail_parser_get_parsers (EMailParser *parser,
+ const gchar *mime_type)
+{
+ EMailExtensionRegistry *reg;
+ EMailParserClass *parser_class;
+ gchar *as_mime_type;
+ GQueue *parsers;
+
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+
+ parser_class = E_MAIL_PARSER_GET_CLASS (parser);
+ g_return_val_if_fail (parser_class != NULL, NULL);
+
+ if (mime_type)
+ as_mime_type = g_ascii_strdown (mime_type, -1);
+ else
+ as_mime_type = NULL;
+
+ reg = E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry);
+
+ parsers = e_mail_extension_registry_get_for_mime_type (reg, as_mime_type);
+ if (!parsers)
+ parsers = e_mail_extension_registry_get_fallback (reg, as_mime_type);
+
+ g_free (as_mime_type);
+
+ return parsers;
+}
+
+gboolean
+e_mail_parser_parse_part (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ CamelContentType *ct;
+ gchar *mime_type;
+ gint handled;
+
+ ct = camel_mime_part_get_content_type (part);
+ if (!ct) {
+ mime_type = (gchar *) "application/vnd.evolution.error";
+ } else {
+ gchar *tmp;
+ tmp = camel_content_type_simple (ct);
+ mime_type = g_ascii_strdown (tmp, -1);
+ g_free (tmp);
+ }
+
+ handled = e_mail_parser_parse_part_as (
+ parser, part, part_id, mime_type,
+ cancellable, out_mail_parts);
+
+ if (ct) {
+ g_free (mime_type);
+ }
+
+ return handled;
+}
+
+gboolean
+e_mail_parser_parse_part_as (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ const gchar *mime_type,
+ GCancellable *cancellable,
+ GQueue *out_mail_parts)
+{
+ GQueue *parsers;
+ GList *iter;
+ gboolean mime_part_handled = FALSE;
+
+ parsers = e_mail_parser_get_parsers (parser, mime_type);
+
+ if (parsers == NULL) {
+ e_mail_parser_wrap_as_attachment (
+ parser, part, part_id, out_mail_parts);
+ return TRUE;
+ }
+
+ for (iter = parsers->head; iter; iter = iter->next) {
+ EMailParserExtension *extension;
+
+ extension = iter->data;
+ if (!extension)
+ continue;
+
+ mime_part_handled = e_mail_parser_extension_parse (
+ extension, parser, part, part_id,
+ cancellable, out_mail_parts);
+
+ if (mime_part_handled)
+ break;
+ }
+
+ return mime_part_handled;
+}
+
+void
+e_mail_parser_error (EMailParser *parser,
+ GQueue *out_mail_parts,
+ const gchar *format,
+ ...)
+{
+ const gchar *mime_type = "application/vnd.evolution.error";
+ EMailPart *mail_part;
+ CamelMimePart *part;
+ gchar *errmsg;
+ gchar *uri;
+ va_list ap;
+
+ g_return_if_fail (E_IS_MAIL_PARSER (parser));
+ g_return_if_fail (out_mail_parts != NULL);
+ g_return_if_fail (format != NULL);
+
+ va_start (ap, format);
+ errmsg = g_strdup_vprintf (format, ap);
+
+ part = camel_mime_part_new ();
+ camel_mime_part_set_content (
+ part, errmsg, strlen (errmsg), mime_type);
+ g_free (errmsg);
+ va_end (ap);
+
+ g_mutex_lock (&parser->priv->mutex);
+ parser->priv->last_error++;
+ uri = g_strdup_printf (".error.%d", parser->priv->last_error);
+ g_mutex_unlock (&parser->priv->mutex);
+
+ mail_part = e_mail_part_new (part, uri);
+ e_mail_part_set_mime_type (mail_part, mime_type);
+ mail_part->is_error = TRUE;
+
+ g_free (uri);
+ g_object_unref (part);
+
+ g_queue_push_tail (out_mail_parts, mail_part);
+}
+
+static void
+attachment_loaded (EAttachment *attachment,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EShell *shell;
+ GtkWindow *window;
+
+ shell = e_shell_get_default ();
+ window = e_shell_get_active_window (shell);
+
+ e_attachment_load_handle_error (attachment, res, window);
+
+ g_object_unref (attachment);
+}
+
+/* Idle callback */
+static gboolean
+load_attachment_idle (EAttachment *attachment)
+{
+ e_attachment_load_async (
+ attachment,
+ (GAsyncReadyCallback) attachment_loaded, NULL);
+
+ return FALSE;
+}
+
+void
+e_mail_parser_wrap_as_attachment (EMailParser *parser,
+ CamelMimePart *part,
+ GString *part_id,
+ GQueue *parts_queue)
+{
+ EMailPartAttachment *empa;
+ EAttachment *attachment;
+ EMailPart *first_part;
+ const gchar *snoop_mime_type;
+ GQueue *extensions;
+ CamelContentType *ct;
+ gchar *mime_type;
+ CamelDataWrapper *dw;
+ GByteArray *ba;
+ gsize size;
+ gint part_id_len;
+
+ ct = camel_mime_part_get_content_type (part);
+ extensions = NULL;
+ snoop_mime_type = NULL;
+ if (ct) {
+ EMailExtensionRegistry *reg;
+ mime_type = camel_content_type_simple (ct);
+
+ reg = e_mail_parser_get_extension_registry (parser);
+ extensions = e_mail_extension_registry_get_for_mime_type (
+ reg, mime_type);
+
+ if (camel_content_type_is (ct, "text", "*") ||
+ camel_content_type_is (ct, "message", "*"))
+ snoop_mime_type = mime_type;
+ else
+ g_free (mime_type);
+ }
+
+ if (!snoop_mime_type)
+ snoop_mime_type = e_mail_part_snoop_type (part);
+
+ if (!extensions) {
+ EMailExtensionRegistry *reg;
+
+ reg = e_mail_parser_get_extension_registry (parser);
+ extensions = e_mail_extension_registry_get_for_mime_type (
+ reg, snoop_mime_type);
+
+ if (!extensions) {
+ extensions = e_mail_extension_registry_get_fallback (
+ reg, snoop_mime_type);
+ }
+ }
+
+ part_id_len = part_id->len;
+ g_string_append (part_id, ".attachment");
+
+ empa = e_mail_part_attachment_new (part, part_id->str);
+ empa->shown = extensions && (!g_queue_is_empty (extensions) &&
+ e_mail_part_is_inline (part, extensions));
+ empa->snoop_mime_type = snoop_mime_type;
+
+ first_part = g_queue_peek_head (parts_queue);
+ if (first_part != NULL && !E_IS_MAIL_PART_ATTACHMENT (first_part)) {
+ const gchar *id = e_mail_part_get_id (first_part);
+ empa->part_id_with_attachment = g_strdup (id);
+ first_part->is_hidden = TRUE;
+ }
+
+ attachment = e_mail_part_attachment_ref_attachment (empa);
+
+ e_attachment_set_initially_shown (attachment, empa->shown);
+ e_attachment_set_can_show (
+ attachment,
+ extensions && !g_queue_is_empty (extensions));
+
+ /* Try to guess size of the attachments */
+ dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+ ba = camel_data_wrapper_get_byte_array (dw);
+ if (ba) {
+ size = ba->len;
+
+ if (camel_mime_part_get_encoding (part) == CAMEL_TRANSFER_ENCODING_BASE64)
+ size = size / 1.37;
+ } else {
+ size = 0;
+ }
+
+ /* e_attachment_load_async must be called from main thread */
+ /* Prioritize ahead of GTK+ redraws. */
+ g_idle_add_full (
+ G_PRIORITY_HIGH_IDLE,
+ (GSourceFunc) load_attachment_idle,
+ g_object_ref (attachment),
+ NULL);
+
+ if (size != 0) {
+ GFileInfo *file_info;
+
+ file_info = e_attachment_ref_file_info (attachment);
+
+ if (file_info == NULL) {
+ file_info = g_file_info_new ();
+ g_file_info_set_content_type (
+ file_info, empa->snoop_mime_type);
+ }
+
+ g_file_info_set_size (file_info, size);
+ e_attachment_set_file_info (attachment, file_info);
+
+ g_object_unref (file_info);
+ }
+
+ g_object_unref (attachment);
+
+ g_string_truncate (part_id, part_id_len);
+
+ /* Push to head, not tail. */
+ g_queue_push_head (parts_queue, empa);
+}
+
+CamelSession *
+e_mail_parser_get_session (EMailParser *parser)
+{
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+
+ return parser->priv->session;
+}
+
+EMailExtensionRegistry *
+e_mail_parser_get_extension_registry (EMailParser *parser)
+{
+ EMailParserClass *parser_class;
+
+ g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+
+ parser_class = E_MAIL_PARSER_GET_CLASS (parser);
+ g_return_val_if_fail (parser_class != NULL, NULL);
+
+ return E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry);
+}
diff --git a/src/em-format/e-mail-part.c b/src/em-format/e-mail-part.c
index 135005e..03271ce 100644
--- a/src/em-format/e-mail-part.c
+++ b/src/em-format/e-mail-part.c
@@ -662,6 +662,15 @@ e_mail_part_update_validity (EMailPart *part,
mask = E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SMIME;
+ /* Auto-add flags when the related part is present */
+ if (!(validity_type & E_MAIL_PART_VALIDITY_SIGNED) &&
+ validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
+ validity_type |= E_MAIL_PART_VALIDITY_SIGNED;
+
+ if (!(validity_type & E_MAIL_PART_VALIDITY_ENCRYPTED) &&
+ validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE)
+ validity_type |= E_MAIL_PART_VALIDITY_ENCRYPTED;
+
pair = mail_part_find_validity_pair (part, validity_type & mask);
if (pair != NULL) {
pair->validity_type |= validity_type;
diff --git a/src/em-format/e-mail-part.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-part.c.cve-2018-15587-reposition-signature-bar
new file mode 100644
index 0000000..135005e
--- /dev/null
+++ b/src/em-format/e-mail-part.c.cve-2018-15587-reposition-signature-bar
@@ -0,0 +1,798 @@
+/*
+ * e-mail-part.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 .
+ *
+ */
+
+/**
+ * EMailPart:
+ *
+ * The #EMailPart is a wrapper around #CamelMimePart which holds additional
+ * information about the mime part, like it's ID, encryption type etc.
+ *
+ * Each #EMailPart must have a unique ID. The ID is a dot-separated
+ * hierarchical description of the location of the part within the email
+ * message.
+ */
+
+#include "evolution-config.h"
+
+#include "e-mail-part.h"
+
+#include
+
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-list.h"
+
+#define E_MAIL_PART_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_PART, EMailPartPrivate))
+
+struct _EMailPartPrivate {
+ GWeakRef part_list;
+ CamelMimePart *mime_part;
+
+ gchar *id;
+ gchar *cid;
+ gchar *mime_type;
+
+ gboolean is_attachment;
+ gboolean converted_to_utf8;
+};
+
+enum {
+ PROP_0,
+ PROP_CID,
+ PROP_CONVERTED_TO_UTF8,
+ PROP_ID,
+ PROP_IS_ATTACHMENT,
+ PROP_MIME_PART,
+ PROP_MIME_TYPE,
+ PROP_PART_LIST
+};
+
+G_DEFINE_TYPE_WITH_CODE (
+ EMailPart,
+ e_mail_part,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_EXTENSIBLE, NULL))
+
+static void
+mail_part_validity_pair_free (gpointer ptr)
+{
+ EMailPartValidityPair *pair = ptr;
+
+ if (!pair)
+ return;
+
+ camel_cipher_validity_free (pair->validity);
+ g_free (pair);
+}
+
+static void
+mail_part_set_id (EMailPart *part,
+ const gchar *id)
+{
+ g_return_if_fail (part->priv->id == NULL);
+
+ part->priv->id = g_strdup (id);
+}
+
+static void
+mail_part_set_mime_part (EMailPart *part,
+ CamelMimePart *mime_part)
+{
+ g_return_if_fail (part->priv->mime_part == NULL);
+
+ /* The CamelMimePart is optional. */
+ if (mime_part != NULL)
+ part->priv->mime_part = g_object_ref (mime_part);
+}
+
+static void
+mail_part_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CID:
+ e_mail_part_set_cid (
+ E_MAIL_PART (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_CONVERTED_TO_UTF8:
+ e_mail_part_set_converted_to_utf8 (
+ E_MAIL_PART (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_ID:
+ mail_part_set_id (
+ E_MAIL_PART (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_IS_ATTACHMENT:
+ e_mail_part_set_is_attachment (
+ E_MAIL_PART (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_MIME_PART:
+ mail_part_set_mime_part (
+ E_MAIL_PART (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_MIME_TYPE:
+ e_mail_part_set_mime_type (
+ E_MAIL_PART (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_PART_LIST:
+ e_mail_part_set_part_list (
+ E_MAIL_PART (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CID:
+ g_value_set_string (
+ value,
+ e_mail_part_get_cid (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_CONVERTED_TO_UTF8:
+ g_value_set_boolean (
+ value,
+ e_mail_part_get_converted_to_utf8 (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_ID:
+ g_value_set_string (
+ value,
+ e_mail_part_get_id (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_IS_ATTACHMENT:
+ g_value_set_boolean (
+ value,
+ e_mail_part_get_is_attachment (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_MIME_PART:
+ g_value_take_object (
+ value,
+ e_mail_part_ref_mime_part (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_MIME_TYPE:
+ g_value_set_string (
+ value,
+ e_mail_part_get_mime_type (
+ E_MAIL_PART (object)));
+ return;
+
+ case PROP_PART_LIST:
+ g_value_take_object (
+ value,
+ e_mail_part_ref_part_list (
+ E_MAIL_PART (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_part_dispose (GObject *object)
+{
+ EMailPartPrivate *priv;
+
+ priv = E_MAIL_PART_GET_PRIVATE (object);
+
+ g_weak_ref_set (&priv->part_list, NULL);
+
+ g_clear_object (&priv->mime_part);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_part_parent_class)->dispose (object);
+}
+
+static void
+mail_part_finalize (GObject *object)
+{
+ EMailPart *part = E_MAIL_PART (object);
+ EMailPartValidityPair *pair;
+
+ g_free (part->priv->id);
+ g_free (part->priv->cid);
+ g_free (part->priv->mime_type);
+
+ while ((pair = g_queue_pop_head (&part->validities)) != NULL)
+ mail_part_validity_pair_free (pair);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_part_parent_class)->finalize (object);
+}
+
+static void
+mail_part_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_part_parent_class)->constructed (object);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (object));
+}
+
+static void
+e_mail_part_class_init (EMailPartClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EMailPartPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_part_set_property;
+ object_class->get_property = mail_part_get_property;
+ object_class->dispose = mail_part_dispose;
+ object_class->finalize = mail_part_finalize;
+ object_class->constructed = mail_part_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CID,
+ g_param_spec_string (
+ "cid",
+ "Content ID",
+ "The MIME Content-ID",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CONVERTED_TO_UTF8,
+ g_param_spec_boolean (
+ "converted-to-utf8",
+ "Converted To UTF8",
+ "Whether the part content was already converted to UTF-8",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ID,
+ g_param_spec_string (
+ "id",
+ "Part ID",
+ "The part ID",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_IS_ATTACHMENT,
+ g_param_spec_boolean (
+ "is-attachment",
+ "Is Attachment",
+ "Format the part as an attachment",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MIME_PART,
+ g_param_spec_object (
+ "mime-part",
+ "MIME Part",
+ "The MIME part",
+ CAMEL_TYPE_MIME_PART,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MIME_TYPE,
+ g_param_spec_string (
+ "mime-type",
+ "MIME Type",
+ "The MIME type",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PART_LIST,
+ g_param_spec_object (
+ "part-list",
+ "Part List",
+ "The part list that owns the part",
+ E_TYPE_MAIL_PART_LIST,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_mail_part_init (EMailPart *part)
+{
+ part->priv = E_MAIL_PART_GET_PRIVATE (part);
+}
+
+/**
+ * e_mail_part_new:
+ * @mime_part: (allow-none) a #CamelMimePart or %NULL
+ * @id: part ID
+ *
+ * Creates a new #EMailPart for the given @mime_part.
+ *
+ * Return value: a new #EMailPart
+ */
+EMailPart *
+e_mail_part_new (CamelMimePart *mime_part,
+ const gchar *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART,
+ "id", id, "mime-part", mime_part, NULL);
+}
+
+const gchar *
+e_mail_part_get_id (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ return part->priv->id;
+}
+
+const gchar *
+e_mail_part_get_cid (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ return part->priv->cid;
+}
+
+void
+e_mail_part_set_cid (EMailPart *part,
+ const gchar *cid)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ g_free (part->priv->cid);
+ part->priv->cid = g_strdup (cid);
+
+ g_object_notify (G_OBJECT (part), "cid");
+}
+
+gboolean
+e_mail_part_id_has_prefix (EMailPart *part,
+ const gchar *prefix)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+ g_return_val_if_fail (prefix != NULL, FALSE);
+
+ return g_str_has_prefix (part->priv->id, prefix);
+}
+
+gboolean
+e_mail_part_id_has_suffix (EMailPart *part,
+ const gchar *suffix)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+ g_return_val_if_fail (suffix != NULL, FALSE);
+
+ return g_str_has_suffix (part->priv->id, suffix);
+}
+
+gboolean
+e_mail_part_id_has_substr (EMailPart *part,
+ const gchar *substr)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+ g_return_val_if_fail (substr != NULL, FALSE);
+
+ return (strstr (part->priv->id, substr) != NULL);
+}
+
+CamelMimePart *
+e_mail_part_ref_mime_part (EMailPart *part)
+{
+ CamelMimePart *mime_part = NULL;
+
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ if (part->priv->mime_part != NULL)
+ mime_part = g_object_ref (part->priv->mime_part);
+
+ return mime_part;
+}
+
+const gchar *
+e_mail_part_get_mime_type (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ return part->priv->mime_type;
+}
+
+void
+e_mail_part_set_mime_type (EMailPart *part,
+ const gchar *mime_type)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ if (g_strcmp0 (mime_type, part->priv->mime_type) == 0)
+ return;
+
+ g_free (part->priv->mime_type);
+ part->priv->mime_type = g_strdup (mime_type);
+
+ g_object_notify (G_OBJECT (part), "mime-type");
+}
+
+gboolean
+e_mail_part_get_converted_to_utf8 (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+
+ return part->priv->converted_to_utf8;
+}
+
+void
+e_mail_part_set_converted_to_utf8 (EMailPart *part,
+ gboolean converted_to_utf8)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ if (converted_to_utf8 == part->priv->converted_to_utf8)
+ return;
+
+ part->priv->converted_to_utf8 = converted_to_utf8;
+
+ g_object_notify (G_OBJECT (part), "converted-to-utf8");
+}
+
+gboolean
+e_mail_part_should_show_inline (EMailPart *part)
+{
+ CamelMimePart *mime_part;
+ const CamelContentDisposition *disposition;
+ gboolean res = FALSE;
+
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+
+ /* Automatically expand attachments that have inline
+ * disposition or the EMailParts have specific
+ * force_inline flag set. */
+
+ if (part->force_collapse)
+ return FALSE;
+
+ if (part->force_inline)
+ return TRUE;
+
+ if (E_IS_MAIL_PART_ATTACHMENT (part)) {
+ EMailPartAttachment *empa = E_MAIL_PART_ATTACHMENT (part);
+
+ if (g_strcmp0 (empa->snoop_mime_type, "message/rfc822") == 0)
+ return TRUE;
+ }
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ if (!mime_part)
+ return FALSE;
+
+ disposition = camel_mime_part_get_content_disposition (mime_part);
+ if (disposition && disposition->disposition &&
+ g_ascii_strncasecmp (disposition->disposition, "inline", 6) == 0) {
+ GSettings *settings;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ res = g_settings_get_boolean (settings, "display-content-disposition-inline");
+ g_clear_object (&settings);
+ }
+
+ g_object_unref (mime_part);
+
+ return res;
+}
+
+EMailPartList *
+e_mail_part_ref_part_list (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ return g_weak_ref_get (&part->priv->part_list);
+}
+
+void
+e_mail_part_set_part_list (EMailPart *part,
+ EMailPartList *part_list)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ if (part_list != NULL)
+ g_return_if_fail (E_IS_MAIL_PART_LIST (part_list));
+
+ g_weak_ref_set (&part->priv->part_list, part_list);
+
+ g_object_notify (G_OBJECT (part), "part-list");
+}
+
+gboolean
+e_mail_part_get_is_attachment (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+
+ return part->priv->is_attachment;
+}
+
+void
+e_mail_part_set_is_attachment (EMailPart *part,
+ gboolean is_attachment)
+{
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ if (is_attachment == part->priv->is_attachment)
+ return;
+
+ part->priv->is_attachment = is_attachment;
+
+ g_object_notify (G_OBJECT (part), "is-attachment");
+}
+
+void
+e_mail_part_bind_dom_element (EMailPart *part,
+ EWebView *web_view,
+ guint64 page_id,
+ const gchar *element_id)
+{
+ EMailPartClass *class;
+
+ g_return_if_fail (E_IS_MAIL_PART (part));
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (page_id != 0);
+ g_return_if_fail (element_id && *element_id);
+
+ class = E_MAIL_PART_GET_CLASS (part);
+ g_return_if_fail (class != NULL);
+
+ if (class->bind_dom_element != NULL)
+ class->bind_dom_element (part, web_view, page_id, element_id);
+}
+
+void
+e_mail_part_web_view_loaded (EMailPart *part,
+ EWebView *web_view)
+{
+ EMailPartClass *klass;
+
+ g_return_if_fail (E_IS_MAIL_PART (part));
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ klass = E_MAIL_PART_GET_CLASS (part);
+ g_return_if_fail (klass != NULL);
+
+ if (klass->web_view_loaded)
+ klass->web_view_loaded (part, web_view);
+}
+
+static EMailPartValidityPair *
+mail_part_find_validity_pair (EMailPart *part,
+ EMailPartValidityFlags validity_type)
+{
+ GList *head, *link;
+
+ head = g_queue_peek_head_link (&part->validities);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+
+ if (pair == NULL)
+ continue;
+
+ if ((pair->validity_type & validity_type) == validity_type)
+ return pair;
+ }
+
+ return NULL;
+}
+
+/**
+ * e_mail_part_update_validity:
+ * @part: An #EMailPart
+ * @validity: a #CamelCipherValidity
+ * @validity_type: E_MAIL_PART_VALIDITY_* flags
+ *
+ * Updates validity of the @part. When the part already has some validity
+ * set, the new @validity and @validity_type are just appended, preserving
+ * the original validity. Validities of the same type (PGP or S/MIME) are
+ * merged together.
+ */
+void
+e_mail_part_update_validity (EMailPart *part,
+ CamelCipherValidity *validity,
+ EMailPartValidityFlags validity_type)
+{
+ EMailPartValidityPair *pair;
+ EMailPartValidityFlags mask;
+
+ g_return_if_fail (E_IS_MAIL_PART (part));
+ g_return_if_fail (validity != NULL);
+
+ mask = E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SMIME;
+
+ pair = mail_part_find_validity_pair (part, validity_type & mask);
+ if (pair != NULL) {
+ pair->validity_type |= validity_type;
+ camel_cipher_validity_envelope (pair->validity, validity);
+ } else {
+ pair = g_new0 (EMailPartValidityPair, 1);
+ pair->validity_type = validity_type;
+ pair->validity = camel_cipher_validity_clone (validity);
+
+ g_queue_push_tail (&part->validities, pair);
+ }
+}
+
+/**
+ * e_mail_part_get_validity:
+ * @part: An #EMailPart
+ * @validity_type: E_MAIL_PART_VALIDITY_* flags
+ *
+ * Returns, validity of @part contains any validity with the same bits
+ * as @validity_type set. It should contain all bits of it.
+ *
+ * Returns: a #CamelCipherValidity of the given type, %NULL if not found
+ *
+ * Since: 3.8
+ */
+CamelCipherValidity *
+e_mail_part_get_validity (EMailPart *part,
+ EMailPartValidityFlags validity_type)
+{
+ EMailPartValidityPair *pair;
+
+ g_return_val_if_fail (E_IS_MAIL_PART (part), NULL);
+
+ pair = mail_part_find_validity_pair (part, validity_type);
+
+ return (pair != NULL) ? pair->validity : NULL;
+}
+
+gboolean
+e_mail_part_has_validity (EMailPart *part)
+{
+ g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE);
+
+ return !g_queue_is_empty (&part->validities);
+}
+
+EMailPartValidityFlags
+e_mail_part_get_validity_flags (EMailPart *part)
+{
+ EMailPartValidityFlags flags = 0;
+ GList *head, *link;
+
+ g_return_val_if_fail (E_IS_MAIL_PART (part), 0);
+
+ head = g_queue_peek_head_link (&part->validities);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+
+ if (pair != NULL)
+ flags |= pair->validity_type;
+ }
+
+ return flags;
+}
+
+static gboolean
+from_matches_signers_alt_emails (CamelInternetAddress *from_address,
+ CamelCipherCertInfo *cinfo)
+{
+ GSList *props_link;
+ gboolean matches = FALSE;
+
+ for (props_link = cinfo->properties; props_link && !matches; props_link = g_slist_next (props_link)) {
+ const CamelCipherCertInfoProperty *prop = props_link->data;
+
+ if (prop && g_strcmp0 (prop->name, CAMEL_CIPHER_CERT_INFO_PROPERTY_SIGNERS_ALT_EMAILS) == 0 && prop->value) {
+ CamelInternetAddress *address;
+ gint count, ii;
+
+ address = camel_internet_address_new ();
+ count = camel_address_unformat (CAMEL_ADDRESS (address), prop->value);
+ for (ii = 0; ii < count && !matches; ii++) {
+ const gchar *email = NULL;
+
+ if (camel_internet_address_get (address, ii, NULL, &email) && email && *email) {
+ matches = camel_internet_address_find_address (from_address, email, NULL) >= 0;
+ }
+ }
+ g_object_unref (address);
+ break;
+ }
+ }
+
+ return matches;
+}
+
+void
+e_mail_part_verify_validity_sender (EMailPart *part,
+ CamelInternetAddress *from_address)
+{
+ GList *link;
+
+ g_return_if_fail (E_IS_MAIL_PART (part));
+
+ if (!from_address)
+ return;
+
+ for (link = g_queue_peek_head_link (&part->validities); link; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+
+ if (pair && pair->validity && !(pair->validity_type & E_MAIL_PART_VALIDITY_VERIFIED)) {
+ pair->validity_type |= E_MAIL_PART_VALIDITY_VERIFIED;
+
+ if (pair->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
+ GList *link2;
+ gboolean from_matches_signer = FALSE;
+
+ for (link2 = g_queue_peek_head_link (&pair->validity->sign.signers); link2 && !from_matches_signer; link2 = g_list_next (link2)) {
+ CamelCipherCertInfo *cinfo = link2->data;
+
+ if (cinfo->email && *cinfo->email) {
+ from_matches_signer = from_matches_signer ||
+ (from_address && camel_internet_address_find_address (from_address, cinfo->email, NULL) >= 0) ||
+ (from_address && from_matches_signers_alt_emails (from_address, cinfo));
+ }
+ }
+
+ if (!from_matches_signer)
+ pair->validity_type |= E_MAIL_PART_VALIDITY_SENDER_SIGNER_MISMATCH;
+ }
+ }
+ }
+}