evolution-3.6.4/modules/text-highlight/e-mail-formatter-text-highlight.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-mail-formatter-text-highlight.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-mail-formatter-text-highlight.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  * text-highlight.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-formatter-text-highlight.h"
 24 #include "languages.h"
 25 
 26 #include <em-format/e-mail-formatter-extension.h>
 27 #include <em-format/e-mail-formatter.h>
 28 #include <em-format/e-mail-part-utils.h>
 29 #include <e-util/e-util.h>
 30 
 31 #include <shell/e-shell-settings.h>
 32 #include <shell/e-shell.h>
 33 
 34 #include <libebackend/libebackend.h>
 35 #include <libedataserver/libedataserver.h>
 36 
 37 #include <glib/gi18n-lib.h>
 38 #include <X11/Xlib.h>
 39 #include <camel/camel.h>
 40 
 41 typedef struct _EMailFormatterTextHighlight EMailFormatterTextHighlight;
 42 typedef struct _EMailFormatterTextHighlightClass EMailFormatterTextHighlightClass;
 43 
 44 struct _EMailFormatterTextHighlight {
 45 	EExtension parent;
 46 };
 47 
 48 struct _EMailFormatterTextHighlightClass {
 49 	EExtensionClass parent_class;
 50 };
 51 
 52 GType e_mail_formatter_text_highlight_get_type (void);
 53 static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
 54 static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
 55 
 56 G_DEFINE_DYNAMIC_TYPE_EXTENDED (
 57 	EMailFormatterTextHighlight,
 58 	e_mail_formatter_text_highlight,
 59 	E_TYPE_EXTENSION,
 60 	0,
 61 	G_IMPLEMENT_INTERFACE_DYNAMIC (
 62 		E_TYPE_MAIL_EXTENSION,
 63 		e_mail_formatter_mail_extension_interface_init)
 64 	G_IMPLEMENT_INTERFACE_DYNAMIC (
 65 		E_TYPE_MAIL_FORMATTER_EXTENSION,
 66 		e_mail_formatter_formatter_extension_interface_init));
 67 
 68 static gchar *
 69 get_default_font (void)
 70 {
 71 	gchar *font;
 72 	GSettings *settings;
 73 
 74 	settings = g_settings_new ("org.gnome.desktop.interface");
 75 
 76 	font = g_settings_get_string (settings, "monospace-font-name");
 77 
 78 	g_object_unref (settings);
 79 
 80 	return font ? font : g_strdup ("monospace 10");
 81 }
 82 
 83 static gchar *
 84 get_syntax (EMailPart *part,
 85             const gchar *uri)
 86 {
 87 	gchar *syntax = NULL;
 88 	CamelContentType *ct = NULL;
 89 
 90 	if (uri) {
 91 		SoupURI *soup_uri = soup_uri_new (uri);
 92 		GHashTable *query = soup_form_decode (soup_uri->query);
 93 
 94 		syntax = g_hash_table_lookup (query, "__formatas");
 95 		if (syntax) {
 96 			syntax = g_strdup (syntax);
 97 		}
 98 		g_hash_table_destroy (query);
 99 		soup_uri_free (soup_uri);
100 	}
101 
102 	/* Try to detect syntax by content-type first */
103 	if (syntax == NULL) {
104 		ct = camel_mime_part_get_content_type (part->part);
105 		if (ct) {
106 			gchar *mime_type = camel_content_type_simple (ct);
107 
108 			syntax = (gchar *) get_syntax_for_mime_type (mime_type);
109 			syntax = syntax ? g_strdup (syntax) : NULL;
110 			g_free (mime_type);
111 		}
112 	}
113 
114 	/* If it fails or the content type too generic, try to detect it by
115 	 * filename extension */
116 	if (syntax == NULL ||
117 	    (ct != NULL &&
118 	     (camel_content_type_is (ct, "application", "octet-stream") ||
119 	     (camel_content_type_is (ct, "text", "plain"))))) {
120 		const gchar *filename = camel_mime_part_get_filename (part->part);
121 		if (filename) {
122 			gchar *ext = g_strrstr (filename, ".");
123 			if (ext) {
124 				syntax = (gchar *) get_syntax_for_ext (ext + 1);
125 				syntax = syntax ? g_strdup (syntax) : NULL;
126 			}
127 		}
128 	}
129 
130 	/* Out of ideas - use plain text */
131 	if (syntax == NULL) {
132 		syntax = g_strdup ("txt");
133 	}
134 
135 	return syntax;
136 }
137 
138 static gboolean
139 emfe_text_highlight_format (EMailFormatterExtension *extension,
140                             EMailFormatter *formatter,
141                             EMailFormatterContext *context,
142                             EMailPart *part,
143                             CamelStream *stream,
144                             GCancellable *cancellable)
145 {
146 	/* Don't format text/html unless it's an attachment */
147 	CamelContentType *ct = camel_mime_part_get_content_type (part->part);
148 	if (ct && camel_content_type_is (ct, "text", "html")) {
149 		const CamelContentDisposition *disp;
150 		disp = camel_mime_part_get_content_disposition (part->part);
151 
152 		if (!disp || g_strcmp0 (disp->disposition, "attachment") != 0)
153 			return FALSE;
154 	}
155 
156 	if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
157 
158 		CamelDataWrapper *dw;
159 		CamelStream *filter_stream;
160 		CamelMimeFilter *mime_filter;
161 
162 		dw = camel_medium_get_content (CAMEL_MEDIUM (part->part));
163 		if (!dw) {
164 			return FALSE;
165 		}
166 
167 		camel_stream_write_string (
168 			stream, "<pre><div class=\"pre\">", cancellable, NULL);
169 
170 		filter_stream = camel_stream_filter_new (stream);
171 		mime_filter = camel_mime_filter_tohtml_new (
172 				CAMEL_MIME_FILTER_TOHTML_PRE |
173 				CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES, 0);
174 		camel_stream_filter_add (
175 			CAMEL_STREAM_FILTER (filter_stream), mime_filter);
176 		g_object_unref (mime_filter);
177 
178 		e_mail_formatter_format_text (
179 			formatter, part, filter_stream, cancellable);
180 
181 		camel_stream_flush (filter_stream, cancellable, NULL);
182 		g_object_unref (filter_stream);
183 
184 		camel_stream_write_string (
185 			stream, "</div></pre>", cancellable, NULL);
186 
187 		return TRUE;
188 
189 	} else if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
190 		gint pipe_stdin, pipe_stdout;
191 		GPid pid;
192 		CamelDataWrapper *dw;
193 		gchar *font_family, *font_size, *syntax;
194 		gboolean use_custom_font;
195 		EShell *shell;
196 		EShellSettings *settings;
197 		PangoFontDescription *fd;
198 		gboolean success;
199 
200 		const gchar *argv[] = { "highlight",
201 					NULL,	/* --font= */
202 					NULL,   /* --font-size= */
203 					NULL,   /* --syntax= */
204 					"--out-format=html",
205 					"--include-style",
206 					"--inline-css",
207 					"--style=bclear",
208 					"--failsafe",
209 					NULL };
210 
211 		dw = camel_medium_get_content (CAMEL_MEDIUM (part->part));
212 		if (!dw) {
213 			return FALSE;
214 		}
215 
216 		syntax = get_syntax (part, context->uri);
217 
218 		/* Use the traditional text/plain formatter for plain-text */
219 		if (g_strcmp0 (syntax, "txt") == 0) {
220 			g_free (syntax);
221 			return FALSE;
222 		}
223 
224 		shell = e_shell_get_default ();
225 		settings = e_shell_get_shell_settings (shell);
226 
227 		fd = NULL;
228 		use_custom_font = e_shell_settings_get_boolean (
229 					settings, "mail-use-custom-fonts");
230 		if (!use_custom_font) {
231 			gchar *font;
232 
233 			font = get_default_font ();
234 			fd = pango_font_description_from_string (font);
235 			g_free (font);
236 
237 		} else {
238 			gchar *font;
239 
240 			font = e_shell_settings_get_string (
241 					settings, "mail-font-monospace");
242 			if (!font)
243 				font = get_default_font ();
244 
245 			fd = pango_font_description_from_string (font);
246 			g_free (font);
247 		}
248 
249 		font_family = g_strdup_printf (
250 			"--font='%s'",
251 			pango_font_description_get_family (fd));
252 		font_size = g_strdup_printf (
253 			"--font-size=%d",
254 			pango_font_description_get_size (fd) / PANGO_SCALE);
255 
256 		argv[1] = font_family;
257 		argv[2] = font_size;
258 		argv[3] = g_strdup_printf ("--syntax=%s", syntax);
259 		g_free (syntax);
260 
261 		success = g_spawn_async_with_pipes (
262 			NULL, (gchar **) argv, NULL,
263 			G_SPAWN_SEARCH_PATH, NULL, NULL, &pid,
264 			&pipe_stdin, &pipe_stdout, NULL, NULL);
265 
266 		if (success) {
267 			CamelStream *read;
268 			CamelStream *write;
269 			CamelStream *utf8;
270 			GByteArray *ba;
271 			gchar *tmp;
272 
273 			write = camel_stream_fs_new_with_fd (pipe_stdin);
274 			read = camel_stream_fs_new_with_fd (pipe_stdout);
275 
276 			/* Decode the content of mime part to the 'utf8' stream */
277 			utf8 = camel_stream_mem_new ();
278 			camel_data_wrapper_decode_to_stream_sync (
279 				dw, utf8, cancellable, NULL);
280 
281 			/* Convert the binary data do someting displayable */
282 			ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (utf8));
283 			tmp = e_util_utf8_data_make_valid ((gchar *) ba->data, ba->len);
284 
285 			/* Send the sanitized data to the highlighter */
286 			camel_stream_write_string (write, tmp, cancellable, NULL);
287 			g_free (tmp);
288 			g_object_unref (utf8);
289 			g_object_unref (write);
290 
291 			g_spawn_close_pid (pid);
292 
293 			g_seekable_seek (G_SEEKABLE (read), 0, G_SEEK_SET, cancellable, NULL);
294 			camel_stream_write_to_stream (read, stream, cancellable, NULL);
295 			g_object_unref (read);
296 		} else {
297 			/* We can't call e_mail_formatter_format_as on text/plain,
298 			 * because text-highlight is registered as an handler for
299 			 * text/plain, so we would end up in an endless recursion.
300 			 *
301 			 * Just return FALSE here and EMailFormatter will automatically
302 			 * fall back to the default text/plain formatter */
303 			if (camel_content_type_is (ct, "text", "plain")) {
304 				g_free (font_family);
305 				g_free (font_size);
306 				g_free ((gchar *) argv[3]);
307 				pango_font_description_free (fd);
308 
309 				return FALSE;
310 			} else {
311 				/* In case of any other content, force use of
312 				 * text/plain formatter, because returning FALSE
313 				 * for text/x-patch or application/php would show
314 				 * an error, as there is no other handler registered
315 				 * for these */
316 				e_mail_formatter_format_as (
317 					formatter, context, part, stream,
318 					"application/vnd.evolution.plaintext",
319 					cancellable);
320 			}
321 		}
322 
323 		g_free (font_family);
324 		g_free (font_size);
325 		g_free ((gchar *) argv[3]);
326 		pango_font_description_free (fd);
327 	} else {
328 		const gchar *default_charset, *charset;
329 		gchar *uri, *str;
330 		gchar *syntax;
331 
332 		default_charset = e_mail_formatter_get_default_charset (formatter);
333 		charset = e_mail_formatter_get_charset (formatter);
334 
335 		if (!default_charset)
336 			default_charset = "";
337 		if (!charset)
338 			charset = "";
339 
340 		syntax = get_syntax (part, NULL);
341 
342 		uri = e_mail_part_build_uri (
343 			context->folder, context->message_uid,
344 			"part_id", G_TYPE_STRING, part->id,
345 			"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
346 			"__formatas", G_TYPE_STRING, syntax,
347 			"formatter_default_charset", G_TYPE_STRING, default_charset,
348 			"formatter_charset", G_TYPE_STRING, charset,
349 			NULL);
350 
351 		g_free (syntax);
352 
353 		str = g_strdup_printf (
354 			"<div class=\"part-container-nostyle\" >"
355 			"<iframe width=\"100%%\" height=\"10\""
356 			" id=\"%s\" name=\"%s\" "
357 			" frameborder=\"0\" src=\"%s\" "
358 			" style=\"border: 1px solid #%06x; background-color: #%06x;\">"
359 			"</iframe>"
360 			"</div>",
361 			part->id, part->id, uri,
362 			e_color_to_value ((GdkColor *)
363 				e_mail_formatter_get_color (
364 					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
365 			e_color_to_value ((GdkColor *)
366 				e_mail_formatter_get_color (
367 					formatter, E_MAIL_FORMATTER_COLOR_CONTENT)));
368 
369 		camel_stream_write_string (stream, str, cancellable, NULL);
370 
371 		g_free (str);
372 		g_free (uri);
373 
374 	}
375 
376 	return TRUE;
377 }
378 
379 static const gchar *
380 emfe_text_highlight_get_display_name (EMailFormatterExtension *extension)
381 {
382 	return _("Text Highlight");
383 }
384 
385 static const gchar *
386 emfe_text_highlight_get_description (EMailFormatterExtension *extension)
387 {
388 	return _("Syntax highlighting of mail parts");
389 }
390 
391 static const gchar **
392 emfe_text_highlight_mime_types (EMailExtension *extension)
393 {
394 	return get_mime_types ();
395 }
396 
397 static void
398 emfe_text_highlight_constructed (GObject *object)
399 {
400 	EExtensible *extensible;
401 	EMailExtensionRegistry *reg;
402 
403 	extensible = e_extension_get_extensible (E_EXTENSION (object));
404 	reg = E_MAIL_EXTENSION_REGISTRY (extensible);
405 
406 	e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object));
407 }
408 
409 static void
410 e_mail_formatter_text_highlight_init (EMailFormatterTextHighlight *object)
411 {
412 }
413 
414 static void
415 e_mail_formatter_text_highlight_class_init (EMailFormatterTextHighlightClass *class)
416 {
417 	GObjectClass *object_class;
418 	EExtensionClass *extension_class;
419 
420 	object_class = G_OBJECT_CLASS (class);
421 	object_class->constructed = emfe_text_highlight_constructed;
422 
423 	extension_class = E_EXTENSION_CLASS (class);
424 	extension_class->extensible_type = E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY;
425 }
426 
427 static void
428 e_mail_formatter_text_highlight_class_finalize (EMailFormatterTextHighlightClass *class)
429 {
430 }
431 
432 void
433 e_mail_formatter_text_highlight_type_register (GTypeModule *type_module)
434 {
435 	e_mail_formatter_text_highlight_register_type (type_module);
436 }
437 
438 static void
439 e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
440 {
441 	iface->format = emfe_text_highlight_format;
442 	iface->get_display_name = emfe_text_highlight_get_display_name;
443 	iface->get_description = emfe_text_highlight_get_description;
444 }
445 
446 static void
447 e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
448 {
449 	iface->mime_types = emfe_text_highlight_mime_types;
450 }