No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-mail-formatter-headers.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-mail-formatter-headers.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * e-mail-formatter-headers.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "e-mail-format-extensions.h"
24
25 #include <glib/gi18n-lib.h>
26
27 #include <em-format/e-mail-formatter-extension.h>
28 #include <em-format/e-mail-formatter.h>
29 #include <em-format/e-mail-formatter-utils.h>
30 #include <em-format/e-mail-inline-filter.h>
31 #include <libemail-engine/e-mail-utils.h>
32 #include <libedataserver/libedataserver.h>
33 #include <e-util/e-util.h>
34 #include <shell/e-shell.h>
35
36 #include <camel/camel.h>
37
38 #include <string.h>
39
40 typedef struct _EMailFormatterHeaders {
41 GObject parent;
42 } EMailFormatterHeaders;
43
44 typedef struct _EMailFormatterHeadersClass {
45 GObjectClass parent_class;
46 } EMailFormatterHeadersClass;
47
48 static const gchar *formatter_mime_types[] = { "application/vnd.evolution.headers", NULL };
49
50 static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
51 static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
52
53 G_DEFINE_TYPE_EXTENDED (
54 EMailFormatterHeaders,
55 e_mail_formatter_headers,
56 G_TYPE_OBJECT,
57 0,
58 G_IMPLEMENT_INTERFACE (
59 E_TYPE_MAIL_EXTENSION,
60 e_mail_formatter_mail_extension_interface_init)
61 G_IMPLEMENT_INTERFACE (
62 E_TYPE_MAIL_FORMATTER_EXTENSION,
63 e_mail_formatter_formatter_extension_interface_init))
64
65 static void
66 format_short_headers (EMailFormatter *formatter,
67 GString *buffer,
68 CamelMedium *part,
69 guint32 flags,
70 GCancellable *cancellable)
71 {
72 const gchar *charset;
73 CamelContentType *ct;
74 const gchar *hdr_charset;
75 gchar *evolution_imagesdir;
76 gchar *subject = NULL;
77 struct _camel_header_address *addrs = NULL;
78 struct _camel_header_raw *header;
79 GString *from;
80 gboolean is_rtl;
81
82 if (g_cancellable_is_cancelled (cancellable))
83 return;
84
85 ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
86 charset = camel_content_type_param (ct, "charset");
87 charset = camel_iconv_charset_name (charset);
88 hdr_charset = e_mail_formatter_get_charset (formatter) ?
89 e_mail_formatter_get_charset (formatter) :
90 e_mail_formatter_get_default_charset (formatter);
91
92 evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
93 from = g_string_new ("");
94
95 g_string_append_printf (
96 buffer,
97 "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" "
98 "id=\"__evo-short-headers\" style=\"display: %s\">",
99 flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "block" : "none");
100
101 header = ((CamelMimePart *) part)->headers;
102 while (header) {
103 if (!g_ascii_strcasecmp (header->name, "From")) {
104 GString *tmp;
105 if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) {
106 header = header->next;
107 continue;
108 }
109 tmp = g_string_new ("");
110 e_mail_formatter_format_address (
111 formatter, tmp, addrs, header->name, FALSE,
112 !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
113
114 if (tmp->len)
115 g_string_printf (from, _("From: %s"), tmp->str);
116 g_string_free (tmp, TRUE);
117
118 } else if (!g_ascii_strcasecmp (header->name, "Subject")) {
119 gchar *buf = NULL;
120 subject = camel_header_unfold (header->value);
121 buf = camel_header_decode_string (subject, hdr_charset);
122 g_free (subject);
123 subject = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0);
124 g_free (buf);
125 }
126 header = header->next;
127 }
128
129 is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL;
130 if (is_rtl) {
131 g_string_append_printf (
132 buffer,
133 "<tr><td width=\"100%%\" align=\"right\">%s%s%s <strong>%s</strong></td></tr>",
134 from->len ? "(" : "", from->str, from->len ? ")" : "",
135 subject ? subject : _("(no subject)"));
136 } else {
137 g_string_append_printf (
138 buffer,
139 "<tr><td><strong>%s</strong> %s%s%s</td></tr>",
140 subject ? subject : _("(no subject)"),
141 from->len ? "(" : "", from->str, from->len ? ")" : "");
142 }
143
144 g_string_append (buffer, "</table>");
145
146 g_free (subject);
147 if (addrs)
148 camel_header_address_list_clear (&addrs);
149
150 g_string_free (from, TRUE);
151 g_free (evolution_imagesdir);
152 }
153
154 static void
155 write_contact_picture (CamelMimePart *part,
156 gint size,
157 GString *buffer)
158 {
159 gchar *b64, *content_type;
160 CamelDataWrapper *dw;
161 CamelContentType *ct;
162 GByteArray *ba;
163
164 ba = NULL;
165 dw = camel_medium_get_content (CAMEL_MEDIUM (part));
166 if (dw) {
167 ba = camel_data_wrapper_get_byte_array (dw);
168 }
169
170 if (!ba || ba->len == 0) {
171
172 if (camel_mime_part_get_filename (part)) {
173
174 if (size >= 0) {
175 g_string_append_printf (
176 buffer,
177 "<img width=\"%d\" src=\"evo-file://%s\" />",
178 size, camel_mime_part_get_filename (part));
179 } else {
180 g_string_append_printf (
181 buffer,
182 "<img src=\"evo-file://%s\" />",
183 camel_mime_part_get_filename (part));
184 }
185 }
186
187 return;
188 }
189
190 b64 = g_base64_encode (ba->data, ba->len);
191 ct = camel_mime_part_get_content_type (part);
192 content_type = camel_content_type_simple (ct);
193
194 if (size >= 0) {
195 g_string_append_printf (
196 buffer,
197 "<img width=\"%d\" src=\"data:%s;base64,%s\">",
198 size, content_type, b64);
199 } else {
200 g_string_append_printf (
201 buffer,
202 "<img src=\"data:%s;base64,%s\">",
203 content_type, b64);
204 }
205
206 g_free (b64);
207 g_free (content_type);
208 }
209
210 static CamelMimePart *
211 load_picture_from_file (const gchar *mime_type,
212 const gchar *filename,
213 GCancellable *cancellable)
214 {
215 CamelMimePart *part;
216 CamelStream *stream;
217 CamelDataWrapper *dw;
218 gchar *basename;
219
220 stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
221 if (stream == NULL)
222 return NULL;
223
224 dw = camel_data_wrapper_new ();
225 camel_data_wrapper_construct_from_stream_sync (
226 dw, stream, cancellable, NULL);
227 g_object_unref (stream);
228 if (mime_type)
229 camel_data_wrapper_set_mime_type (dw, mime_type);
230 part = camel_mime_part_new ();
231 camel_medium_set_content ((CamelMedium *) part, dw);
232 g_object_unref (dw);
233 basename = g_path_get_basename (filename);
234 camel_mime_part_set_filename (part, basename);
235 g_free (basename);
236
237 return part;
238 }
239
240 static void
241 format_full_headers (EMailFormatter *formatter,
242 GString *buffer,
243 CamelMedium *part,
244 guint32 mode,
245 guint32 flags,
246 GCancellable *cancellable)
247 {
248 const gchar *charset;
249 CamelContentType *ct;
250 struct _camel_header_raw *header;
251 gboolean have_icon = FALSE;
252 const gchar *photo_name = NULL;
253 gboolean face_decoded = FALSE, contact_has_photo = FALSE;
254 guchar *face_header_value = NULL;
255 gsize face_header_len = 0;
256 gchar *header_sender = NULL, *header_from = NULL, *name;
257 gboolean mail_from_delegate = FALSE;
258 const gchar *hdr_charset;
259 gchar *evolution_imagesdir;
260
261 if (g_cancellable_is_cancelled (cancellable))
262 return;
263
264 ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
265 charset = camel_content_type_param (ct, "charset");
266 charset = camel_iconv_charset_name (charset);
267 hdr_charset = e_mail_formatter_get_charset (formatter) ?
268 e_mail_formatter_get_charset (formatter) :
269 e_mail_formatter_get_default_charset (formatter);
270
271 evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
272
273 g_string_append_printf (
274 buffer,
275 "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" "
276 "id=\"__evo-full-headers\" style=\"display: %s\" width=\"100%%\">",
277 flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "none" : "block");
278
279 header = ((CamelMimePart *) part)->headers;
280 while (header) {
281 if (!g_ascii_strcasecmp (header->name, "Sender")) {
282 struct _camel_header_address *addrs;
283 GString *html;
284
285 if (!(addrs = camel_header_address_decode (header->value, hdr_charset)))
286 break;
287
288 html = g_string_new ("");
289 name = e_mail_formatter_format_address (
290 formatter, html, addrs, header->name, FALSE,
291 ~(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
292
293 header_sender = html->str;
294 camel_header_address_list_clear (&addrs);
295
296 g_string_free (html, FALSE);
297 g_free (name);
298 } else if (!g_ascii_strcasecmp (header->name, "From")) {
299 struct _camel_header_address *addrs;
300 GString *html;
301
302 if (!(addrs = camel_header_address_decode (header->value, hdr_charset)))
303 break;
304
305 html = g_string_new ("");
306 name = e_mail_formatter_format_address (
307 formatter, html, addrs, header->name, FALSE,
308 !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
309
310 header_from = html->str;
311 camel_header_address_list_clear (&addrs);
312
313 g_string_free (html, FALSE);
314 g_free (name);
315 } else if (!g_ascii_strcasecmp (header->name, "X-Evolution-Mail-From-Delegate")) {
316 mail_from_delegate = TRUE;
317 }
318
319 header = header->next;
320 }
321
322 if (header_sender && header_from && mail_from_delegate) {
323 gchar *bold_sender, *bold_from;
324
325 g_string_append (
326 buffer,
327 "<tr valign=\"top\"><td><table border=1 width=\"100%\" "
328 "cellspacing=2 cellpadding=2><tr>");
329 if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
330 g_string_append (
331 buffer, "<td align=\"right\" width=\"100%\">");
332 else
333 g_string_append (
334 buffer, "<td align=\"left\" width=\"100%\">");
335 bold_sender = g_strconcat ("<b>", header_sender, "</b>", NULL);
336 bold_from = g_strconcat ("<b>", header_from, "</b>", NULL);
337 /* Translators: This message suggests to the receipients
338 * that the sender of the mail is different from the one
339 * listed in From field. */
340 g_string_append_printf (
341 buffer,
342 _("This message was sent by %s on behalf of %s"),
343 bold_sender, bold_from);
344 g_string_append (buffer, "</td></tr></table></td></tr>");
345 g_free (bold_sender);
346 g_free (bold_from);
347 }
348
349 g_free (header_sender);
350 g_free (header_from);
351
352 g_string_append (
353 buffer,
354 "<tr valign=\"top\"><td width=\"100%\">"
355 "<table border=0 cellpadding=\"0\">\n");
356
357 g_free (evolution_imagesdir);
358
359 /* dump selected headers */
360 if (mode & E_MAIL_FORMATTER_MODE_ALL_HEADERS) {
361 header = ((CamelMimePart *) part)->headers;
362 while (header) {
363 e_mail_formatter_format_header (
364 formatter, buffer, part, header,
365 E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS, charset);
366 header = header->next;
367 }
368 } else {
369 GList *link;
370 gint mailer_shown = FALSE;
371
372 link = g_queue_peek_head_link (
373 (GQueue *) e_mail_formatter_get_headers (formatter));
374
375 while (link != NULL) {
376 EMailFormatterHeader *h = link->data;
377 gint mailer, face;
378
379 header = ((CamelMimePart *) part)->headers;
380 mailer = !g_ascii_strcasecmp (h->name, "X-Evolution-Mailer");
381 face = !g_ascii_strcasecmp (h->name, "Face");
382
383 while (header) {
384 if (e_mail_formatter_get_show_sender_photo (formatter) &&
385 !photo_name && !g_ascii_strcasecmp (header->name, "From"))
386 photo_name = header->value;
387
388 if (!mailer_shown && mailer && (
389 !g_ascii_strcasecmp (header->name, "X-Mailer") ||
390 !g_ascii_strcasecmp (header->name, "User-Agent") ||
391 !g_ascii_strcasecmp (header->name, "X-Newsreader") ||
392 !g_ascii_strcasecmp (header->name, "X-MimeOLE"))) {
393 struct _camel_header_raw xmailer, *use_header = NULL;
394
395 if (!g_ascii_strcasecmp (header->name, "X-MimeOLE")) {
396 for (use_header = header->next; use_header; use_header = use_header->next) {
397 if (!g_ascii_strcasecmp (use_header->name, "X-Mailer") ||
398 !g_ascii_strcasecmp (use_header->name, "User-Agent") ||
399 !g_ascii_strcasecmp (use_header->name, "X-Newsreader")) {
400 /* even we have X-MimeOLE, then use rather the standard one, when available */
401 break;
402 }
403 }
404 }
405
406 if (!use_header)
407 use_header = header;
408
409 xmailer.name = (gchar *) "X-Evolution-Mailer";
410 xmailer.value = use_header->value;
411 mailer_shown = TRUE;
412
413 e_mail_formatter_format_header (
414 formatter, buffer, part,
415 &xmailer, h->flags, charset);
416 if (strstr (use_header->value, "Evolution"))
417 have_icon = TRUE;
418 } else if (!face_decoded && face && !g_ascii_strcasecmp (header->name, "Face")) {
419 gchar *cp = header->value;
420
421 /* Skip over spaces */
422 while (*cp == ' ')
423 cp++;
424
425 face_header_value = g_base64_decode (
426 cp, &face_header_len);
427 face_header_value = g_realloc (
428 face_header_value,
429 face_header_len + 1);
430 face_header_value[face_header_len] = 0;
431 face_decoded = TRUE;
432 /* Showing an encoded "Face" header makes little sense */
433 } else if (!g_ascii_strcasecmp (header->name, h->name) && !face) {
434 e_mail_formatter_format_header (
435 formatter, buffer, part,
436 header, h->flags, charset);
437 }
438
439 header = header->next;
440 }
441
442 link = g_list_next (link);
443 }
444 }
445
446 g_string_append (buffer, "</table></td>");
447
448 if (photo_name) {
449 gboolean only_local_photo;
450 gchar *name;
451
452 name = g_uri_escape_string (photo_name, NULL, FALSE);
453 only_local_photo = e_mail_formatter_get_only_local_photos (formatter);
454 g_string_append (buffer, "<td align=\"right\" valign=\"top\">");
455
456 g_string_append_printf (
457 buffer,
458 "<img src=\"mail://contact-photo?mailaddr=&only-local-photo=1\" "
459 "data-mailaddr=\"%s\" %s id=\"__evo-contact-photo\"/>",
460 name, only_local_photo ? "data-onlylocal=1" : "");
461 g_string_append (buffer, "</td>");
462
463 g_free (name);
464 }
465
466 if (!contact_has_photo && face_decoded) {
467 CamelMimePart *part;
468
469 part = camel_mime_part_new ();
470 camel_mime_part_set_content (
471 (CamelMimePart *) part,
472 (const gchar *) face_header_value,
473 face_header_len, "image/png");
474
475 g_string_append (buffer, "<td align=\"right\" valign=\"top\">");
476 write_contact_picture (part, 48, buffer);
477 g_string_append (buffer, "</td>");
478
479 g_object_unref (part);
480 g_free (face_header_value);
481 }
482
483 if (have_icon) {
484 GtkIconInfo *icon_info;
485 CamelMimePart *iconpart = NULL;
486
487 icon_info = gtk_icon_theme_lookup_icon (
488 gtk_icon_theme_get_default (),
489 "evolution", 16, GTK_ICON_LOOKUP_NO_SVG);
490 if (icon_info != NULL) {
491 iconpart = load_picture_from_file (
492 "image/png", gtk_icon_info_get_filename (icon_info),
493 cancellable);
494 gtk_icon_info_free (icon_info);
495 }
496 if (iconpart) {
497 g_string_append (buffer, "<td align=\"right\" valign=\"top\">");
498 write_contact_picture (iconpart, 16, buffer);
499 g_string_append (buffer, "</td>");
500
501 g_object_unref (iconpart);
502 }
503 }
504
505 g_string_append (buffer, "</tr></table>");
506 }
507
508 static gboolean
509 emfe_headers_format (EMailFormatterExtension *extension,
510 EMailFormatter *formatter,
511 EMailFormatterContext *context,
512 EMailPart *part,
513 CamelStream *stream,
514 GCancellable *cancellable)
515 {
516 GString *buffer;
517 gint bg_color;
518
519 if (g_cancellable_is_cancelled (cancellable))
520 return FALSE;
521
522 if (!part->part)
523 return FALSE;
524
525 buffer = g_string_new ("");
526
527 if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
528 GdkColor white = { 0, G_MAXUINT16, G_MAXUINT16, G_MAXUINT16 };
529 bg_color = e_color_to_value (&white);
530 } else {
531 bg_color = e_color_to_value ((GdkColor *)
532 e_mail_formatter_get_color (
533 formatter, E_MAIL_FORMATTER_COLOR_BODY));
534 }
535
536 g_string_append_printf (
537 buffer,
538 "<div class=\"headers\" style=\"background: #%06x;\" id=\"%s\">"
539 "<table border=\"0\" width=\"100%%\" style=\"color: #%06x;\">\n"
540 "<tr><td valign=\"top\" width=\"16\">\n",
541 bg_color,
542 part->id,
543 e_color_to_value ((GdkColor *)
544 e_mail_formatter_get_color (
545 formatter,
546 E_MAIL_FORMATTER_COLOR_HEADER)));
547
548 if (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE) {
549 g_string_append_printf (
550 buffer,
551 "<img src=\"evo-file://%s/%s\" class=\"navigable\" "
552 "id=\"__evo-collapse-headers-img\" />"
553 "</td><td>",
554 EVOLUTION_IMAGESDIR,
555 (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED) ?
556 "plus.png" : "minus.png");
557
558 format_short_headers (formatter, buffer,
559 (CamelMedium *) part->part, context->flags, cancellable);
560 }
561
562 format_full_headers (formatter, buffer,
563 (CamelMedium *) part->part, context->mode, context->flags, cancellable);
564
565 g_string_append (buffer, "</td></tr></table></div>");
566
567 camel_stream_write_string (stream, buffer->str, cancellable, NULL);
568
569 g_string_free (buffer, TRUE);
570
571 return TRUE;
572 }
573
574 static const gchar *
575 emfe_headers_get_display_name (EMailFormatterExtension *extension)
576 {
577 return NULL;
578 }
579
580 static const gchar *
581 emfe_headers_get_description (EMailFormatterExtension *extension)
582 {
583 return NULL;
584 }
585
586 static const gchar **
587 emfe_headers_mime_types (EMailExtension *extension)
588 {
589 return formatter_mime_types;
590 }
591
592 static void
593 e_mail_formatter_headers_class_init (EMailFormatterHeadersClass *class)
594 {
595 }
596
597 static void
598 e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
599 {
600 iface->format = emfe_headers_format;
601 iface->get_display_name = emfe_headers_get_display_name;
602 iface->get_description = emfe_headers_get_description;
603 }
604
605 static void
606 e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
607 {
608 iface->mime_types = emfe_headers_mime_types;
609 }
610
611 static void
612 e_mail_formatter_headers_init (EMailFormatterHeaders *formatter)
613 {
614
615 }