No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-mail-inline-filter.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-mail-inline-filter.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Michael Zucchi <notzed@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28
29 #include "e-mail-inline-filter.h"
30 #include "e-mail-part-utils.h"
31
32 #define d(x)
33
34 G_DEFINE_TYPE (EMailInlineFilter, e_mail_inline_filter, CAMEL_TYPE_MIME_FILTER)
35
36 enum {
37 EMIF_PLAIN,
38 EMIF_BINHEX,
39 EMIF_POSTSCRIPT,
40 EMIF_PGPSIGNED,
41 EMIF_PGPENCRYPTED
42 };
43
44 static const struct {
45 const gchar *type;
46 const gchar *subtype;
47 CamelTransferEncoding encoding;
48 guint plain : 1;
49 } emif_types[] = {
50 { "text", "plain",
51 CAMEL_TRANSFER_ENCODING_DEFAULT, 1 },
52
53 { "application", "mac-binhex40",
54 CAMEL_TRANSFER_ENCODING_7BIT, 0 },
55
56 { "application", "postscript",
57 CAMEL_TRANSFER_ENCODING_7BIT, 0 },
58
59 { "application", "x-inlinepgp-signed",
60 CAMEL_TRANSFER_ENCODING_DEFAULT, 0 },
61
62 { "application", "x-inlinepgp-encrypted",
63 CAMEL_TRANSFER_ENCODING_DEFAULT, 0 }
64 };
65
66 static CamelMimePart *
67 construct_part_from_stream (CamelStream *mem,
68 const GByteArray *data)
69 {
70 CamelMimePart *part = NULL;
71 CamelMimeParser *parser;
72
73 g_return_val_if_fail (mem != NULL, NULL);
74 g_return_val_if_fail (data != NULL, NULL);
75
76 if (data->len <= 13 || g_ascii_strncasecmp ((const gchar *) data->data, "Content-Type:", 13) != 0)
77 return NULL;
78
79 parser = camel_mime_parser_new ();
80 camel_mime_parser_scan_from (parser, FALSE);
81 camel_mime_parser_scan_pre_from (parser, FALSE);
82
83 if (camel_mime_parser_init_with_stream (parser, mem, NULL) != -1) {
84 part = camel_mime_part_new ();
85 if (!camel_mime_part_construct_from_parser_sync (part, parser, NULL, NULL)) {
86 g_object_unref (part);
87 part = NULL;
88 }
89 }
90
91 g_object_unref (parser);
92
93 return part;
94 }
95
96 static void
97 inline_filter_add_part (EMailInlineFilter *emif,
98 const gchar *data,
99 gint len)
100 {
101 CamelTransferEncoding encoding;
102 CamelContentType *content_type;
103 CamelDataWrapper *dw;
104 const gchar *mimetype;
105 CamelMimePart *part;
106 CamelStream *mem;
107 gchar *type;
108
109 if (emif->state == EMIF_PLAIN || emif->state == EMIF_PGPSIGNED || emif->state == EMIF_PGPENCRYPTED)
110 encoding = emif->base_encoding;
111 else
112 encoding = emif_types[emif->state].encoding;
113
114 g_byte_array_append (emif->data, (guchar *) data, len);
115 /* check the part will actually have content */
116 if (emif->data->len <= 0) {
117 return;
118 }
119
120 mem = camel_stream_mem_new_with_byte_array (emif->data);
121 part = construct_part_from_stream (mem, emif->data);
122 if (part) {
123 g_object_unref (mem);
124 emif->data = g_byte_array_new ();
125 g_free (emif->filename);
126 emif->filename = NULL;
127
128 emif->parts = g_slist_append (emif->parts, part);
129 emif->found_any = TRUE;
130
131 return;
132 }
133
134 emif->data = g_byte_array_new ();
135 g_seekable_seek (G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL);
136
137 dw = camel_data_wrapper_new ();
138 if (encoding == emif->base_encoding && (encoding == CAMEL_TRANSFER_ENCODING_BASE64 || encoding == CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE)) {
139 CamelMimeFilter *enc_filter = camel_mime_filter_basic_new (encoding == CAMEL_TRANSFER_ENCODING_BASE64 ? CAMEL_MIME_FILTER_BASIC_BASE64_ENC : CAMEL_MIME_FILTER_BASIC_QP_ENC);
140 CamelStream *filter_stream;
141
142 filter_stream = camel_stream_filter_new (mem);
143 camel_stream_filter_add (CAMEL_STREAM_FILTER (filter_stream), enc_filter);
144
145 /* properly encode content */
146 camel_data_wrapper_construct_from_stream_sync (
147 dw, filter_stream, NULL, NULL);
148
149 g_object_unref (enc_filter);
150 g_object_unref (filter_stream);
151 } else {
152 camel_data_wrapper_construct_from_stream_sync (
153 dw, mem, NULL, NULL);
154 }
155 g_object_unref (mem);
156
157 if (emif_types[emif->state].plain && emif->base_type) {
158 /* create a copy */
159 type = camel_content_type_format (emif->base_type);
160 content_type = camel_content_type_decode (type);
161 g_free (type);
162 } else {
163 /* we want to preserve all params */
164 type = camel_content_type_format (emif->base_type);
165 content_type = camel_content_type_decode (type);
166 g_free (type);
167
168 g_free (content_type->type);
169 g_free (content_type->subtype);
170 content_type->type = g_strdup (emif_types[emif->state].type);
171 content_type->subtype = g_strdup (emif_types[emif->state].subtype);
172 }
173
174 camel_data_wrapper_set_mime_type_field (dw, content_type);
175 camel_content_type_unref (content_type);
176 dw->encoding = encoding;
177
178 part = camel_mime_part_new ();
179 camel_medium_set_content ((CamelMedium *) part, dw);
180 camel_mime_part_set_encoding (part, encoding);
181 g_object_unref (dw);
182
183 if (emif->filename)
184 camel_mime_part_set_filename (part, emif->filename);
185
186 /* pre-snoop the mime type of unknown objects, and poke and hack it into place */
187 if (camel_content_type_is (dw->mime_type, "application", "octet-stream")
188 && (mimetype = e_mail_part_snoop_type (part))
189 && strcmp (mimetype, "application/octet-stream") != 0) {
190 camel_data_wrapper_set_mime_type (dw, mimetype);
191 camel_mime_part_set_content_type (part, mimetype);
192 if (emif->filename)
193 camel_mime_part_set_filename (part, emif->filename);
194 }
195
196 g_free (emif->filename);
197 emif->filename = NULL;
198
199 emif->parts = g_slist_append (emif->parts, part);
200 }
201
202 static gboolean
203 newline_or_whitespace_follows (const gchar *str,
204 guint len,
205 guint skip_first)
206 {
207 if (len <= skip_first)
208 return len == skip_first;
209
210 str += skip_first;
211 len -= skip_first;
212
213 while (len > 0 && *str != '\n') {
214 if (!*str)
215 return TRUE;
216
217 if (!camel_mime_is_lwsp (*str))
218 return FALSE;
219
220 len--;
221 str++;
222 }
223
224 return len == 0 || *str == '\n';
225 }
226
227 static gint
228 inline_filter_scan (CamelMimeFilter *f,
229 gchar *in,
230 gsize len,
231 gint final)
232 {
233 EMailInlineFilter *emif = (EMailInlineFilter *) f;
234 gchar *inptr = in, *inend = in + len;
235 gchar *data_start = in;
236 gchar *start = in;
237
238 while (inptr < inend) {
239 gint rest_len;
240 gboolean set_null_byte = FALSE;
241
242 start = inptr;
243
244 while (inptr < inend && *inptr != '\n')
245 inptr++;
246
247 if (inptr == inend && start == inptr) {
248 if (!final) {
249 camel_mime_filter_backup (f, start, inend - start);
250 inend = start;
251 }
252 break;
253 }
254
255 rest_len = inend - start;
256 if (inptr < inend) {
257 *inptr++ = 0;
258 set_null_byte = TRUE;
259 }
260
261 #define restore_inptr() G_STMT_START { if (set_null_byte) inptr[-1] = '\n'; } G_STMT_END
262
263 switch (emif->state) {
264 case EMIF_PLAIN:
265 if (rest_len >= 45 && strncmp (start, "(This file must be converted with BinHex 4.0)", 45) == 0) {
266 restore_inptr ();
267 inline_filter_add_part (emif, data_start, start - data_start);
268 data_start = start;
269 emif->state = EMIF_BINHEX;
270 } else if (rest_len >= 11 && strncmp (start, "%!PS-Adobe-", 11) == 0) {
271 restore_inptr ();
272 inline_filter_add_part (emif, data_start, start - data_start);
273 data_start = start;
274 emif->state = EMIF_POSTSCRIPT;
275 } else if (rest_len >= 34 && strncmp (start, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0 &&
276 newline_or_whitespace_follows (start, rest_len, 34)) {
277 restore_inptr ();
278 inline_filter_add_part (emif, data_start, start - data_start);
279 data_start = start;
280 emif->state = EMIF_PGPSIGNED;
281 } else if (rest_len >= 27 && strncmp (start, "-----BEGIN PGP MESSAGE-----", 27) == 0 &&
282 newline_or_whitespace_follows (start, rest_len, 27)) {
283 restore_inptr ();
284 inline_filter_add_part (emif, data_start, start - data_start);
285 data_start = start;
286 emif->state = EMIF_PGPENCRYPTED;
287 }
288
289 break;
290 case EMIF_BINHEX:
291 if (inptr > (start + 1) && inptr[-2] == ':') {
292 restore_inptr ();
293 inline_filter_add_part (emif, data_start, inptr - data_start);
294 data_start = inptr;
295 emif->state = EMIF_PLAIN;
296 emif->found_any = TRUE;
297 }
298 break;
299 case EMIF_POSTSCRIPT:
300 if (rest_len >= 5 && strncmp (start, "%%EOF", 5) == 0) {
301 restore_inptr ();
302 inline_filter_add_part (emif, data_start, inptr - data_start);
303 data_start = inptr;
304 emif->state = EMIF_PLAIN;
305 emif->found_any = TRUE;
306 }
307 break;
308 case EMIF_PGPSIGNED:
309 if (rest_len >= 27 && strncmp (start, "-----END PGP SIGNATURE-----", 27) == 0 &&
310 newline_or_whitespace_follows (start, rest_len, 27)) {
311 restore_inptr ();
312 inline_filter_add_part (emif, data_start, inptr - data_start);
313 data_start = inptr;
314 emif->state = EMIF_PLAIN;
315 emif->found_any = TRUE;
316 }
317 break;
318 case EMIF_PGPENCRYPTED:
319 if (rest_len >= 25 && strncmp (start, "-----END PGP MESSAGE-----", 25) == 0 &&
320 newline_or_whitespace_follows (start, rest_len, 25)) {
321 restore_inptr ();
322 inline_filter_add_part (emif, data_start, inptr - data_start);
323 data_start = inptr;
324 emif->state = EMIF_PLAIN;
325 emif->found_any = TRUE;
326 }
327 break;
328 }
329
330 restore_inptr ();
331
332 #undef restore_inptr
333 }
334
335 if (final) {
336 /* always stop as plain, especially when not read those tags fully */
337 emif->state = EMIF_PLAIN;
338
339 inline_filter_add_part (emif, data_start, inend - data_start);
340 } else if (start > data_start) {
341 /* backup the last line, in case the tag is divided within buffers */
342 camel_mime_filter_backup (f, start, inend - start);
343 g_byte_array_append (emif->data, (guchar *) data_start, start - data_start);
344 } else {
345 g_byte_array_append (emif->data, (guchar *) data_start, inend - data_start);
346 }
347
348 return 0;
349 }
350
351 static void
352 inline_filter_finalize (GObject *object)
353 {
354 EMailInlineFilter *emif = E_MAIL_INLINE_FILTER (object);
355
356 if (emif->base_type)
357 camel_content_type_unref (emif->base_type);
358
359 camel_mime_filter_reset (CAMEL_MIME_FILTER (object));
360 g_byte_array_free (emif->data, TRUE);
361 g_free (emif->filename);
362
363 /* Chain up to parent's finalize() method. */
364 G_OBJECT_CLASS (e_mail_inline_filter_parent_class)->finalize (object);
365 }
366
367 static void
368 inline_filter_filter (CamelMimeFilter *filter,
369 const gchar *in,
370 gsize len,
371 gsize prespace,
372 gchar **out,
373 gsize *outlen,
374 gsize *outprespace)
375 {
376 inline_filter_scan (filter, (gchar *) in, len, FALSE);
377
378 *out = (gchar *)in;
379 *outlen = len;
380 *outprespace = prespace;
381 }
382
383 static void
384 inline_filter_complete (CamelMimeFilter *filter,
385 const gchar *in,
386 gsize len,
387 gsize prespace,
388 gchar **out,
389 gsize *outlen,
390 gsize *outprespace)
391 {
392 inline_filter_scan (filter, (gchar *) in, len, TRUE);
393
394 *out = (gchar *)in;
395 *outlen = len;
396 *outprespace = prespace;
397 }
398
399 static void
400 inline_filter_reset (CamelMimeFilter *filter)
401 {
402 EMailInlineFilter *emif = E_MAIL_INLINE_FILTER (filter);
403 GSList *l;
404
405 l = emif->parts;
406 while (l) {
407 GSList *n = l->next;
408
409 g_object_unref (l->data);
410 g_slist_free_1 (l);
411
412 l = n;
413 }
414 emif->parts = NULL;
415 g_byte_array_set_size (emif->data, 0);
416 emif->found_any = FALSE;
417 }
418
419 static void
420 e_mail_inline_filter_class_init (EMailInlineFilterClass *class)
421 {
422 GObjectClass *object_class;
423 CamelMimeFilterClass *mime_filter_class;
424
425 object_class = G_OBJECT_CLASS (class);
426 object_class->finalize = inline_filter_finalize;
427
428 mime_filter_class = CAMEL_MIME_FILTER_CLASS (class);
429 mime_filter_class->filter = inline_filter_filter;
430 mime_filter_class->complete = inline_filter_complete;
431 mime_filter_class->reset = inline_filter_reset;
432 }
433
434 static void
435 e_mail_inline_filter_init (EMailInlineFilter *emif)
436 {
437 emif->data = g_byte_array_new ();
438 emif->found_any = FALSE;
439 }
440
441 /**
442 * em_inline_filter_new:
443 * @base_encoding: The base transfer-encoding of the
444 * raw data being processed.
445 * @base_type: The base content-type of the raw data, should always be
446 * text/plain.
447 * @filename: Filename of the part, or NULL
448 *
449 * Create a filter which will scan a (text) stream for
450 * embedded parts. You can then retrieve the contents
451 * as a CamelMultipart object.
452 *
453 * Return value:
454 **/
455 EMailInlineFilter *
456 e_mail_inline_filter_new (CamelTransferEncoding base_encoding,
457 CamelContentType *base_type,
458 const gchar *filename)
459 {
460 EMailInlineFilter *emif;
461
462 emif = g_object_new (E_TYPE_MAIL_INLINE_FILTER, NULL);
463 emif->base_encoding = base_encoding;
464 if (base_type) {
465 emif->base_type = base_type;
466 camel_content_type_ref (emif->base_type);
467 }
468
469 if (filename && *filename)
470 emif->filename = g_strdup (filename);
471
472 return emif;
473 }
474
475 CamelMultipart *
476 e_mail_inline_filter_get_multipart (EMailInlineFilter *emif)
477 {
478 GSList *l = emif->parts;
479 CamelMultipart *mp;
480
481 mp = camel_multipart_new ();
482 while (l) {
483 camel_multipart_add_part (mp, l->data);
484 l = l->next;
485 }
486
487 return mp;
488 }
489
490 gboolean
491 e_mail_inline_filter_found_any (EMailInlineFilter *emif)
492 {
493 g_return_val_if_fail (emif != NULL, FALSE);
494
495 return emif->found_any;
496 }