static gboolean
emfe_error_format (EMailFormatterExtension *extension,
                   EMailFormatter *formatter,
                   EMailFormatterContext *context,
                   EMailPart *part,
                   GOutputStream *stream,
                   GCancellable *cancellable)
{
	GOutputStream *filtered_stream;
	CamelMimeFilter *filter;
	CamelMimePart *mime_part;
	CamelDataWrapper *dw;
	const gchar *string;
	gchar *html;

	mime_part = e_mail_part_ref_mime_part (part);
	dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));

	html = g_strdup_printf (
		"<div class=\"part-container -e-mail-formatter-frame-color "
		"-e-mail-formatter-body-color -e-web-view-text-color\">"
		"<div class=\"part-container-inner-margin pre\">\n"
		"<table border=\"0\" cellspacing=\"10\" "
		"cellpadding=\"0\" width=\"100%%\">\n"
		"<tr valign=\"top\"><td width=50>"
		"<img src=\"gtk-stock://%s/?size=%d\" /></td>\n"
		"<td style=\"color: red;\">",
		"dialog-error", GTK_ICON_SIZE_DIALOG);

	g_output_stream_write_all (
		stream, html, strlen (html), NULL, cancellable, NULL);

	g_free (html);

	filter = camel_mime_filter_tohtml_new (
		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
	filtered_stream = camel_filter_output_stream_new (stream, filter);
	g_object_unref (filter);

	camel_data_wrapper_decode_to_output_stream_sync (
		dw, filtered_stream, cancellable, NULL);
	g_output_stream_flush (filtered_stream, cancellable, NULL);

	g_object_unref (filtered_stream);

	string = "</td></tr></table></div></div>";

	g_output_stream_write_all (
		stream, string, strlen (string), NULL, cancellable, NULL);

	g_object_unref (mime_part);

	return TRUE;
}
Exemple #2
0
static gboolean
emqfe_headers_format (EMailFormatterExtension *extension,
                      EMailFormatter *formatter,
                      EMailFormatterContext *context,
                      EMailPart *part,
                      GOutputStream *stream,
                      GCancellable *cancellable)
{
	CamelContentType *ct;
	CamelMimePart *mime_part;
	const gchar *charset;
	GString *buffer;
	gchar **default_headers;
	guint ii, length = 0;

	g_return_val_if_fail (E_IS_MAIL_PART_HEADERS (part), FALSE);

	mime_part = e_mail_part_ref_mime_part (part);

	ct = camel_mime_part_get_content_type (mime_part);
	charset = camel_content_type_param (ct, "charset");
	charset = camel_iconv_charset_name (charset);

	buffer = g_string_new ("");

	/* dump selected headers */

	default_headers = e_mail_part_headers_dup_default_headers (
		E_MAIL_PART_HEADERS (part));
	if (default_headers != NULL)
		length = g_strv_length (default_headers);

	for (ii = 0; ii < length; ii++)
		emfqe_format_header (
			formatter, context, buffer, part,
			default_headers[ii], charset);

	g_strfreev (default_headers);

	g_string_append (buffer, HEADER_PREFIX);
	g_string_append (buffer, "<br>");
	g_string_append (buffer, HEADER_SUFFIX);

	g_output_stream_write_all (
		stream, buffer->str, buffer->len, NULL, cancellable, NULL);

	g_string_free (buffer, TRUE);

	g_object_unref (mime_part);

	return TRUE;
}
static gboolean
emfe_attachment_format (EMailFormatterExtension *extension,
                        EMailFormatter *formatter,
                        EMailFormatterContext *context,
                        EMailPart *part,
                        GOutputStream *stream,
                        GCancellable *cancellable)
{
	gchar *text, *html;
	gchar *button_id;
	EAttachmentStore *store;
	EMailExtensionRegistry *registry;
	GQueue *extensions;
	EMailPartAttachment *empa;
	CamelMimePart *mime_part;
	CamelMimeFilterToHTMLFlags flags;
	GString *buffer;
	const gchar *attachment_part_id;
	const gchar *part_id;

	g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT (part), FALSE);

	empa = (EMailPartAttachment *) part;
	part_id = e_mail_part_get_id (part);

	if ((context->mode == E_MAIL_FORMATTER_MODE_NORMAL) ||
	    (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) ||
	    (context->mode == E_MAIL_FORMATTER_MODE_ALL_HEADERS)) {
		EAttachment *attachment;
		GList *head, *link;

		attachment = e_mail_part_attachment_ref_attachment (
			E_MAIL_PART_ATTACHMENT (part));

		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 & E_MAIL_PART_VALIDITY_SIGNED) != 0)
				e_attachment_set_signed (
					attachment,
					pair->validity->sign.status);

			if ((pair->validity_type & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0)
				e_attachment_set_encrypted (
					attachment,
					pair->validity->encrypt.status);
		}

		store = find_attachment_store (context->part_list, part);
		if (store) {
			GList *attachments = e_attachment_store_get_attachments (store);
			if (!g_list_find (attachments, attachment)) {
				e_attachment_store_add_attachment (
					store, attachment);
			}
			g_list_free (attachments);
		} else {
			g_warning ("Failed to locate attachment-bar for %s", part_id);
		}

		g_object_unref (attachment);
	}

	registry = e_mail_formatter_get_extension_registry (formatter);

	extensions = e_mail_extension_registry_get_for_mime_type (
		registry, empa->snoop_mime_type);
	if (extensions == NULL)
		extensions = e_mail_extension_registry_get_fallback (
			registry, empa->snoop_mime_type);

	/* If the attachment is requested as RAW, then call the
	 * handler directly and do not append any other code. */
	if ((context->mode == E_MAIL_FORMATTER_MODE_RAW) ||
	    (context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) {
		GList *head, *link;
		gboolean success = FALSE;

		if (extensions == NULL)
			return FALSE;

		if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
			gchar *name;
			EAttachment *attachment;
			GFileInfo *file_info;
			const gchar *display_name;
			gchar *description;

			attachment = e_mail_part_attachment_ref_attachment (
				E_MAIL_PART_ATTACHMENT (part));

			file_info = e_attachment_ref_file_info (attachment);
			display_name = g_file_info_get_display_name (file_info);

			description = e_attachment_dup_description (attachment);
			if (description != NULL && *description != '\0') {
				name = g_strdup_printf (
					"<h2>Attachment: %s (%s)</h2>\n",
					description, display_name);
			} else {
				name = g_strdup_printf (
					"<h2>Attachment: %s</h2>\n",
					display_name);
			}

			g_output_stream_write_all (
				stream, name, strlen (name),
				NULL, cancellable, NULL);

			g_free (description);
			g_free (name);

			g_object_unref (attachment);
			g_object_unref (file_info);
		}

		head = g_queue_peek_head_link (extensions);

		for (link = head; link != NULL; link = g_list_next (link)) {
			success = e_mail_formatter_extension_format (
				E_MAIL_FORMATTER_EXTENSION (link->data),
				formatter, context, part, stream, cancellable);
			if (success)
				break;
		}

		return success;
	}

	/* E_MAIL_FORMATTER_MODE_NORMAL: */

	mime_part = e_mail_part_ref_mime_part (part);
	text = e_mail_part_describe (mime_part, empa->snoop_mime_type);
	flags = e_mail_formatter_get_text_format_flags (formatter);
	html = camel_text_to_html (
		text, flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
	g_free (text);
	g_object_unref (mime_part);

	if (empa->attachment_view_part_id)
		attachment_part_id = empa->attachment_view_part_id;
	else
		attachment_part_id = part_id;

	button_id = g_strconcat (attachment_part_id, ".attachment_button", NULL);

	/* XXX Wild guess at the initial size. */
	buffer = g_string_sized_new (8192);

	g_string_append_printf (
		buffer,
		"<div class=\"attachment\">"
		"<table width=\"100%%\" border=\"0\">"
		"<tr valign=\"middle\">"
		"<td align=\"left\" width=\"100\">"
		"<object type=\"application/vnd.evolution.widget.attachment-button\" "
		"height=\"20\" width=\"100\" data=\"%s\" id=\"%s\"></object>"
		"</td>"
		"<td align=\"left\">%s</td>"
		"</tr>", part_id, button_id, html);

	g_free (button_id);
	g_free (html);

	if (extensions != NULL) {
		GOutputStream *content_stream;
		gboolean success = FALSE;

		content_stream = g_memory_output_stream_new_resizable ();

		if (empa->attachment_view_part_id != NULL) {
			EMailPart *attachment_view_part;

			attachment_view_part = e_mail_part_list_ref_part (
				context->part_list,
				empa->attachment_view_part_id);

			/* Avoid recursion. */
			if (attachment_view_part == part)
				g_clear_object (&attachment_view_part);

			if (attachment_view_part != NULL) {
				success = e_mail_formatter_format_as (
					formatter, context,
					attachment_view_part,
					content_stream, NULL,
					cancellable);
				g_object_unref (attachment_view_part);
			}

		} else {
			GList *head, *link;

			head = g_queue_peek_head_link (extensions);

			for (link = head; link != NULL; link = g_list_next (link)) {
				success = e_mail_formatter_extension_format (
					E_MAIL_FORMATTER_EXTENSION (link->data),
					formatter, context,
					part, content_stream,
					cancellable);
				if (success)
					break;
			}
		}

		if (success) {
			gchar *wrapper_element_id;
			gconstpointer data;
			gsize size;

			wrapper_element_id = g_strconcat (
				attachment_part_id, ".wrapper", NULL);

			data = g_memory_output_stream_get_data (
				G_MEMORY_OUTPUT_STREAM (content_stream));
			size = g_memory_output_stream_get_data_size (
				G_MEMORY_OUTPUT_STREAM (content_stream));

			g_string_append_printf (
				buffer,
				"<tr><td colspan=\"2\">"
				"<div class=\"attachment-wrapper\" id=\"%s\">",
				wrapper_element_id);

			g_string_append_len (buffer, data, size);

			g_string_append (buffer, "</div></td></tr>");

			g_free (wrapper_element_id);
		}

		g_object_unref (content_stream);
	}

	g_string_append (buffer, "</table></div>");

	g_output_stream_write_all (
		stream, buffer->str, buffer->len, NULL, cancellable, NULL);

	g_string_free (buffer, TRUE);

	return TRUE;
}
Exemple #4
0
static void
emfqe_format_header (EMailFormatter *formatter,
		     EMailFormatterContext *context,
                     GString *buffer,
                     EMailPart *part,
                     const gchar *header_name,
                     const gchar *charset)
{
	CamelMimePart *mime_part;
	EMailFormatterHeaderFlags flags;
	gchar *canon_name, *buf, *value = NULL;
	const gchar *txt, *label;
	gboolean addrspec = FALSE;
	gint is_html = FALSE;
	gint i;

	/* Skip Face header in prints, which includes also message forward */
	if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING &&
	    g_ascii_strcasecmp (header_name, "Face") == 0)
		return;

	flags = E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE;

	canon_name = g_alloca (strlen (header_name) + 1);
	strcpy (canon_name, header_name);
	e_mail_formatter_canon_header_name (canon_name);

	/* Never quote Bcc/Resent-Bcc headers. */
	if (g_str_equal (canon_name, "Bcc"))
		return;
	if (g_str_equal (canon_name, "Resent-Bcc"))
		return;

	mime_part = e_mail_part_ref_mime_part (part);

	for (i = 0; addrspec_hdrs[i]; i++) {
		if (g_str_equal (canon_name, addrspec_hdrs[i])) {
			addrspec = TRUE;
			break;
		}
	}

	label = _(canon_name);

	if (addrspec) {
		CamelMedium *medium;
		struct _camel_header_address *addrs;
		GString *html;
		gchar *charset;

		medium = CAMEL_MEDIUM (mime_part);
		txt = camel_medium_get_header (medium, canon_name);
		if (txt == NULL)
			return;

		charset = e_mail_formatter_dup_charset (formatter);
		if (!charset)
			charset = e_mail_formatter_dup_default_charset (formatter);

		buf = camel_header_unfold (txt);
		addrs = camel_header_address_decode (txt, charset);
		g_free (charset);

		if (addrs == NULL) {
			g_free (buf);
			return;
		}

		g_free (buf);

		html = g_string_new ("");
		e_mail_formatter_format_address (formatter, html,
			addrs, canon_name, FALSE, FALSE);
		camel_header_address_unref (addrs);
		txt = value = html->str;
		g_string_free (html, FALSE);
		flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
		is_html = TRUE;

	} else if (g_str_equal (canon_name, "Subject")) {
		CamelMimeMessage *message;

		message = CAMEL_MIME_MESSAGE (mime_part);
		txt = camel_mime_message_get_subject (message);
		label = _("Subject");
		flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;

	} else if (g_str_equal (canon_name, "X-Evolution-Mailer")) {
		CamelMedium *medium;

		medium = CAMEL_MEDIUM (mime_part);
		txt = camel_medium_get_header (medium, "x-mailer");
		if (txt == NULL)
			txt = camel_medium_get_header (medium, "user-agent");
		if (txt == NULL)
			txt = camel_medium_get_header (medium, "x-newsreader");
		if (txt == NULL)
			txt = camel_medium_get_header (medium, "x-mimeole");
		if (txt == NULL)
			return;

		txt = value = camel_header_format_ctext (txt, charset);

		label = _("Mailer");
		flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;

	} else if (g_str_equal (canon_name, "Date") ||
		   g_str_equal (canon_name, "Resent-Date")) {
		CamelMedium *medium;

		medium = CAMEL_MEDIUM (mime_part);
		txt = camel_medium_get_header (medium, canon_name);
		if (txt == NULL)
			return;

		flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;

	} else {
		CamelMedium *medium;

		medium = CAMEL_MEDIUM (mime_part);
		txt = camel_medium_get_header (medium, canon_name);
		buf = camel_header_unfold (txt);
		txt = value = camel_header_decode_string (txt, charset);
		g_free (buf);
	}

	emfqe_format_text_header (formatter, buffer, label, txt, flags, is_html);

	g_free (value);

	g_object_unref (mime_part);
}
static gboolean
emqfe_text_plain_format (EMailFormatterExtension *extension,
                         EMailFormatter *formatter,
                         EMailFormatterContext *context,
                         EMailPart *part,
                         GOutputStream *stream,
                         GCancellable *cancellable)
{
	GOutputStream *filtered_stream;
	GOutputStream *temp_stream;
	CamelMimeFilter *filter;
	CamelMimePart *mime_part;
	CamelContentType *type;
	EMailFormatterQuoteContext *qf_context;
	CamelMimeFilterToHTMLFlags text_flags;
	const gchar *format;
	guint32 rgb = 0x737373;

	mime_part = e_mail_part_ref_mime_part (part);
	if (mime_part == NULL)
		return FALSE;

	qf_context = (EMailFormatterQuoteContext *) context;

	text_flags =
		CAMEL_MIME_FILTER_TOHTML_PRE |
		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
		CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;

	/* XXX Should we define a separate EMailFormatter property
	 *     for using CAMEL_MIME_FILTER_TOHTML_QUOTE_CITATION? */
	if (e_mail_formatter_get_mark_citations (formatter))
		text_flags |= CAMEL_MIME_FILTER_TOHTML_QUOTE_CITATION;

	/* Check for RFC 2646 flowed text. */
	type = camel_mime_part_get_content_type (mime_part);
	if (camel_content_type_is (type, "text", "plain")
	    && (format = camel_content_type_param (type, "format"))
	    && !g_ascii_strcasecmp (format, "flowed"))
		text_flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;

	filtered_stream = g_object_ref (stream);

	if ((qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG) == 0) {
		filter = e_mail_stripsig_filter_new (TRUE);
		temp_stream = camel_filter_output_stream_new (
			filtered_stream, filter);
		g_filter_output_stream_set_close_base_stream (
			G_FILTER_OUTPUT_STREAM (temp_stream), FALSE);
		g_object_unref (filtered_stream);
		filtered_stream = temp_stream;
		g_object_unref (filter);
	}

	filter = camel_mime_filter_tohtml_new (text_flags, rgb);
	temp_stream = camel_filter_output_stream_new (filtered_stream, filter);
	g_filter_output_stream_set_close_base_stream (
		G_FILTER_OUTPUT_STREAM (temp_stream), FALSE);
	g_object_unref (filtered_stream);
	filtered_stream = temp_stream;
	g_object_unref (filter);

	e_mail_formatter_format_text (
		formatter, part, filtered_stream, cancellable);

	g_output_stream_flush (filtered_stream, cancellable, NULL);
	g_object_unref (filtered_stream);

	g_object_unref (mime_part);

	return TRUE;
}
Exemple #6
0
static gboolean
emfe_image_format (EMailFormatterExtension *extension,
                   EMailFormatter *formatter,
                   EMailFormatterContext *context,
                   EMailPart *part,
                   GOutputStream *stream,
                   GCancellable *cancellable)
{
	gchar *content;
	CamelMimePart *mime_part;
	CamelDataWrapper *dw;
	GBytes *bytes;
	GOutputStream *raw_content;

	if (g_cancellable_is_cancelled (cancellable))
		return FALSE;

	mime_part = e_mail_part_ref_mime_part (part);
	dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
	g_return_val_if_fail (dw, FALSE);

	raw_content = g_memory_output_stream_new_resizable ();
	camel_data_wrapper_decode_to_output_stream_sync (
		dw, raw_content, cancellable, NULL);
	g_output_stream_close (raw_content, NULL, NULL);

	bytes = g_memory_output_stream_steal_as_bytes (
		G_MEMORY_OUTPUT_STREAM (raw_content));

	if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {

		if (!e_mail_formatter_get_animate_images (formatter)) {

			gchar *buff;
			gsize len;

			e_mail_part_animation_extract_frame (
				bytes, &buff, &len);

			g_output_stream_write_all (
				stream, buff, len, NULL, cancellable, NULL);

			g_free (buff);

		} else {
			gconstpointer data;
			gsize size;

			data = g_bytes_get_data (bytes, &size);

			g_output_stream_write_all (
				stream, data, size, NULL, cancellable, NULL);
		}

	} else {
		gchar *buffer;
		const gchar *mime_type;

		if (!e_mail_formatter_get_animate_images (formatter)) {

			gchar *buff;
			gsize len;

			e_mail_part_animation_extract_frame (
				bytes, &buff, &len);

			content = g_base64_encode ((guchar *) buff, len);
			g_free (buff);

		} else {
			gconstpointer data;
			gsize size;

			data = g_bytes_get_data (bytes, &size);
			content = g_base64_encode (data, size);
		}

		mime_type = e_mail_part_get_mime_type (part);
		if (mime_type == NULL)
			mime_type = "image/*";

		/* The image is already base64-encrypted so we can directly
		 * paste it to the output */
		buffer = g_strdup_printf (
			"<img src=\"data:%s;base64,%s\" "
			"     style=\"max-width: 100%%;\" />",
			mime_type, content);

		g_output_stream_write_all (
			stream, buffer, strlen (buffer),
			NULL, cancellable, NULL);

		g_free (buffer);
		g_free (content);
	}

	g_bytes_unref (bytes);

	g_object_unref (raw_content);

	g_object_unref (mime_part);

	return TRUE;
}
static gboolean
emfpe_headers_format (EMailFormatterExtension *extension,
                      EMailFormatter *formatter,
                      EMailFormatterContext *context,
                      EMailPart *part,
                      GOutputStream *stream,
                      GCancellable *cancellable)
{
	EMailPartHeaders *headers_part;
	GtkTreeModel *tree_model;
	GtkTreeIter iter;
	gboolean iter_valid;
	GString *str, *tmp;
	gchar *subject;
	const gchar *buf;
	gint attachments_count;
	gchar *part_id_prefix;
	CamelMimePart *mime_part;
	GQueue queue = G_QUEUE_INIT;
	GList *head, *link;
	const gchar *part_id;

	g_return_val_if_fail (E_IS_MAIL_PART_HEADERS (part), FALSE);

	mime_part = e_mail_part_ref_mime_part (part);

	buf = camel_medium_get_header (CAMEL_MEDIUM (mime_part), "subject");
	subject = camel_header_decode_string (buf, "UTF-8");
	str = g_string_new ("");
	g_string_append_printf (str, "<h1>%s</h1>\n", subject);
	g_free (subject);

	g_string_append (
		str,
		"<table border=\"0\" cellspacing=\"5\" "
		"cellpadding=\"0\" class=\"printing-header\">\n");

	headers_part = E_MAIL_PART_HEADERS (part);
	tree_model = e_mail_part_headers_ref_print_model (headers_part);
	iter_valid = gtk_tree_model_get_iter_first (tree_model, &iter);

	while (iter_valid) {
		gchar *header_name = NULL;
		gchar *header_value = NULL;
		gboolean include = FALSE;

		gtk_tree_model_get (
			tree_model, &iter,
			E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_INCLUDE,
			&include,
			E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_HEADER_NAME,
			&header_name,
			E_MAIL_PART_HEADERS_PRINT_MODEL_COLUMN_HEADER_VALUE,
			&header_value,
			-1);

		if (include)
			e_mail_formatter_format_header (
				formatter, str,
				header_name, header_value,
				E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS,
				"UTF-8");

		g_free (header_name);
		g_free (header_value);

		iter_valid = gtk_tree_model_iter_next (tree_model, &iter);
	}

	g_object_unref (tree_model);

	/* 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 encrpyted"));
		}

		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 encrpyted"));
		}

		break;
	}

	if (tmp->len > 0) {
		e_mail_formatter_format_header (
			formatter, str,
			_("Security"), tmp->str,
			E_MAIL_FORMATTER_HEADER_FLAG_BOLD |
			E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, "UTF-8");
	}
	g_string_free (tmp, TRUE);

	/* Count attachments and display the number as a header */
	attachments_count = 0;

	for (link = head; link != NULL; link = g_list_next (link)) {
		EMailPart *mail_part = E_MAIL_PART (link->data);

		if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix))
			continue;

		if (!e_mail_part_get_is_attachment (mail_part))
			continue;

		if (mail_part->is_hidden)
			continue;

		if (e_mail_part_get_cid (mail_part) != NULL)
			continue;

		attachments_count++;
	}

	if (attachments_count > 0) {
		gchar *header_value;

		header_value = g_strdup_printf ("%d", attachments_count);
		e_mail_formatter_format_header (
			formatter, str,
			_("Attachments"), header_value,
			E_MAIL_FORMATTER_HEADER_FLAG_BOLD |
			E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, "UTF-8");
		g_free (header_value);
	}

	while (!g_queue_is_empty (&queue))
		g_object_unref (g_queue_pop_head (&queue));

	g_string_append (str, "</table>");

	g_output_stream_write_all (
		stream, str->str, str->len, NULL, cancellable, NULL);

	g_string_free (str, TRUE);
	g_free (part_id_prefix);

	g_object_unref (mime_part);

	return TRUE;
}