evolution-3.6.4/em-format/e-mail-inline-filter.c

No issues found

Incomplete coverage

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
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  * 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 }