1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*  GMime
3  *  Copyright (C) 2000-2020 Jeffrey Stedfast
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public License
7  *  as published by the Free Software Foundation; either version 2.1
8  *  of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free
17  *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
18  *  02110-1301, USA.
19  */
20 
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <string.h>
27 #include <ctype.h>
28 #include <locale.h>
29 
30 #include "gmime-message.h"
31 #include "gmime-multipart.h"
32 #include "gmime-multipart-signed.h"
33 #include "gmime-multipart-encrypted.h"
34 #include "gmime-part.h"
35 #include "gmime-utils.h"
36 #include "gmime-common.h"
37 #include "gmime-stream-mem.h"
38 #include "gmime-stream-filter.h"
39 #include "gmime-parse-utils.h"
40 #include "gmime-internal.h"
41 #include "gmime-events.h"
42 
43 
44 /**
45  * SECTION: gmime-message
46  * @title: GMimeMessage
47  * @short_description: Messages
48  * @see_also:
49  *
50  * A #GMimeMessage represents an rfc822 message.
51  **/
52 
53 static void g_mime_message_class_init (GMimeMessageClass *klass);
54 static void g_mime_message_init (GMimeMessage *message, GMimeMessageClass *klass);
55 static void g_mime_message_finalize (GObject *object);
56 
57 /* GMimeObject class methods */
58 static void message_header_added    (GMimeObject *object, GMimeHeader *header);
59 static void message_header_changed  (GMimeObject *object, GMimeHeader *header);
60 static void message_header_removed  (GMimeObject *object, GMimeHeader *header);
61 static void message_headers_cleared (GMimeObject *object);
62 
63 static char *message_get_headers (GMimeObject *object, GMimeFormatOptions *options);
64 static ssize_t message_write_to_stream (GMimeObject *object, GMimeFormatOptions *options,
65 					gboolean content_only, GMimeStream *stream);
66 static void message_encode (GMimeObject *object, GMimeEncodingConstraint constraint);
67 
68 static void sender_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
69 static void from_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
70 static void reply_to_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
71 static void to_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
72 static void cc_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
73 static void bcc_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
74 
75 static GMimeObjectClass *parent_class = NULL;
76 
77 static struct {
78 	const char *name;
79 	GMimeEventCallback changed_cb;
80 } address_types[] = {
81 	{ "Sender",          (GMimeEventCallback) sender_changed          },
82 	{ "From",            (GMimeEventCallback) from_changed            },
83 	{ "Reply-To",        (GMimeEventCallback) reply_to_changed        },
84 	{ "To",              (GMimeEventCallback) to_list_changed         },
85 	{ "Cc",              (GMimeEventCallback) cc_list_changed         },
86 	{ "Bcc",             (GMimeEventCallback) bcc_list_changed        },
87 };
88 
89 #define N_ADDRESS_TYPES G_N_ELEMENTS (address_types)
90 
91 static char *rfc822_headers[] = {
92 	"Return-Path",
93 	"Received",
94 	"Date",
95 	"From",
96 	"Reply-To",
97 	"Subject",
98 	"Sender",
99 	"To",
100 	"Cc",
101 };
102 
103 
104 GType
g_mime_message_get_type(void)105 g_mime_message_get_type (void)
106 {
107 	static GType type = 0;
108 
109 	if (!type) {
110 		static const GTypeInfo info = {
111 			sizeof (GMimeMessageClass),
112 			NULL, /* base_class_init */
113 			NULL, /* base_class_finalize */
114 			(GClassInitFunc) g_mime_message_class_init,
115 			NULL, /* class_finalize */
116 			NULL, /* class_data */
117 			sizeof (GMimeMessage),
118 			0,   /* n_preallocs */
119 			(GInstanceInitFunc) g_mime_message_init,
120 		};
121 
122 		type = g_type_register_static (GMIME_TYPE_OBJECT, "GMimeMessage", &info, 0);
123 	}
124 
125 	return type;
126 }
127 
128 
129 static void
g_mime_message_class_init(GMimeMessageClass * klass)130 g_mime_message_class_init (GMimeMessageClass *klass)
131 {
132 	GMimeObjectClass *object_class = GMIME_OBJECT_CLASS (klass);
133 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
134 
135 	parent_class = g_type_class_ref (GMIME_TYPE_OBJECT);
136 
137 	gobject_class->finalize = g_mime_message_finalize;
138 
139 	object_class->header_added = message_header_added;
140 	object_class->header_changed = message_header_changed;
141 	object_class->header_removed = message_header_removed;
142 	object_class->headers_cleared = message_headers_cleared;
143 	object_class->get_headers = message_get_headers;
144 	object_class->write_to_stream = message_write_to_stream;
145 	object_class->encode = message_encode;
146 }
147 
148 static void
connect_changed_event(GMimeMessage * message,GMimeAddressType type)149 connect_changed_event (GMimeMessage *message, GMimeAddressType type)
150 {
151 	InternetAddressList *addrlist;
152 
153 	addrlist = message->addrlists[type];
154 
155 	g_mime_event_add (addrlist->changed, address_types[type].changed_cb, message);
156 }
157 
158 static void
disconnect_changed_event(GMimeMessage * message,GMimeAddressType type)159 disconnect_changed_event (GMimeMessage *message, GMimeAddressType type)
160 {
161 	InternetAddressList *addrlist;
162 
163 	addrlist = message->addrlists[type];
164 
165 	g_mime_event_remove (addrlist->changed, address_types[type].changed_cb, message);
166 }
167 
168 static void
block_changed_event(GMimeMessage * message,GMimeAddressType type)169 block_changed_event (GMimeMessage *message, GMimeAddressType type)
170 {
171 	InternetAddressList *addrlist;
172 
173 	addrlist = message->addrlists[type];
174 
175 	g_mime_event_block (addrlist->changed, address_types[type].changed_cb, message);
176 }
177 
178 static void
unblock_changed_event(GMimeMessage * message,GMimeAddressType type)179 unblock_changed_event (GMimeMessage *message, GMimeAddressType type)
180 {
181 	InternetAddressList *addrlist;
182 
183 	addrlist = message->addrlists[type];
184 
185 	g_mime_event_unblock (addrlist->changed, address_types[type].changed_cb, message);
186 }
187 
188 static void
g_mime_message_init(GMimeMessage * message,GMimeMessageClass * klass)189 g_mime_message_init (GMimeMessage *message, GMimeMessageClass *klass)
190 {
191 	guint i;
192 
193 	message->addrlists = g_new (InternetAddressList *, N_ADDRESS_TYPES);
194 	((GMimeObject *) message)->ensure_newline = TRUE;
195 	message->message_id = NULL;
196 	message->mime_part = NULL;
197 	message->subject = NULL;
198 	message->date = NULL;
199 
200 	/* initialize recipient lists */
201 	for (i = 0; i < N_ADDRESS_TYPES; i++) {
202 		message->addrlists[i] = internet_address_list_new ();
203 		connect_changed_event (message, i);
204 	}
205 }
206 
207 static void
g_mime_message_finalize(GObject * object)208 g_mime_message_finalize (GObject *object)
209 {
210 	GMimeMessage *message = (GMimeMessage *) object;
211 	guint i;
212 
213 	/* disconnect changed handlers */
214 	for (i = 0; i < N_ADDRESS_TYPES; i++) {
215 		disconnect_changed_event (message, i);
216 		g_object_unref (message->addrlists[i]);
217 	}
218 
219 	g_free (message->addrlists);
220 	g_free (message->message_id);
221 	g_free (message->subject);
222 	g_free (message->marker);
223 
224 	if (message->date)
225 		g_date_time_unref (message->date);
226 
227 	/* unref child mime part */
228 	if (message->mime_part)
229 		g_object_unref (message->mime_part);
230 
231 	G_OBJECT_CLASS (parent_class)->finalize (object);
232 }
233 
234 
235 enum {
236 	HEADER_SENDER,
237 	HEADER_FROM,
238 	HEADER_REPLY_TO,
239 	HEADER_TO,
240 	HEADER_CC,
241 	HEADER_BCC,
242 	HEADER_SUBJECT,
243 	HEADER_DATE,
244 	HEADER_MESSAGE_ID,
245 	HEADER_MIME_VERSION,
246 	HEADER_UNKNOWN
247 };
248 
249 static const char *message_headers[] = {
250 	"Sender",
251 	"From",
252 	"Reply-To",
253 	"To",
254 	"Cc",
255 	"Bcc",
256 	"Subject",
257 	"Date",
258 	"Message-Id",
259 	"MIME-Version"
260 };
261 
262 static void
message_update_addresses(GMimeMessage * message,GMimeParserOptions * options,GMimeAddressType type)263 message_update_addresses (GMimeMessage *message, GMimeParserOptions *options, GMimeAddressType type)
264 {
265 	GMimeHeaderList *headers = ((GMimeObject *) message)->headers;
266 	InternetAddressList *addrlist, *list;
267 	const char *name, *value;
268 	GMimeHeader *header;
269 	int count, i;
270 
271 	block_changed_event (message, type);
272 
273 	addrlist = message->addrlists[type];
274 
275 	internet_address_list_clear (addrlist);
276 
277 	count = g_mime_header_list_get_count (headers);
278 	for (i = 0; i < count; i++) {
279 		header = g_mime_header_list_get_header_at (headers, i);
280 		name = g_mime_header_get_name (header);
281 
282 		if (g_ascii_strcasecmp (address_types[type].name, name) != 0)
283 			continue;
284 
285 		if ((value = g_mime_header_get_raw_value (header))) {
286 			if ((list = _internet_address_list_parse (options, value, header->offset))) {
287 				internet_address_list_append (addrlist, list);
288 				g_object_unref (list);
289 			}
290 		}
291 	}
292 
293 	unblock_changed_event (message, type);
294 }
295 
296 static void
process_header(GMimeObject * object,GMimeHeader * header)297 process_header (GMimeObject *object, GMimeHeader *header)
298 {
299 	GMimeParserOptions *options = _g_mime_header_list_get_options (object->headers);
300 	GMimeMessage *message = (GMimeMessage *) object;
301 	const char *name, *value;
302 	guint i;
303 
304 	name = g_mime_header_get_name (header);
305 
306 	for (i = 0; i < G_N_ELEMENTS (message_headers); i++) {
307 		if (!g_ascii_strcasecmp (message_headers[i], name))
308 			break;
309 	}
310 
311 	switch (i) {
312 	case HEADER_SENDER:
313 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_SENDER);
314 		break;
315 	case HEADER_FROM:
316 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_FROM);
317 		break;
318 	case HEADER_REPLY_TO:
319 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_REPLY_TO);
320 		break;
321 	case HEADER_TO:
322 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_TO);
323 		break;
324 	case HEADER_CC:
325 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_CC);
326 		break;
327 	case HEADER_BCC:
328 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_BCC);
329 		break;
330 	case HEADER_SUBJECT:
331 		g_free (message->subject);
332 
333 		if ((value = g_mime_header_get_value (header)))
334 			message->subject = g_strdup (value);
335 		else
336 			message->subject = NULL;
337 		break;
338 	case HEADER_DATE:
339 		if ((value = g_mime_header_get_value (header))) {
340 			if (message->date)
341 				g_date_time_unref (message->date);
342 
343 			message->date = g_mime_utils_header_decode_date (value);
344 		}
345 		break;
346 	case HEADER_MESSAGE_ID:
347 		g_free (message->message_id);
348 
349 		if ((value = g_mime_header_get_value (header)))
350 			message->message_id = g_mime_utils_decode_message_id (value);
351 		else
352 			message->message_id = NULL;
353 		break;
354 	}
355 }
356 
357 static void
message_header_added(GMimeObject * object,GMimeHeader * header)358 message_header_added (GMimeObject *object, GMimeHeader *header)
359 {
360 	process_header (object, header);
361 
362 	GMIME_OBJECT_CLASS (parent_class)->header_added (object, header);
363 }
364 
365 static void
message_header_changed(GMimeObject * object,GMimeHeader * header)366 message_header_changed (GMimeObject *object, GMimeHeader *header)
367 {
368 	process_header (object, header);
369 
370 	GMIME_OBJECT_CLASS (parent_class)->header_changed (object, header);
371 }
372 
373 static void
message_header_removed(GMimeObject * object,GMimeHeader * header)374 message_header_removed (GMimeObject *object, GMimeHeader *header)
375 {
376 	GMimeParserOptions *options = _g_mime_header_list_get_options (object->headers);
377 	GMimeMessage *message = (GMimeMessage *) object;
378 	const char *name;
379 	guint i;
380 
381 	name = g_mime_header_get_name (header);
382 
383 	for (i = 0; i < G_N_ELEMENTS (message_headers); i++) {
384 		if (!g_ascii_strcasecmp (message_headers[i], name))
385 			break;
386 	}
387 
388 	switch (i) {
389 	case HEADER_SENDER:
390 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_SENDER);
391 		break;
392 	case HEADER_FROM:
393 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_FROM);
394 		break;
395 	case HEADER_REPLY_TO:
396 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_REPLY_TO);
397 		break;
398 	case HEADER_TO:
399 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_TO);
400 		break;
401 	case HEADER_CC:
402 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_CC);
403 		break;
404 	case HEADER_BCC:
405 		message_update_addresses (message, options, GMIME_ADDRESS_TYPE_BCC);
406 		break;
407 	case HEADER_SUBJECT:
408 		g_free (message->subject);
409 		message->subject = NULL;
410 		break;
411 	case HEADER_DATE:
412 		if (message->date) {
413 			g_date_time_unref (message->date);
414 			message->date = NULL;
415 		}
416 		break;
417 	case HEADER_MESSAGE_ID:
418 		g_free (message->message_id);
419 		message->message_id = NULL;
420 		break;
421 	}
422 
423 	GMIME_OBJECT_CLASS (parent_class)->header_removed (object, header);
424 }
425 
426 static void
message_headers_cleared(GMimeObject * object)427 message_headers_cleared (GMimeObject *object)
428 {
429 	GMimeMessage *message = (GMimeMessage *) object;
430 	guint i;
431 
432 	for (i = 0; i < N_ADDRESS_TYPES; i++) {
433 		block_changed_event (message, i);
434 		internet_address_list_clear (message->addrlists[i]);
435 		unblock_changed_event (message, i);
436 	}
437 
438 	g_free (message->message_id);
439 	message->message_id = NULL;
440 	g_free (message->subject);
441 	message->subject = NULL;
442 
443 	if (message->date) {
444 		g_date_time_unref (message->date);
445 		message->date = NULL;
446 	}
447 
448 	GMIME_OBJECT_CLASS (parent_class)->headers_cleared (object);
449 }
450 
451 
452 static ssize_t
write_headers_to_stream(GMimeObject * object,GMimeFormatOptions * options,GMimeStream * stream)453 write_headers_to_stream (GMimeObject *object, GMimeFormatOptions *options, GMimeStream *stream)
454 {
455 	GMimeMessage *message = (GMimeMessage *) object;
456 	GMimeObject *mime_part = message->mime_part;
457 
458 	if (mime_part != NULL) {
459 		int body_count = g_mime_header_list_get_count (mime_part->headers);
460 		int count = g_mime_header_list_get_count (object->headers);
461 		GMimeHeader *header, *body_header;
462 		ssize_t nwritten, total = 0;
463 		gint64 body_offset, offset;
464 		GMimeStream *filtered;
465 		GMimeFilter *filter;
466 		int body_index = 0;
467 		int index = 0;
468 
469 		filtered = g_mime_stream_filter_new (stream);
470 		filter = g_mime_format_options_create_newline_filter (options, FALSE);
471 		g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
472 		g_object_unref (filter);
473 
474 		while (index < count && body_index < body_count) {
475 			body_header = g_mime_header_list_get_header_at (mime_part->headers, body_index);
476 			if ((body_offset = g_mime_header_get_offset (body_header)) < 0)
477 				break;
478 
479 			header = g_mime_header_list_get_header_at (object->headers, index);
480 			offset = g_mime_header_get_offset (header);
481 
482 			if (offset < body_offset) {
483 				if (!g_mime_format_options_is_hidden_header (options, header->name)) {
484 					if ((nwritten = g_mime_header_write_to_stream (header, options, filtered)) == -1) {
485 						g_object_unref (filtered);
486 						return -1;
487 					}
488 
489 					total += nwritten;
490 				}
491 
492 				index++;
493 			} else {
494 				if (!g_mime_format_options_is_hidden_header (options, header->name)) {
495 					if ((nwritten = g_mime_header_write_to_stream (body_header, options, filtered)) == -1) {
496 						g_object_unref (filtered);
497 						return -1;
498 					}
499 
500 					total += nwritten;
501 				}
502 
503 				body_index++;
504 			}
505 		}
506 
507 		while (index < count) {
508 			header = g_mime_header_list_get_header_at (object->headers, index);
509 
510 			if (!g_mime_format_options_is_hidden_header (options, header->name)) {
511 				if ((nwritten = g_mime_header_write_to_stream (header, options, filtered)) == -1) {
512 					g_object_unref (filtered);
513 					return -1;
514 				}
515 
516 				total += nwritten;
517 			}
518 
519 			index++;
520 		}
521 
522 		while (body_index < body_count) {
523 			header = g_mime_header_list_get_header_at (mime_part->headers, body_index);
524 
525 			if (!g_mime_format_options_is_hidden_header (options, header->name)) {
526 				if ((nwritten = g_mime_header_write_to_stream (header, options, filtered)) == -1) {
527 					g_object_unref (filtered);
528 					return -1;
529 				}
530 
531 				total += nwritten;
532 			}
533 
534 			body_index++;
535 		}
536 
537 		g_object_unref (filtered);
538 
539 		return total;
540 	}
541 
542 	return g_mime_header_list_write_to_stream (object->headers, options, stream);
543 }
544 
545 
546 static char *
message_get_headers(GMimeObject * object,GMimeFormatOptions * options)547 message_get_headers (GMimeObject *object, GMimeFormatOptions *options)
548 {
549 	GMimeStream *stream;
550 	GByteArray *ba;
551 	char *str;
552 
553 	ba = g_byte_array_new ();
554 	stream = g_mime_stream_mem_new ();
555 	g_mime_stream_mem_set_byte_array ((GMimeStreamMem *) stream, ba);
556 	write_headers_to_stream (object, options, stream);
557 	g_object_unref (stream);
558 	g_byte_array_append (ba, (unsigned char *) "", 1);
559 	str = (char *) ba->data;
560 	g_byte_array_free (ba, FALSE);
561 
562 	return str;
563 }
564 
565 static ssize_t
message_write_to_stream(GMimeObject * object,GMimeFormatOptions * options,gboolean content_only,GMimeStream * stream)566 message_write_to_stream (GMimeObject *object, GMimeFormatOptions *options, gboolean content_only, GMimeStream *stream)
567 {
568 	GMimeMessage *message = (GMimeMessage *) object;
569 	GMimeObject *mime_part = message->mime_part;
570 	ssize_t nwritten, total = 0;
571 	const char *newline;
572 
573 	if (!content_only) {
574 		if ((nwritten = write_headers_to_stream (object, options, stream)) == -1)
575 			return -1;
576 
577 		total += nwritten;
578 
579 		newline = g_mime_format_options_get_newline (options);
580 		if ((nwritten = g_mime_stream_write_string (stream, newline)) == -1)
581 			return -1;
582 
583 		total += nwritten;
584 	}
585 
586 	if (mime_part) {
587 		GMimeObjectClass *klass = GMIME_OBJECT_GET_CLASS (mime_part);
588 
589 		mime_part->ensure_newline = ((GMimeObject *) message)->ensure_newline;
590 		nwritten = klass->write_to_stream (mime_part, options, TRUE, stream);
591 		mime_part->ensure_newline = FALSE;
592 
593 		if (nwritten == -1)
594 			return -1;
595 
596 		total += nwritten;
597 	}
598 
599 	return total;
600 }
601 
602 static void
message_encode(GMimeObject * object,GMimeEncodingConstraint constraint)603 message_encode (GMimeObject *object, GMimeEncodingConstraint constraint)
604 {
605 	GMimeMessage *message = (GMimeMessage *) object;
606 
607 	if (message->mime_part != NULL)
608 		g_mime_object_encode (message->mime_part, constraint);
609 }
610 
611 
612 
613 /**
614  * g_mime_message_new:
615  * @pretty_headers: make pretty headers
616  *
617  * If @pretty_headers is %TRUE, then the standard rfc822 headers are
618  * initialized so as to put headers in a nice friendly order. This is
619  * strictly a cosmetic thing, so if you are unsure, it is safe to say
620  * no (%FALSE).
621  *
622  * Returns: an empty #GMimeMessage object.
623  **/
624 GMimeMessage *
g_mime_message_new(gboolean pretty_headers)625 g_mime_message_new (gboolean pretty_headers)
626 {
627 	GMimeHeaderList *headers;
628 	GMimeMessage *message;
629 	guint i;
630 
631 	message = g_object_new (GMIME_TYPE_MESSAGE, NULL);
632 
633 	if (pretty_headers) {
634 		/* Populate with the "standard" rfc822 headers so we can have a standard order */
635 		headers = ((GMimeObject *) message)->headers;
636 
637 		_g_mime_object_block_header_list_changed ((GMimeObject *) message);
638 		for (i = 0; i < G_N_ELEMENTS (rfc822_headers); i++)
639 			g_mime_header_list_set (headers, rfc822_headers[i], NULL, NULL);
640 		_g_mime_object_unblock_header_list_changed ((GMimeObject *) message);
641 	}
642 
643 	return message;
644 }
645 
646 
647 /**
648  * g_mime_message_get_sender:
649  * @message: A #GMimeMessage
650  *
651  * Gets the parsed list of addresses in the Sender header.
652  *
653  * Returns: (transfer none): the parsed list of addresses in the Sender header.
654  **/
655 InternetAddressList *
g_mime_message_get_sender(GMimeMessage * message)656 g_mime_message_get_sender (GMimeMessage *message)
657 {
658 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
659 
660 	return message->addrlists[GMIME_ADDRESS_TYPE_SENDER];
661 }
662 
663 
664 /**
665  * g_mime_message_get_from:
666  * @message: A #GMimeMessage
667  *
668  * Gets the parsed list of addresses in the From header.
669  *
670  * Returns: (transfer none): the parsed list of addresses in the From header.
671  **/
672 InternetAddressList *
g_mime_message_get_from(GMimeMessage * message)673 g_mime_message_get_from (GMimeMessage *message)
674 {
675 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
676 
677 	return message->addrlists[GMIME_ADDRESS_TYPE_FROM];
678 }
679 
680 
681 /**
682  * g_mime_message_get_reply_to:
683  * @message: A #GMimeMessage
684  *
685  * Gets the parsed list of addresses in the Reply-To header.
686  *
687  * Returns: (transfer none): the parsed list of addresses in the Reply-To header.
688  **/
689 InternetAddressList *
g_mime_message_get_reply_to(GMimeMessage * message)690 g_mime_message_get_reply_to (GMimeMessage *message)
691 {
692 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
693 
694 	return message->addrlists[GMIME_ADDRESS_TYPE_REPLY_TO];
695 }
696 
697 
698 /**
699  * g_mime_message_get_to:
700  * @message: A #GMimeMessage
701  *
702  * Gets combined list of parsed addresses in the To header(s).
703  *
704  * Returns: (transfer none): the parsed list of addresses in the To header(s).
705  **/
706 InternetAddressList *
g_mime_message_get_to(GMimeMessage * message)707 g_mime_message_get_to (GMimeMessage *message)
708 {
709 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
710 
711 	return message->addrlists[GMIME_ADDRESS_TYPE_TO];
712 }
713 
714 
715 /**
716  * g_mime_message_get_cc:
717  * @message: A #GMimeMessage
718  *
719  * Gets combined list of parsed addresses in the Cc header(s).
720  *
721  * Returns: (transfer none): the parsed list of addresses in the Cc header(s).
722  **/
723 InternetAddressList *
g_mime_message_get_cc(GMimeMessage * message)724 g_mime_message_get_cc (GMimeMessage *message)
725 {
726 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
727 
728 	return message->addrlists[GMIME_ADDRESS_TYPE_CC];
729 }
730 
731 
732 /**
733  * g_mime_message_get_bcc:
734  * @message: A #GMimeMessage
735  *
736  * Gets combined list of parsed addresses in the Bcc header(s).
737  *
738  * Returns: (transfer none): the parsed list of addresses in the Bcc header(s).
739  **/
740 InternetAddressList *
g_mime_message_get_bcc(GMimeMessage * message)741 g_mime_message_get_bcc (GMimeMessage *message)
742 {
743 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
744 
745 	return message->addrlists[GMIME_ADDRESS_TYPE_BCC];
746 }
747 
748 
749 static void
sync_internet_address_list(InternetAddressList * list,GMimeMessage * message,const char * name)750 sync_internet_address_list (InternetAddressList *list, GMimeMessage *message, const char *name)
751 {
752 	GMimeObject *object = (GMimeObject *) message;
753 	GString *str;
754 	guint n;
755 
756 	str = g_string_new (name);
757 	g_string_append_c (str, ':');
758 	n = str->len;
759 
760 	g_string_append_c (str, ' ');
761 	internet_address_list_encode (list, NULL, str);
762 
763 	_g_mime_object_block_header_list_changed (object);
764 	_g_mime_header_list_set (object->headers, name, str->str + n);
765 	_g_mime_object_unblock_header_list_changed (object);
766 
767 	g_string_free (str, TRUE);
768 }
769 
770 static void
sync_address_header(GMimeMessage * message,GMimeAddressType type)771 sync_address_header (GMimeMessage *message, GMimeAddressType type)
772 {
773 	InternetAddressList *list = message->addrlists[type];
774 	const char *name = address_types[type].name;
775 
776 	sync_internet_address_list (list, message, name);
777 }
778 
779 static void
sender_changed(InternetAddressList * list,gpointer args,GMimeMessage * message)780 sender_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
781 {
782 	sync_address_header (message, GMIME_ADDRESS_TYPE_SENDER);
783 }
784 
785 static void
from_changed(InternetAddressList * list,gpointer args,GMimeMessage * message)786 from_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
787 {
788 	sync_address_header (message, GMIME_ADDRESS_TYPE_FROM);
789 }
790 
791 static void
reply_to_changed(InternetAddressList * list,gpointer args,GMimeMessage * message)792 reply_to_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
793 {
794 	sync_address_header (message, GMIME_ADDRESS_TYPE_REPLY_TO);
795 }
796 
797 static void
to_list_changed(InternetAddressList * list,gpointer args,GMimeMessage * message)798 to_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
799 {
800 	sync_address_header (message, GMIME_ADDRESS_TYPE_TO);
801 }
802 
803 static void
cc_list_changed(InternetAddressList * list,gpointer args,GMimeMessage * message)804 cc_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
805 {
806 	sync_address_header (message, GMIME_ADDRESS_TYPE_CC);
807 }
808 
809 static void
bcc_list_changed(InternetAddressList * list,gpointer args,GMimeMessage * message)810 bcc_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
811 {
812 	sync_address_header (message, GMIME_ADDRESS_TYPE_BCC);
813 }
814 
815 
816 /**
817  * g_mime_message_add_mailbox:
818  * @message: A #GMimeMessage
819  * @type: A #GMimeAddressType
820  * @name: The name of the mailbox (or %NULL)
821  * @addr: The address of the mailbox
822  *
823  * Add a mailbox of a chosen type to the MIME message.
824  *
825  * Note: The @name (and @addr) strings should be in UTF-8.
826  **/
827 void
g_mime_message_add_mailbox(GMimeMessage * message,GMimeAddressType type,const char * name,const char * addr)828 g_mime_message_add_mailbox (GMimeMessage *message, GMimeAddressType type, const char *name, const char *addr)
829 {
830 	InternetAddressList *addrlist;
831 	InternetAddress *ia;
832 
833 	g_return_if_fail (GMIME_IS_MESSAGE (message));
834 	g_return_if_fail (type < N_ADDRESS_TYPES);
835 	g_return_if_fail (addr != NULL);
836 
837 	addrlist = message->addrlists[type];
838 	ia = internet_address_mailbox_new (name, addr);
839 	internet_address_list_add (addrlist, ia);
840 	g_object_unref (ia);
841 }
842 
843 
844 /**
845  * g_mime_message_get_addresses:
846  * @message: A #GMimeMessage
847  * @type: A #GMimeAddressType
848  *
849  * Gets a list of addresses of the specified @type from the @message.
850  *
851  * Returns: (transfer none): a list of addresses of the specified
852  * @type from the @message.
853  **/
854 InternetAddressList *
g_mime_message_get_addresses(GMimeMessage * message,GMimeAddressType type)855 g_mime_message_get_addresses (GMimeMessage *message, GMimeAddressType type)
856 {
857 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
858 	g_return_val_if_fail (type < N_ADDRESS_TYPES, NULL);
859 
860 	return message->addrlists[type];
861 }
862 
863 
864 /**
865  * g_mime_message_get_all_recipients:
866  * @message: A #GMimeMessage
867  *
868  * Gets the complete list of recipients for @message.
869  *
870  * Returns: (transfer full): a newly allocated #InternetAddressList
871  * containing all recipients of the message or %NULL if no recipients
872  * are set.
873  **/
874 InternetAddressList *
g_mime_message_get_all_recipients(GMimeMessage * message)875 g_mime_message_get_all_recipients (GMimeMessage *message)
876 {
877 	InternetAddressList *recipients, *list = NULL;
878 	guint i;
879 
880 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
881 
882 	for (i = GMIME_ADDRESS_TYPE_TO; i <= GMIME_ADDRESS_TYPE_BCC; i++) {
883 		recipients = message->addrlists[i];
884 
885 		if (internet_address_list_length (recipients) == 0)
886 			continue;
887 
888 		if (list == NULL)
889 			list = internet_address_list_new ();
890 
891 		internet_address_list_append (list, recipients);
892 	}
893 
894 	return list;
895 }
896 
897 
898 /**
899  * g_mime_message_set_subject:
900  * @message: A #GMimeMessage
901  * @subject: Subject string
902  * @charset: The charset to use for encoding the subject or %NULL to use the default
903  *
904  * Set the subject of a @message.
905  *
906  * Note: The @subject string should be in UTF-8.
907  **/
908 void
g_mime_message_set_subject(GMimeMessage * message,const char * subject,const char * charset)909 g_mime_message_set_subject (GMimeMessage *message, const char *subject, const char *charset)
910 {
911 	g_return_if_fail (GMIME_IS_MESSAGE (message));
912 	g_return_if_fail (subject != NULL);
913 
914 	g_mime_object_set_header ((GMimeObject *) message, "Subject", subject, charset);
915 }
916 
917 
918 /**
919  * g_mime_message_get_subject:
920  * @message: A #GMimeMessage
921  *
922  * Gets the subject of the @message.
923  *
924  * Returns: the subject of the @message in a form suitable for display
925  * or %NULL if no subject is set. If not %NULL, the returned string
926  * will be in UTF-8.
927  **/
928 const char *
g_mime_message_get_subject(GMimeMessage * message)929 g_mime_message_get_subject (GMimeMessage *message)
930 {
931 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
932 
933 	return message->subject;
934 }
935 
936 
937 /**
938  * g_mime_message_set_date:
939  * @message: A #GMimeMessage
940  * @date: a date to be used in the Date header
941  *
942  * Sets the Date header on a MIME Message.
943  **/
944 void
g_mime_message_set_date(GMimeMessage * message,GDateTime * date)945 g_mime_message_set_date (GMimeMessage *message, GDateTime *date)
946 {
947 	char *str;
948 
949 	g_return_if_fail (GMIME_IS_MESSAGE (message));
950 
951 	str = g_mime_utils_header_format_date (date);
952 	g_mime_object_set_header ((GMimeObject *) message, "Date", str, NULL);
953 	g_free (str);
954 }
955 
956 
957 /**
958  * g_mime_message_get_date:
959  * @message: A #GMimeMessage
960  *
961  * Gets the parsed date and time value from the Date header.
962  *
963  * Returns: a #GDateTime on success or %NULL if the date could not be parsed.
964  **/
965 GDateTime *
g_mime_message_get_date(GMimeMessage * message)966 g_mime_message_get_date (GMimeMessage *message)
967 {
968 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
969 
970 	return message->date;
971 }
972 
973 
974 /**
975  * g_mime_message_set_message_id:
976  * @message: A #GMimeMessage
977  * @message_id: message-id (addr-spec portion)
978  *
979  * Set the Message-Id on a message.
980  **/
981 void
g_mime_message_set_message_id(GMimeMessage * message,const char * message_id)982 g_mime_message_set_message_id (GMimeMessage *message, const char *message_id)
983 {
984 	char *msgid;
985 
986 	g_return_if_fail (GMIME_IS_MESSAGE (message));
987 	g_return_if_fail (message_id != NULL);
988 
989 	msgid = g_strdup_printf ("<%s>", message_id);
990 	g_mime_object_set_header ((GMimeObject *) message, "Message-Id", msgid, NULL);
991 	g_free (msgid);
992 }
993 
994 
995 /**
996  * g_mime_message_get_message_id:
997  * @message: A #GMimeMessage
998  *
999  * Gets the Message-Id header of @message.
1000  *
1001  * Returns: the Message-Id of a message.
1002  **/
1003 const char *
g_mime_message_get_message_id(GMimeMessage * message)1004 g_mime_message_get_message_id (GMimeMessage *message)
1005 {
1006 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1007 
1008 	return message->message_id;
1009 }
1010 
1011 
1012 /**
1013  * g_mime_message_get_mime_part:
1014  * @message: A #GMimeMessage
1015  *
1016  * Gets the toplevel MIME part contained within @message.
1017  *
1018  * Returns: (transfer none): the toplevel MIME part of @message.
1019  **/
1020 GMimeObject *
g_mime_message_get_mime_part(GMimeMessage * message)1021 g_mime_message_get_mime_part (GMimeMessage *message)
1022 {
1023 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1024 
1025 	if (message->mime_part == NULL)
1026 		return NULL;
1027 
1028 	return message->mime_part;
1029 }
1030 
1031 
1032 /**
1033  * g_mime_message_set_mime_part:
1034  * @message: A #GMimeMessage
1035  * @mime_part: The root-level MIME Part
1036  *
1037  * Set the root-level MIME part of the message.
1038  **/
1039 void
g_mime_message_set_mime_part(GMimeMessage * message,GMimeObject * mime_part)1040 g_mime_message_set_mime_part (GMimeMessage *message, GMimeObject *mime_part)
1041 {
1042 	g_return_if_fail (GMIME_IS_OBJECT (mime_part));
1043 	g_return_if_fail (GMIME_IS_MESSAGE (message));
1044 
1045 	if (message->mime_part == mime_part)
1046 		return;
1047 
1048 	if (message->mime_part)
1049 		g_object_unref (message->mime_part);
1050 
1051 	if (mime_part) {
1052 		GMimeHeaderList *headers = ((GMimeObject *) message)->headers;
1053 		GMimeHeader *header;
1054 		int i;
1055 
1056 		if (!g_mime_header_list_contains (headers, "MIME-Version"))
1057 			g_mime_header_list_append (headers, "MIME-Version", "1.0", NULL);
1058 
1059 		for (i = 0; i < g_mime_header_list_get_count (mime_part->headers); i++) {
1060 			header = g_mime_header_list_get_header_at (mime_part->headers, i);
1061 			_g_mime_header_set_offset (header, -1);
1062 		}
1063 
1064 		g_object_ref (mime_part);
1065 	}
1066 
1067 	message->mime_part = mime_part;
1068 }
1069 
1070 
1071 /**
1072  * g_mime_message_foreach:
1073  * @message: A #GMimeMessage
1074  * @callback: (scope call): function to call on each of the mime parts
1075  *   contained by the mime message
1076  * @user_data: user-supplied callback data
1077  *
1078  * Recursively calls @callback on each of the mime parts in the mime message.
1079  **/
1080 void
g_mime_message_foreach(GMimeMessage * message,GMimeObjectForeachFunc callback,gpointer user_data)1081 g_mime_message_foreach (GMimeMessage *message, GMimeObjectForeachFunc callback, gpointer user_data)
1082 {
1083 	g_return_if_fail (GMIME_IS_MESSAGE (message));
1084 	g_return_if_fail (callback != NULL);
1085 
1086 	callback ((GMimeObject *) message, message->mime_part, user_data);
1087 
1088 	if (GMIME_IS_MULTIPART (message->mime_part))
1089 		g_mime_multipart_foreach ((GMimeMultipart *) message->mime_part, callback, user_data);
1090 }
1091 
1092 static gboolean
part_is_textual(GMimeObject * mime_part)1093 part_is_textual (GMimeObject *mime_part)
1094 {
1095 	GMimeContentType *type;
1096 
1097 	type = g_mime_object_get_content_type (mime_part);
1098 
1099 	return g_mime_content_type_is_type (type, "text", "*");
1100 }
1101 
1102 static GMimeObject *
multipart_guess_body(GMimeMultipart * multipart)1103 multipart_guess_body (GMimeMultipart *multipart)
1104 {
1105 	GMimeContentType *type;
1106 	GMimeObject *mime_part;
1107 	int count, i;
1108 
1109 	if (GMIME_IS_MULTIPART_ENCRYPTED (multipart)) {
1110 		/* nothing more we can do */
1111 		return (GMimeObject *) multipart;
1112 	}
1113 
1114 	type = g_mime_object_get_content_type ((GMimeObject *) multipart);
1115 	if (g_mime_content_type_is_type (type, "multipart", "alternative")) {
1116 		/* very likely that this is the body - leave it up to
1117 		 * our caller to decide which format of the body it
1118 		 * wants to use. */
1119 		return (GMimeObject *) multipart;
1120 	}
1121 
1122 	count = g_mime_multipart_get_count (multipart);
1123 
1124 	if (count >= 1 && GMIME_IS_MULTIPART_SIGNED (multipart)) {
1125 		/* if the body is in here, it has to be the first part */
1126 		count = 1;
1127 	}
1128 
1129 	for (i = 0; i < count; i++) {
1130 		mime_part = g_mime_multipart_get_part (multipart, i);
1131 
1132 		if (GMIME_IS_MULTIPART (mime_part)) {
1133 			if ((mime_part = multipart_guess_body ((GMimeMultipart *) mime_part)))
1134 				return mime_part;
1135 		} else if (GMIME_IS_PART (mime_part)) {
1136 			if (part_is_textual (mime_part))
1137 				return mime_part;
1138 		}
1139 	}
1140 
1141 	return NULL;
1142 }
1143 
1144 
1145 /**
1146  * g_mime_message_get_body:
1147  * @message: A #GMimeMessage
1148  *
1149  * Attempts to identify the MIME part containing the body of the
1150  * message.
1151  *
1152  * Returns: (transfer none): a #GMimeObject containing the textual
1153  * content that appears to be the main body of the message.
1154  *
1155  * Note: This function is NOT guaranteed to always work as it
1156  * makes some assumptions that are not necessarily true. It is
1157  * recommended that you traverse the MIME structure yourself.
1158  **/
1159 GMimeObject *
g_mime_message_get_body(GMimeMessage * message)1160 g_mime_message_get_body (GMimeMessage *message)
1161 {
1162 	GMimeObject *mime_part;
1163 
1164 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1165 
1166 	if (!(mime_part = message->mime_part))
1167 		return NULL;
1168 
1169 	if (GMIME_IS_MULTIPART (mime_part))
1170 		return multipart_guess_body ((GMimeMultipart *) mime_part);
1171 	else if (GMIME_IS_PART (mime_part) && part_is_textual (mime_part))
1172 		return mime_part;
1173 
1174 	return NULL;
1175 }
1176 
1177 
1178 /**
1179  * g_mime_message_get_autocrypt_header:
1180  * @message: a #GMimeMessage object.
1181  * @now: a #GDateTime object, or %NULL
1182  *
1183  * Creates a new #GMimeAutocryptHeader based on the relevant Autocrypt
1184  * header associated with the sender of an e-mail message.
1185  *
1186  * If the message has no sender in the From: field, or has more than
1187  * one sender, then this function will return %NULL.  Autocrypt should
1188  * ignore the message entirely.
1189  *
1190  * If there is one sender, but no single Autocrypt header is found
1191  * that matches that e-mail address, a #GMimeAutocryptHeader will be
1192  * returned for the sender, but it will be incomplete (see
1193  * #g_mime_autocrypt_header_is_complete).
1194  *
1195  * Note that the following types of Autocrypt headers will not be
1196  * returned by this function:
1197  *
1198  *  - headers that do not match an address in "From:"
1199  *  - unparseable headers
1200  *  - headers with unknown critical attributes
1201  *  - duplicate valid headers for the sender's address
1202  *
1203  * The returned Autocrypt header will have its effective_date set to
1204  * the earliest of either:
1205  *
1206  * - the Date: header of the message or
1207  * - @now (or the current time, if @now is %NULL)
1208  *
1209  * Returns: (transfer full): a new #GMimeAutocryptHeader object,
1210  * or %NULL if the message should be ignored for purposes of
1211  * Autocrypt.
1212  **/
1213 GMimeAutocryptHeader *
g_mime_message_get_autocrypt_header(GMimeMessage * message,GDateTime * now)1214 g_mime_message_get_autocrypt_header (GMimeMessage *message, GDateTime *now)
1215 {
1216 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1217 
1218 	GMimeAutocryptHeaderList *retlist = NULL;
1219 	GMimeAutocryptHeader *ret = NULL;
1220 	GDateTime *newnow = NULL;
1221 	GDateTime *effective_date = NULL;
1222 	if (now == NULL)
1223 		now = newnow = g_date_time_new_now_utc ();
1224 	effective_date = now;
1225 	if (message->date && g_date_time_compare (message->date, now) < 0)
1226 		effective_date = message->date;
1227 	retlist = g_mime_object_get_autocrypt_headers (GMIME_OBJECT (message),
1228 						       effective_date,
1229 						       "autocrypt",
1230 						       message->addrlists[GMIME_ADDRESS_TYPE_FROM],
1231 						       TRUE);
1232 	if (newnow)
1233 		g_date_time_unref (newnow);
1234 	if (retlist) {
1235 		if (g_mime_autocrypt_header_list_get_count (retlist) == 1) {
1236 			ret = g_mime_autocrypt_header_list_get_header_at (retlist, 0);
1237 			g_object_ref (ret);
1238 		}
1239 		g_object_unref (retlist);
1240 	}
1241 	return ret;
1242 }
1243 
1244 
1245 /**
1246  * g_mime_message_get_autocrypt_gossip_headers_from_inner_part:
1247  * @message: a #GMimeMessage object.
1248  * @now: a #GDateTime object, or %NULL
1249  * @inner_part: a #GMimeObject which is the cleartext part of the inner message
1250  *
1251  * Creates a new #GMimeAutocryptHeaderList of relevant headers of the
1252  * given type based on the recipient(s) of an e-mail message.
1253  *
1254  * You must pass the decrypted inner part of the message to this
1255  * function, since Autocrypt-Gossip headers are only stored within the
1256  * encrypted layer.
1257  *
1258  * If you don't already have the decrypted inner part available to
1259  * you, you probably want to use
1260  * #g_mime_message_get_autocrypt_gossip_headers instead.
1261  *
1262  * Each header in the returned list will:
1263  *
1264  *  - have a valid address
1265  *  - be of the type requested
1266  *  - be complete
1267  *
1268  * If no Autocrypt header is found for a recipient, no
1269  * #GMimeAutocryptHeader will be in the list associated with that e-mail address.
1270  *
1271  * Note that the following types of Autocrypt headers will not be
1272  * returned by this function:
1273  *
1274  *  - headers of an unrequested type
1275  *  - headers that do not match an address in "From:"
1276  *  - unparseable headers
1277  *  - headers with unknown critical attributes
1278  *  - duplicate valid headers for a given address
1279  *
1280  * On error (e.g. if this version of GMime cannot handle the requested
1281  * Autocrypt type, or if a parameter is missing or malformed), returns
1282  * %NULL
1283  *
1284  * The returned Autocrypt headers will have their effective_date set
1285  * to the earliest of either:
1286  *
1287  * - the Date: header of the message or
1288  * - @now (or the current time, if @now is %NULL)
1289  *
1290  * Returns: (transfer full): a new #GMimeAutocryptHeaderList object, or %NULL on error.
1291  **/
1292 GMimeAutocryptHeaderList *
g_mime_message_get_autocrypt_gossip_headers_from_inner_part(GMimeMessage * message,GDateTime * now,GMimeObject * inner_part)1293 g_mime_message_get_autocrypt_gossip_headers_from_inner_part (GMimeMessage *message, GDateTime *now, GMimeObject *inner_part)
1294 {
1295 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1296 	g_return_val_if_fail (GMIME_IS_OBJECT (inner_part), NULL);
1297 	InternetAddressList *addresses = g_mime_message_get_all_recipients (message);
1298 	GDateTime *newnow = NULL;
1299 	GDateTime *effective_date = NULL;
1300 	GMimeAutocryptHeaderList *ret = NULL;
1301 	if (now == NULL)
1302 		now = newnow = g_date_time_new_now_utc ();
1303 	effective_date = now;
1304 	if (message->date && g_date_time_compare (message->date, now) < 0)
1305 		effective_date = message->date;
1306 	ret = g_mime_object_get_autocrypt_headers (inner_part,
1307 						   effective_date,
1308 						   "autocrypt-gossip",
1309 						   addresses, FALSE);
1310 	g_object_unref (addresses);
1311 	if (newnow)
1312 		g_date_time_unref (newnow);
1313 	return ret;
1314 }
1315 
1316 
1317 /**
1318  * g_mime_message_get_autocrypt_gossip_headers:
1319  * @message: a #GMimeMessage object, which is expected to be encrypted.
1320  * @now: a #GDateTime object, or %NULL
1321  * @flags: a #GMimeDecryptFlags, to be used during decryption
1322  * @session_key: session key to use or %NULL
1323  * @err: a #GError (can be %NULL)
1324  *
1325  * Creates a new #GMimeAutocryptHeaderList of relevant headers of the
1326  * given type based on the recipient(s) of an e-mail message.
1327  *
1328  * Returns the same object as
1329  * #g_mime_message_get_autocrypt_gossip_headers_with_inner_part , but
1330  * handles decryption and cleanup automatically.
1331  *
1332  * @flags and @session_key are passed through to
1333  * #g_mime_multipart_encrypted_decrypt, as needed.
1334  *
1335  * If the message is not actually an encrypted message, returns %NULL:
1336  * it should be ignored for purposes of evaluating gossip.
1337  *
1338  * If decryption fails, returns %NULL.  In this case, an exception
1339  * will be set on @err to provide information about the decryption
1340  * failure.
1341  *
1342  * Returns: (transfer full): a new #GMimeAutocryptHeaderList object,
1343  * or %NULL on error.
1344  **/
g_mime_message_get_autocrypt_gossip_headers(GMimeMessage * message,GDateTime * now,GMimeDecryptFlags flags,const char * session_key,GError ** err)1345 GMimeAutocryptHeaderList *g_mime_message_get_autocrypt_gossip_headers (GMimeMessage *message,
1346 								       GDateTime *now,
1347 								       GMimeDecryptFlags flags,
1348 								       const char *session_key,
1349 								       GError **err)
1350 {
1351 	g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1352 	GMimeAutocryptHeaderList *ret = NULL;
1353 	GMimeObject *top_level = NULL;
1354 	GMimeObject *inner_part = NULL;
1355 
1356 	top_level = g_mime_message_get_mime_part (message);
1357 	if (!GMIME_IS_MULTIPART_ENCRYPTED (top_level))
1358 		return NULL;
1359 
1360 	inner_part = g_mime_multipart_encrypted_decrypt (GMIME_MULTIPART_ENCRYPTED (top_level),
1361 							 flags,
1362 							 session_key,
1363 							 NULL, /* we do not care about decryptresult */
1364 							 err);
1365 	if (inner_part) {
1366 		ret = g_mime_message_get_autocrypt_gossip_headers_from_inner_part (message, now, inner_part);
1367 		g_object_unref (inner_part);
1368 	}
1369 
1370 	return ret;
1371 }
1372