Bug 793240 - Let open attachments in default application easily
[evolution.git] / src / em-format / e-mail-formatter-attachment.c
blob8e88efefb5c0c5d5225b0c07d807775c67722458
1 /*
2 * e-mail-formatter-attachment.c
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-config.h"
20 #include <glib/gi18n-lib.h>
22 #include <shell/e-shell.h>
23 #include <shell/e-shell-window.h>
25 #include "e-mail-formatter-extension.h"
26 #include "e-mail-inline-filter.h"
27 #include "e-mail-part-attachment.h"
28 #include "e-mail-part-utils.h"
30 #define d(x)
32 typedef EMailFormatterExtension EMailFormatterAttachment;
33 typedef EMailFormatterExtensionClass EMailFormatterAttachmentClass;
35 GType e_mail_formatter_attachment_get_type (void);
37 G_DEFINE_TYPE (
38 EMailFormatterAttachment,
39 e_mail_formatter_attachment,
40 E_TYPE_MAIL_FORMATTER_EXTENSION)
42 static const gchar *formatter_mime_types[] = {
43 E_MAIL_PART_ATTACHMENT_MIME_TYPE,
44 "application/vnd.evolution.attachment-button",
45 NULL
48 static gboolean
49 emfe_attachment_format (EMailFormatterExtension *extension,
50 EMailFormatter *formatter,
51 EMailFormatterContext *context,
52 EMailPart *part,
53 GOutputStream *stream,
54 GCancellable *cancellable)
56 gchar *text, *html;
57 gchar *button_id;
58 EMailExtensionRegistry *registry;
59 GQueue *extensions;
60 EMailPartAttachment *empa;
61 CamelMimePart *mime_part;
62 CamelMimeFilterToHTMLFlags flags;
63 GOutputStream *content_stream = NULL;
64 GString *buffer;
65 gint icon_width, icon_height;
66 gchar *icon_uri;
67 gpointer attachment_ptr = NULL;
68 const gchar *attachment_part_id;
69 const gchar *part_id;
71 g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT (part), FALSE);
73 empa = (EMailPartAttachment *) part;
74 part_id = e_mail_part_get_id (part);
76 if ((context->mode == E_MAIL_FORMATTER_MODE_NORMAL) ||
77 (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) ||
78 (context->mode == E_MAIL_FORMATTER_MODE_ALL_HEADERS)) {
79 EAttachment *attachment;
80 GList *head, *link;
82 attachment = e_mail_part_attachment_ref_attachment (E_MAIL_PART_ATTACHMENT (part));
83 attachment_ptr = attachment;
85 head = g_queue_peek_head_link (&part->validities);
87 for (link = head; link != NULL; link = g_list_next (link)) {
88 EMailPartValidityPair *pair = link->data;
90 if (pair == NULL)
91 continue;
93 if ((pair->validity_type & E_MAIL_PART_VALIDITY_SIGNED) != 0)
94 e_attachment_set_signed (
95 attachment,
96 pair->validity->sign.status);
98 if ((pair->validity_type & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0)
99 e_attachment_set_encrypted (
100 attachment,
101 pair->validity->encrypt.status);
104 e_attachment_set_initially_shown (attachment, e_mail_part_should_show_inline (part));
106 e_mail_formatter_claim_attachment (formatter, attachment);
108 g_object_unref (attachment);
111 registry = e_mail_formatter_get_extension_registry (formatter);
113 extensions = e_mail_extension_registry_get_for_mime_type (
114 registry, empa->snoop_mime_type);
115 if (extensions == NULL)
116 extensions = e_mail_extension_registry_get_fallback (
117 registry, empa->snoop_mime_type);
119 /* If the attachment is requested as RAW, then call the
120 * handler directly and do not append any other code. */
121 if ((context->mode == E_MAIL_FORMATTER_MODE_RAW) ||
122 (context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) {
123 GList *head, *link;
124 gboolean success = FALSE;
126 if (extensions == NULL)
127 return FALSE;
129 if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
130 gchar *name;
131 EAttachment *attachment;
132 GFileInfo *file_info;
133 const gchar *display_name;
134 gchar *description;
136 attachment = e_mail_part_attachment_ref_attachment (
137 E_MAIL_PART_ATTACHMENT (part));
139 file_info = e_attachment_ref_file_info (attachment);
140 if (file_info)
141 display_name = g_file_info_get_display_name (file_info);
142 else
143 display_name = "";
145 description = e_attachment_dup_description (attachment);
146 if (description != NULL && *description != '\0') {
147 name = g_strdup_printf (
148 "<h2>Attachment: %s (%s)</h2>\n",
149 description, display_name);
150 } else {
151 name = g_strdup_printf (
152 "<h2>Attachment: %s</h2>\n",
153 display_name);
156 g_output_stream_write_all (
157 stream, name, strlen (name),
158 NULL, cancellable, NULL);
160 g_free (description);
161 g_free (name);
163 g_clear_object (&attachment);
164 g_clear_object (&file_info);
167 head = g_queue_peek_head_link (extensions);
169 for (link = head; link != NULL; link = g_list_next (link)) {
170 success = e_mail_formatter_extension_format (
171 E_MAIL_FORMATTER_EXTENSION (link->data),
172 formatter, context, part, stream, cancellable);
173 if (success)
174 break;
177 return success;
180 /* E_MAIL_FORMATTER_MODE_NORMAL: */
182 mime_part = e_mail_part_ref_mime_part (part);
183 text = e_mail_part_describe (mime_part, empa->snoop_mime_type);
184 flags = e_mail_formatter_get_text_format_flags (formatter);
185 html = camel_text_to_html (
186 text, flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
187 g_free (text);
188 g_object_unref (mime_part);
190 if (empa->part_id_with_attachment)
191 attachment_part_id = empa->part_id_with_attachment;
192 else
193 attachment_part_id = part_id;
195 button_id = g_strconcat (attachment_part_id, ".attachment_button", NULL);
197 if (!gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, &icon_width, &icon_height)) {
198 icon_width = 16;
199 icon_height = 16;
202 if (extensions != NULL) {
203 gboolean success = FALSE;
205 content_stream = g_memory_output_stream_new_resizable ();
207 if (empa->part_id_with_attachment != NULL) {
208 EMailPart *attachment_view_part;
210 attachment_view_part = e_mail_part_list_ref_part (
211 context->part_list,
212 empa->part_id_with_attachment);
214 /* Avoid recursion. */
215 if (attachment_view_part == part)
216 g_clear_object (&attachment_view_part);
218 if (attachment_view_part != NULL) {
219 success = e_mail_formatter_format_as (
220 formatter, context,
221 attachment_view_part,
222 content_stream, NULL,
223 cancellable);
224 g_object_unref (attachment_view_part);
227 } else {
228 GList *head, *link;
230 head = g_queue_peek_head_link (extensions);
232 for (link = head; link != NULL; link = g_list_next (link)) {
233 success = e_mail_formatter_extension_format (
234 E_MAIL_FORMATTER_EXTENSION (link->data),
235 formatter, context,
236 part, content_stream,
237 cancellable);
238 if (success)
239 break;
243 e_mail_part_attachment_set_expandable (empa, success);
246 icon_uri = e_mail_part_build_uri (
247 e_mail_part_list_get_folder (context->part_list),
248 e_mail_part_list_get_message_uid (context->part_list),
249 "part_id", G_TYPE_STRING, part_id,
250 "attachment_icon", G_TYPE_POINTER, attachment_ptr,
251 "size", G_TYPE_INT, icon_width,
252 NULL);
254 /* XXX Wild guess at the initial size. */
255 buffer = g_string_sized_new (8192);
257 g_string_append_printf (
258 buffer,
259 "<div class=\"attachment\">"
260 "<table width=\"100%%\" border=\"0\" style=\"border-spacing: 0px\">"
261 "<tr valign=\"middle\">"
262 "<td align=\"left\" width=\"1px\" style=\"white-space:pre;\">"
263 "<button type=\"button\" class=\"attachment-expander\" id=\"%s\" value=\"%p\" data=\"%s\" style=\"vertical-align:middle; margin:0px;\">"
264 "<img id=\"attachment-expander-img-%p\" src=\"gtk-stock://%s?size=%d\" width=\"%dpx\" height=\"%dpx\" style=\"vertical-align:middle;\">"
265 "<img src=\"%s\" width=\"%dpx\" height=\"%dpx\" style=\"vertical-align:middle;\">"
266 "</button>"
267 "<button type=\"button\" class=\"attachment-menu\" id=\"%s\" value=\"%p\" style=\"vertical-align:middle; margin:0px;\">"
268 "<img src=\"gtk-stock://x-evolution-arrow-down?size=%d\" width=\"%dpx\" height=\"%dpx\" style=\"vertical-align:middle;\">"
269 "</button>"
270 "</td><td align=\"left\">%s</td></tr>",
271 part_id, attachment_ptr, html, attachment_ptr,
272 e_mail_part_should_show_inline (part) ? "go-down" : e_mail_part_attachment_get_expandable (empa) ? "go-next" : "go-top",
273 GTK_ICON_SIZE_BUTTON, icon_width, icon_height,
274 icon_uri, icon_width, icon_height,
275 part_id, attachment_ptr, GTK_ICON_SIZE_BUTTON, icon_width, icon_height,
276 html);
278 g_free (icon_uri);
279 g_free (button_id);
280 g_free (html);
282 if (content_stream && e_mail_part_attachment_get_expandable (empa)) {
283 gchar *wrapper_element_id;
284 gconstpointer data;
285 gsize size;
287 wrapper_element_id = g_strdup_printf ("attachment-wrapper-%p", attachment_ptr);
289 data = g_memory_output_stream_get_data (
290 G_MEMORY_OUTPUT_STREAM (content_stream));
291 size = g_memory_output_stream_get_data_size (
292 G_MEMORY_OUTPUT_STREAM (content_stream));
294 g_string_append_printf (
295 buffer,
296 "<tr><td colspan=\"2\">"
297 "<div class=\"attachment-wrapper\" id=\"%s\"",
298 wrapper_element_id);
300 if (e_mail_part_should_show_inline (part)) {
301 g_string_append (buffer, ">");
302 g_string_append_len (buffer, data, size);
303 } else {
304 gchar *inner_html_data;
306 inner_html_data = g_markup_escape_text (data, size);
308 g_string_append_printf (buffer, " related-part-id=\"%s\" inner-html-data=\"%s\">",
309 attachment_part_id, inner_html_data);
311 g_free (inner_html_data);
314 g_string_append (buffer, "</div></td></tr>");
316 g_free (wrapper_element_id);
319 g_clear_object (&content_stream);
321 g_string_append (buffer, "</table></div>");
323 g_output_stream_write_all (
324 stream, buffer->str, buffer->len, NULL, cancellable, NULL);
326 g_string_free (buffer, TRUE);
328 return TRUE;
331 static void
332 e_mail_formatter_attachment_class_init (EMailFormatterExtensionClass *class)
334 class->display_name = _("Attachment");
335 class->description = _("Display as attachment");
336 class->mime_types = formatter_mime_types;
337 class->priority = G_PRIORITY_LOW;
338 class->format = emfe_attachment_format;
341 static void
342 e_mail_formatter_attachment_init (EMailFormatterExtension *extension)