evolution-3.6.4/em-format/e-mail-formatter-text-html.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-mail-formatter-text-html.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-mail-formatter-text-html.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-text-html.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 <em-format/e-mail-formatter-extension.h>
 26 #include <em-format/e-mail-formatter.h>
 27 #include <em-format/e-mail-inline-filter.h>
 28 #include <em-format/e-mail-part-utils.h>
 29 #include <e-util/e-util.h>
 30 
 31 #include <glib/gi18n-lib.h>
 32 #include <camel/camel.h>
 33 
 34 #include <ctype.h>
 35 #include <string.h>
 36 
 37 static const gchar *formatter_mime_types[] = { "text/html", NULL };
 38 
 39 typedef struct _EMailFormatterTextHTML {
 40 	GObject parent;
 41 } EMailFormatterTextHTML;
 42 
 43 typedef struct _EMailFormatterTextHTMLClass {
 44 	GObjectClass parent_class;
 45 } EMailFormatterTextHTMLClass;
 46 
 47 static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
 48 static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
 49 
 50 G_DEFINE_TYPE_EXTENDED (
 51 	EMailFormatterTextHTML,
 52 	e_mail_formatter_text_html,
 53 	G_TYPE_OBJECT,
 54 	0,
 55 	G_IMPLEMENT_INTERFACE (
 56 		E_TYPE_MAIL_EXTENSION,
 57 		e_mail_formatter_mail_extension_interface_init)
 58 	G_IMPLEMENT_INTERFACE (
 59 		E_TYPE_MAIL_FORMATTER_EXTENSION,
 60 		e_mail_formatter_formatter_extension_interface_init));
 61 
 62 static gchar *
 63 get_tag (const gchar *utf8_string,
 64          const gchar *tag_name,
 65          gchar *opening,
 66          gchar *closing)
 67 {
 68 	gchar *t;
 69 	gunichar c;
 70 	gboolean has_end;
 71 
 72 	c = '\0';
 73 	t = g_utf8_find_prev_char (utf8_string, closing);
 74 	while (t != opening) {
 75 
 76 		c = g_utf8_get_char (t);
 77 		if (!g_unichar_isspace (c))
 78 			break;
 79 	}
 80 
 81 	/* Not a pair tag */
 82 	if (c == '/')
 83 		return g_strndup (opening, closing - opening + 1);
 84 
 85 	t = closing;
 86 	while (t) {
 87 		c = g_utf8_get_char (t);
 88 		if (c == '<') {
 89 			if (t[1] == '!' && t[2] == '-' && t[3] == '-') {
 90 				/* it's a comment start, read until the end of "-->" */
 91 				gchar *end = strstr (t + 4, "-->");
 92 				if (end) {
 93 					t = end + 2;
 94 				} else
 95 					break;
 96 			} else
 97 				break;
 98 		}
 99 
100 		t = g_utf8_find_next_char (t, NULL);
101 	}
102 
103 	has_end = FALSE;
104 	do {
105 		c = g_utf8_get_char (t);
106 
107 		if (c == '/') {
108 			has_end = TRUE;
109 			break;
110 		}
111 
112 		if (c == '>') {
113 			has_end = FALSE;
114 			break;
115 		}
116 
117 		t = g_utf8_find_next_char (t, NULL);
118 
119 	} while (t);
120 
121 	/* Broken HTML? */
122 	if (!has_end)
123 		return NULL;
124 
125 	do {
126 		c = g_utf8_get_char (t);
127 		if ((c != ' ') && (c != '/'))
128 			break;
129 
130 		t = g_utf8_find_next_char (t, NULL);
131 	} while (t);
132 
133 	/* tag_name is always ASCII */
134 	if (g_ascii_strncasecmp (t, tag_name, strlen (tag_name)) == 0) {
135 
136 		closing = g_utf8_strchr (t, -1, '>');
137 
138 		return g_strndup (opening, closing - opening + 1);
139 	}
140 
141 	/* Broken HTML? */
142 	return NULL;
143 }
144 
145 static gboolean
146 emfe_text_html_format (EMailFormatterExtension *extension,
147                        EMailFormatter *formatter,
148                        EMailFormatterContext *context,
149                        EMailPart *part,
150                        CamelStream *stream,
151                        GCancellable *cancellable)
152 {
153 	if (g_cancellable_is_cancelled (cancellable))
154 		return FALSE;
155 
156 	if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
157 		/* FORMATTER FIXME: Shouldn't we have some extra method for
158 		 * BASE64 and QP decoding?? */
159 		e_mail_formatter_format_text (formatter, part, stream, cancellable);
160 
161 	} else if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
162 		GString *string;
163 		GByteArray *ba;
164 		gchar *pos;
165 		GList *tags, *iter;
166 		gboolean valid;
167 		gchar *tag;
168 		const gchar *document_end;
169 		gint length;
170 		gint i;
171 		CamelStream *decoded_stream;
172 
173 		decoded_stream = camel_stream_mem_new ();
174 		/* FORMATTER FIXME: See above */
175 		e_mail_formatter_format_text (formatter, part, decoded_stream, cancellable);
176 		g_seekable_seek (G_SEEKABLE (decoded_stream), 0, G_SEEK_SET, cancellable, NULL);
177 
178 		ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (decoded_stream));
179 		string = g_string_new_len ((gchar *) ba->data, ba->len);
180 
181 		g_object_unref (decoded_stream);
182 
183 		if (!g_utf8_validate (string->str, -1, NULL)) {
184 			gchar *valid_utf8;
185 
186 			valid_utf8 = e_util_utf8_make_valid (string->str);
187 			g_string_free (string, TRUE);
188 			string = g_string_new (valid_utf8);
189 			g_free (valid_utf8);
190 		}
191 
192 		tags = NULL;
193 		pos = string->str;
194 		valid = FALSE;
195 
196 		do {
197 			gchar *tmp;
198 			gchar *closing;
199 			gchar *opening;
200 
201 			tmp = g_utf8_find_next_char (pos, NULL);
202 			pos = g_utf8_strchr (tmp, -1, '<');
203 			if (!pos)
204 				break;
205 
206 			opening = pos;
207 			closing = g_utf8_strchr (pos, -1, '>');
208 
209 			/* Find where the actual tag name begins */
210 			tag = g_utf8_find_next_char (pos, NULL);
211 			while ((tag = g_utf8_find_next_char (pos, NULL)) != NULL) {
212 				gunichar c = g_utf8_get_char (tag);
213 				if (!g_unichar_isspace (c))
214 					break;
215 
216 			}
217 
218 			if (g_ascii_strncasecmp (tag, "style", 5) == 0) {
219 				tags = g_list_append (
220 					tags,
221 					get_tag (string->str, "style", opening, closing));
222 			} else if (g_ascii_strncasecmp (tag, "script", 6) == 0) {
223 				tags = g_list_append (
224 					tags,
225 					get_tag (string->str, "script", opening, closing));
226 			} else if (g_ascii_strncasecmp (tag, "link", 4) == 0) {
227 				tags = g_list_append (
228 					tags,
229 					get_tag (string->str, "link", opening, closing));
230 			} else if (g_ascii_strncasecmp (tag, "body", 4) == 0) {
231 				valid = TRUE;
232 				break;
233 			}
234 
235 		} while (pos);
236 
237 		/* Something's wrong, let's write the entire HTML and hope
238 		 * that WebKit can handle it */
239 		if (!valid) {
240 			EMailFormatterContext c = {
241 				.folder = context->folder,
242 				.message = context->message,
243 				.message_uid = context->message_uid,
244 				.parts = context->parts,
245 				.flags = context->flags,
246 				.mode = E_MAIL_FORMATTER_MODE_RAW,
247 			};
248 
249 			emfe_text_html_format (
250 				extension, formatter, &c, part, stream, cancellable);
251 			return FALSE;
252 		}
253 
254 		/*	       include the "body" as well -----v */
255 		g_string_erase (string, 0, tag - string->str + 4);
256 		g_string_prepend (string, "<div ");
257 
258 		for (iter = tags; iter; iter = iter->next) {
259 			if (iter->data)
260 				g_string_prepend (string, iter->data);
261 		}
262 
263 		g_list_free_full (tags, g_free);
264 
265 		document_end = NULL;
266 		/* We can probably use ASCII functions here */
267 		if (g_strrstr (string->str, "</body>")) {
268 			document_end = ">ydob/<";
269 		}
270 
271 		if (g_strrstr (string->str, "</html>")) {
272 			if (document_end) {
273 				document_end = ">lmth/<>ydob/<";
274 			} else {
275 				document_end = ">lmth/<";
276 			}
277 		}
278 
279 		if (document_end) {
280 			length = strlen (document_end);
281 			tag = string->str + string->len - 1;
282 			i = 0;
283 			valid = FALSE;
284 			while (i < length - 1) {
285 				gunichar c;
286 
287 				c = g_utf8_get_char (tag);
288 				if (g_unichar_isspace (c)) {
289 					tag = g_utf8_find_prev_char (string->str, tag);
290 					continue;
291 				}
292 
293 				c = g_unichar_tolower (c);
294 
295 				if (c == document_end[i]) {
296 					tag = g_utf8_find_prev_char (string->str, tag);
297 					i++;
298 					valid = TRUE;
299 					continue;
300 				}
301 
302 				tag = g_utf8_find_prev_char (string->str, tag);
303 				valid = FALSE;
304 			}
305 		} else {
306 			/* do not cut, if there is no end tag */
307 			valid = FALSE;
308 		}
309 
310 		if (valid)
311 			g_string_truncate (string, tag - string->str);
312 
313 		camel_stream_write_string (stream, string->str, cancellable, NULL);
314 
315 		g_string_free (string, TRUE);
316 	} else {
317 		gchar *uri, *str;
318 		const gchar *default_charset, *charset;
319 
320 		default_charset = e_mail_formatter_get_default_charset (formatter);
321 		charset = e_mail_formatter_get_charset (formatter);
322 
323 		if (!default_charset)
324 			default_charset = "";
325 		if (!charset)
326 			charset = "";
327 
328 		uri = e_mail_part_build_uri (
329 			context->folder, context->message_uid,
330 			"part_id", G_TYPE_STRING, part->id,
331 			"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
332 			"formatter_default_charset", G_TYPE_STRING, default_charset,
333 			"formatter_charset", G_TYPE_STRING, charset,
334 			NULL);
335 
336 		str = g_strdup_printf (
337 			"<div class=\"part-container-nostyle\">"
338 			"<iframe width=\"100%%\" height=\"10\" "
339 			" frameborder=\"0\" src=\"%s\" "
340 			" id=\"%s.iframe\" name=\"%s\" "
341 			" style=\"border: 1px solid #%06x; background-color: #%06x;\">"
342 			"</iframe>"
343 			"</div>",
344 			uri,
345 			part->id,
346 			part->id,
347 			e_color_to_value ((GdkColor *)
348 				e_mail_formatter_get_color (
349 					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
350 			e_color_to_value ((GdkColor *)
351 				e_mail_formatter_get_color (
352 					formatter, E_MAIL_FORMATTER_COLOR_CONTENT)));
353 
354 		camel_stream_write_string (stream, str, cancellable, NULL);
355 
356 		g_free (str);
357 		g_free (uri);
358 	}
359 
360 	return TRUE;
361 }
362 
363 static const gchar *
364 emfe_text_html_get_display_name (EMailFormatterExtension *extension)
365 {
366 	return _("HTML");
367 }
368 
369 static const gchar *
370 emfe_text_html_get_description (EMailFormatterExtension *extension)
371 {
372 	return _("Format part as HTML");
373 }
374 
375 static const gchar **
376 emfe_text_html_mime_types (EMailExtension *extension)
377 {
378 	return formatter_mime_types;
379 }
380 
381 static void
382 e_mail_formatter_text_html_class_init (EMailFormatterTextHTMLClass *class)
383 {
384 }
385 
386 static void
387 e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
388 {
389 	iface->format = emfe_text_html_format;
390 	iface->get_display_name = emfe_text_html_get_display_name;
391 	iface->get_description = emfe_text_html_get_description;
392 }
393 
394 static void
395 e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
396 {
397 	iface->mime_types = emfe_text_html_mime_types;
398 }
399 
400 static void
401 e_mail_formatter_text_html_init (EMailFormatterTextHTML *formatter)
402 {
403 
404 }