evolution-3.6.4/em-format/e-mail-formatter-headers.c

No issues found

Incomplete coverage

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
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  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 }