/* * e-mail-formatter-headers.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "e-mail-formatter-extension.h" #include "e-mail-formatter-utils.h" #include "e-mail-inline-filter.h" typedef EMailFormatterExtension EMailFormatterHeaders; typedef EMailFormatterExtensionClass EMailFormatterHeadersClass; GType e_mail_formatter_headers_get_type (void); G_DEFINE_TYPE ( EMailFormatterHeaders, e_mail_formatter_headers, E_TYPE_MAIL_FORMATTER_EXTENSION) static const gchar *formatter_mime_types[] = { "application/vnd.evolution.headers", NULL }; static void format_short_headers (EMailFormatter *formatter, GString *buffer, CamelMedium *part, guint32 flags, GCancellable *cancellable) { const gchar *charset; CamelContentType *ct; gchar *hdr_charset; gchar *evolution_imagesdir; gchar *subject = NULL; struct _camel_header_address *addrs = NULL; struct _camel_header_raw *header; GString *from; gboolean is_rtl; if (g_cancellable_is_cancelled (cancellable)) return; ct = camel_mime_part_get_content_type ((CamelMimePart *) part); charset = camel_content_type_param (ct, "charset"); charset = camel_iconv_charset_name (charset); hdr_charset = e_mail_formatter_dup_charset (formatter); if (!hdr_charset) hdr_charset = e_mail_formatter_dup_default_charset (formatter); evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL); from = g_string_new (""); g_string_append_printf ( buffer, "", flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "block" : "none"); header = ((CamelMimePart *) part)->headers; while (header) { if (!g_ascii_strcasecmp (header->name, "From")) { GString *tmp; if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) { header = header->next; continue; } tmp = g_string_new (""); e_mail_formatter_format_address ( formatter, tmp, addrs, header->name, FALSE, !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE)); if (tmp->len) g_string_printf (from, _("From: %s"), tmp->str); g_string_free (tmp, TRUE); } else if (!g_ascii_strcasecmp (header->name, "Subject")) { gchar *buf = NULL; subject = camel_header_unfold (header->value); buf = camel_header_decode_string (subject, hdr_charset); g_free (subject); subject = camel_text_to_html ( buf, CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0); g_free (buf); } header = header->next; } g_free (hdr_charset); is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL; if (is_rtl) { g_string_append ( buffer, ""); } else { g_string_append ( buffer, ""); } g_string_append (buffer, "
"); if (from->len > 0) g_string_append_printf (buffer, "(%s) ", from->str); g_string_append (buffer, ""); if (subject != NULL && *subject != '\0') g_string_append (buffer, subject); else g_string_append (buffer, _("(no subject)")); g_string_append (buffer, ""); g_string_append (buffer, "
"); g_string_append (buffer, ""); if (subject != NULL && *subject != '\0') g_string_append (buffer, subject); else g_string_append (buffer, _("(no subject)")); g_string_append (buffer, ""); if (from->len > 0) g_string_append_printf (buffer, " (%s)", from->str); g_string_append (buffer, "
"); g_free (subject); if (addrs) camel_header_address_list_clear (&addrs); g_string_free (from, TRUE); g_free (evolution_imagesdir); } static void write_contact_picture (CamelMimePart *part, gint size, GString *buffer) { gchar *b64, *content_type; CamelDataWrapper *dw; CamelContentType *ct; GByteArray *ba; ba = NULL; dw = camel_medium_get_content (CAMEL_MEDIUM (part)); if (dw) { ba = camel_data_wrapper_get_byte_array (dw); } if (!ba || ba->len == 0) { if (camel_mime_part_get_filename (part)) { if (size >= 0) { g_string_append_printf ( buffer, "", size, camel_mime_part_get_filename (part)); } else { g_string_append_printf ( buffer, "", camel_mime_part_get_filename (part)); } } return; } b64 = g_base64_encode (ba->data, ba->len); ct = camel_mime_part_get_content_type (part); content_type = camel_content_type_simple (ct); if (size >= 0) { g_string_append_printf ( buffer, "", size, content_type, b64); } else { g_string_append_printf ( buffer, "", content_type, b64); } g_free (b64); g_free (content_type); } static CamelMimePart * load_picture_from_file (const gchar *mime_type, const gchar *filename, GCancellable *cancellable) { CamelMimePart *part; CamelStream *stream; CamelDataWrapper *dw; gchar *basename; stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL); if (stream == NULL) return NULL; dw = camel_data_wrapper_new (); camel_data_wrapper_construct_from_stream_sync ( dw, stream, cancellable, NULL); g_object_unref (stream); if (mime_type) camel_data_wrapper_set_mime_type (dw, mime_type); part = camel_mime_part_new (); camel_medium_set_content ((CamelMedium *) part, dw); g_object_unref (dw); basename = g_path_get_basename (filename); camel_mime_part_set_filename (part, basename); g_free (basename); return part; } static void format_full_headers (EMailFormatter *formatter, GString *buffer, CamelMedium *part, guint32 mode, guint32 flags, GCancellable *cancellable) { const gchar *charset; CamelContentType *ct; struct _camel_header_raw *header; gboolean have_icon = FALSE; const gchar *photo_name = NULL; gboolean face_decoded = FALSE, contact_has_photo = FALSE; guchar *face_header_value = NULL; gsize face_header_len = 0; gchar *header_sender = NULL, *header_from = NULL, *name; gboolean mail_from_delegate = FALSE; gchar *hdr_charset; gchar *evolution_imagesdir; if (g_cancellable_is_cancelled (cancellable)) return; ct = camel_mime_part_get_content_type ((CamelMimePart *) part); charset = camel_content_type_param (ct, "charset"); charset = camel_iconv_charset_name (charset); hdr_charset = e_mail_formatter_dup_charset (formatter); if (!hdr_charset) hdr_charset = e_mail_formatter_dup_default_charset (formatter); evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL); g_string_append_printf ( buffer, "", flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "none" : "block"); header = ((CamelMimePart *) part)->headers; while (header != NULL) { if (!g_ascii_strcasecmp (header->name, "Sender")) { struct _camel_header_address *addrs; GString *html; if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) break; html = g_string_new (""); name = e_mail_formatter_format_address ( formatter, html, addrs, header->name, FALSE, ~(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE)); header_sender = html->str; camel_header_address_list_clear (&addrs); g_string_free (html, FALSE); g_free (name); } else if (!g_ascii_strcasecmp (header->name, "From")) { struct _camel_header_address *addrs; GString *html; if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) break; html = g_string_new (""); name = e_mail_formatter_format_address ( formatter, html, addrs, header->name, FALSE, !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE)); header_from = html->str; camel_header_address_list_clear (&addrs); g_string_free (html, FALSE); g_free (name); } else if (!g_ascii_strcasecmp (header->name, "X-Evolution-Mail-From-Delegate")) { mail_from_delegate = TRUE; } header = header->next; } g_free (hdr_charset); if (header_sender && header_from && mail_from_delegate) { gchar *bold_sender, *bold_from; g_string_append ( buffer, ""); g_free (bold_sender); g_free (bold_from); } g_free (header_sender); g_free (header_from); g_string_append ( buffer, ""); if (photo_name) { gchar *name; name = g_uri_escape_string (photo_name, NULL, FALSE); g_string_append (buffer, ""); g_free (name); } if (!contact_has_photo && face_decoded) { CamelMimePart *part; part = camel_mime_part_new (); camel_mime_part_set_content ( (CamelMimePart *) part, (const gchar *) face_header_value, face_header_len, "image/png"); g_string_append (buffer, ""); g_object_unref (part); g_free (face_header_value); } if (have_icon) { GtkIconInfo *icon_info; CamelMimePart *iconpart = NULL; icon_info = gtk_icon_theme_lookup_icon ( gtk_icon_theme_get_default (), "evolution", 16, GTK_ICON_LOOKUP_NO_SVG); if (icon_info != NULL) { iconpart = load_picture_from_file ( "image/png", gtk_icon_info_get_filename (icon_info), cancellable); gtk_icon_info_free (icon_info); } if (iconpart) { g_string_append (buffer, ""); g_object_unref (iconpart); } } g_string_append (buffer, "
"); if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL) g_string_append ( buffer, "
"); else g_string_append ( buffer, ""); bold_sender = g_strconcat ("", header_sender, "", NULL); bold_from = g_strconcat ("", header_from, "", NULL); /* Translators: This message suggests to the receipients * that the sender of the mail is different from the one * listed in From field. */ g_string_append_printf ( buffer, _("This message was sent by %s on behalf of %s"), bold_sender, bold_from); g_string_append (buffer, "
" "\n"); g_free (evolution_imagesdir); /* dump selected headers */ if (mode & E_MAIL_FORMATTER_MODE_ALL_HEADERS) { header = ((CamelMimePart *) part)->headers; while (header != NULL) { e_mail_formatter_format_header ( formatter, buffer, part, header, E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS, charset); header = header->next; } } else { GQueue *headers_queue; GList *link; gint mailer_shown = FALSE; headers_queue = e_mail_formatter_dup_headers (formatter); link = g_queue_peek_head_link (headers_queue); while (link != NULL) { EMailFormatterHeader *h = link->data; gint mailer, face; header = ((CamelMimePart *) part)->headers; mailer = !g_ascii_strcasecmp (h->name, "X-Evolution-Mailer"); face = !g_ascii_strcasecmp (h->name, "Face"); while (header != NULL) { if (e_mail_formatter_get_show_sender_photo (formatter) && !photo_name && !g_ascii_strcasecmp (header->name, "From")) photo_name = header->value; if (!mailer_shown && mailer && ( !g_ascii_strcasecmp (header->name, "X-Mailer") || !g_ascii_strcasecmp (header->name, "User-Agent") || !g_ascii_strcasecmp (header->name, "X-Newsreader") || !g_ascii_strcasecmp (header->name, "X-MimeOLE"))) { struct _camel_header_raw xmailer, *use_header = NULL; if (!g_ascii_strcasecmp (header->name, "X-MimeOLE")) { for (use_header = header->next; use_header; use_header = use_header->next) { if (!g_ascii_strcasecmp (use_header->name, "X-Mailer") || !g_ascii_strcasecmp (use_header->name, "User-Agent") || !g_ascii_strcasecmp (use_header->name, "X-Newsreader")) { /* even we have X-MimeOLE, then use rather the standard one, when available */ break; } } } if (!use_header) use_header = header; xmailer.name = (gchar *) "X-Evolution-Mailer"; xmailer.value = use_header->value; mailer_shown = TRUE; e_mail_formatter_format_header ( formatter, buffer, part, &xmailer, h->flags, charset); if (strstr (use_header->value, "Evolution")) have_icon = TRUE; } else if (!face_decoded && face && !g_ascii_strcasecmp (header->name, "Face")) { gchar *cp = header->value; /* Skip over spaces */ while (*cp == ' ') cp++; face_header_value = g_base64_decode ( cp, &face_header_len); face_header_value = g_realloc ( face_header_value, face_header_len + 1); face_header_value[face_header_len] = 0; face_decoded = TRUE; /* Showing an encoded "Face" header makes little sense */ } else if (!g_ascii_strcasecmp (header->name, h->name) && !face) { e_mail_formatter_format_header ( formatter, buffer, part, header, h->flags, charset); } header = header->next; } link = g_list_next (link); } g_queue_free_full (headers_queue, (GDestroyNotify) e_mail_formatter_header_free); } g_string_append (buffer, "
"); g_string_append_printf ( buffer, "", name); g_string_append (buffer, ""); write_contact_picture (part, 48, buffer); g_string_append (buffer, ""); write_contact_picture (iconpart, 16, buffer); g_string_append (buffer, "
"); } static gboolean emfe_headers_format (EMailFormatterExtension *extension, EMailFormatter *formatter, EMailFormatterContext *context, EMailPart *part, CamelStream *stream, GCancellable *cancellable) { GString *buffer; const GdkRGBA white = { 1.0, 1.0, 1.0, 1.0 }; const GdkRGBA *body_rgba = &white; const GdkRGBA *header_rgba; if (g_cancellable_is_cancelled (cancellable)) return FALSE; if (!part->part) return FALSE; buffer = g_string_new (""); if (context->mode != E_MAIL_FORMATTER_MODE_PRINTING) body_rgba = e_mail_formatter_get_color ( formatter, E_MAIL_FORMATTER_COLOR_BODY); header_rgba = e_mail_formatter_get_color ( formatter, E_MAIL_FORMATTER_COLOR_HEADER); g_string_append_printf ( buffer, "
" "\n" "
\n", e_rgba_to_value (body_rgba), part->id, e_rgba_to_value (header_rgba)); if (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE) { g_string_append_printf ( buffer, "" "", EVOLUTION_IMAGESDIR, (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED) ? "plus.png" : "minus.png"); format_short_headers ( formatter, buffer, CAMEL_MEDIUM (part->part), context->flags, cancellable); } format_full_headers ( formatter, buffer, CAMEL_MEDIUM (part->part), context->mode, context->flags, cancellable); g_string_append (buffer, "
"); camel_stream_write_string (stream, buffer->str, cancellable, NULL); g_string_free (buffer, TRUE); return TRUE; } static void e_mail_formatter_headers_class_init (EMailFormatterExtensionClass *class) { class->mime_types = formatter_mime_types; class->priority = G_PRIORITY_LOW; class->format = emfe_headers_format; } static void e_mail_formatter_headers_init (EMailFormatterExtension *extension) { }