No issues found
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 |
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 }