1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2000-2012 Jeffrey Stedfast
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.
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.
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
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-table-private.h"
39 #include "gmime-parse-utils.h"
40 #include "gmime-events.h"
44 * SECTION: gmime-message
45 * @title: GMimeMessage
46 * @short_description: Messages
49 * A #GMimeMessage represents an rfc822 message.
52 extern GMimeEvent *_g_mime_header_list_get_changed_event (GMimeHeaderList *headers);
54 static void g_mime_message_class_init (GMimeMessageClass *klass);
55 static void g_mime_message_init (GMimeMessage *message, GMimeMessageClass *klass);
56 static void g_mime_message_finalize (GObject *object);
58 /* GMimeObject class methods */
59 static void message_prepend_header (GMimeObject *object, const char *header, const char *value);
60 static void message_append_header (GMimeObject *object, const char *header, const char *value);
61 static void message_set_header (GMimeObject *object, const char *header, const char *value);
62 static const char *message_get_header (GMimeObject *object, const char *header);
63 static gboolean message_remove_header (GMimeObject *object, const char *header);
64 static char *message_get_headers (GMimeObject *object);
65 static ssize_t message_write_to_stream (GMimeObject *object, GMimeStream *stream);
66 static void message_encode (GMimeObject *object, GMimeEncodingConstraint constraint);
68 static ssize_t write_structured (GMimeStream *stream, const char *name, const char *value);
69 static ssize_t write_addrspec (GMimeStream *stream, const char *name, const char *value);
70 static ssize_t write_received (GMimeStream *stream, const char *name, const char *value);
71 static ssize_t write_subject (GMimeStream *stream, const char *name, const char *value);
72 static ssize_t write_msgid (GMimeStream *stream, const char *name, const char *value);
74 static void to_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
75 static void cc_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
76 static void bcc_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message);
79 static GMimeObjectClass *parent_class = NULL;
84 GMimeEventCallback changed_cb;
85 } recipient_types[] = {
86 { "To", (GMimeEventCallback) to_list_changed },
87 { "Cc", (GMimeEventCallback) cc_list_changed },
88 { "Bcc", (GMimeEventCallback) bcc_list_changed }
91 #define N_RECIPIENT_TYPES G_N_ELEMENTS (recipient_types)
93 static char *rfc822_headers[] = {
107 g_mime_message_get_type (void)
109 static GType type = 0;
112 static const GTypeInfo info = {
113 sizeof (GMimeMessageClass),
114 NULL, /* base_class_init */
115 NULL, /* base_class_finalize */
116 (GClassInitFunc) g_mime_message_class_init,
117 NULL, /* class_finalize */
118 NULL, /* class_data */
119 sizeof (GMimeMessage),
121 (GInstanceInitFunc) g_mime_message_init,
124 type = g_type_register_static (GMIME_TYPE_OBJECT, "GMimeMessage", &info, 0);
132 g_mime_message_class_init (GMimeMessageClass *klass)
134 GMimeObjectClass *object_class = GMIME_OBJECT_CLASS (klass);
135 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
137 parent_class = g_type_class_ref (GMIME_TYPE_OBJECT);
139 gobject_class->finalize = g_mime_message_finalize;
141 object_class->prepend_header = message_prepend_header;
142 object_class->append_header = message_append_header;
143 object_class->remove_header = message_remove_header;
144 object_class->set_header = message_set_header;
145 object_class->get_header = message_get_header;
146 object_class->get_headers = message_get_headers;
147 object_class->write_to_stream = message_write_to_stream;
148 object_class->encode = message_encode;
152 mime_part_headers_changed (GMimeHeaderList *headers, gpointer args, GMimeMessage *message)
154 /* clear the message's header stream */
155 g_mime_header_list_set_stream (((GMimeObject *) message)->headers, NULL);
159 connect_changed_event (GMimeMessage *message, GMimeRecipientType type)
161 InternetAddressList *list;
163 list = message->recipients[type];
165 g_mime_event_add (list->priv, recipient_types[type].changed_cb, message);
169 disconnect_changed_event (GMimeMessage *message, GMimeRecipientType type)
171 InternetAddressList *list;
173 list = message->recipients[type];
175 g_mime_event_remove (list->priv, recipient_types[type].changed_cb, message);
179 block_changed_event (GMimeMessage *message, GMimeRecipientType type)
181 InternetAddressList *list;
183 list = message->recipients[type];
185 g_mime_event_block (list->priv, recipient_types[type].changed_cb, message);
189 unblock_changed_event (GMimeMessage *message, GMimeRecipientType type)
191 InternetAddressList *list;
193 list = message->recipients[type];
195 g_mime_event_unblock (list->priv, recipient_types[type].changed_cb, message);
199 g_mime_message_init (GMimeMessage *message, GMimeMessageClass *klass)
201 GMimeHeaderList *headers = ((GMimeObject *) message)->headers;
204 message->from = NULL;
205 message->reply_to = NULL;
206 message->recipients = g_new (InternetAddressList *, N_RECIPIENT_TYPES);
207 message->subject = NULL;
209 message->tz_offset = 0;
210 message->message_id = NULL;
211 message->mime_part = NULL;
213 /* initialize recipient lists */
214 for (i = 0; i < N_RECIPIENT_TYPES; i++) {
215 message->recipients[i] = internet_address_list_new ();
216 connect_changed_event (message, i);
219 g_mime_header_list_register_writer (headers, "Sender", write_addrspec);
220 g_mime_header_list_register_writer (headers, "From", write_addrspec);
221 g_mime_header_list_register_writer (headers, "To", write_addrspec);
222 g_mime_header_list_register_writer (headers, "Cc", write_addrspec);
223 g_mime_header_list_register_writer (headers, "Bcc", write_addrspec);
225 g_mime_header_list_register_writer (headers, "Resent-Sender", write_addrspec);
226 g_mime_header_list_register_writer (headers, "Resent-From", write_addrspec);
227 g_mime_header_list_register_writer (headers, "Resent-To", write_addrspec);
228 g_mime_header_list_register_writer (headers, "Resent-Cc", write_addrspec);
229 g_mime_header_list_register_writer (headers, "Resent-Bcc", write_addrspec);
231 g_mime_header_list_register_writer (headers, "Subject", write_subject);
232 g_mime_header_list_register_writer (headers, "Received", write_received);
233 g_mime_header_list_register_writer (headers, "Message-Id", write_msgid);
234 g_mime_header_list_register_writer (headers, "References", write_structured);
238 g_mime_message_finalize (GObject *object)
240 GMimeMessage *message = (GMimeMessage *) object;
244 g_free (message->from);
245 g_free (message->reply_to);
247 /* disconnect changed handlers */
248 for (i = 0; i < N_RECIPIENT_TYPES; i++) {
249 disconnect_changed_event (message, i);
250 g_object_unref (message->recipients[i]);
253 g_free (message->recipients);
255 g_free (message->subject);
257 g_free (message->message_id);
259 /* unref child mime part */
260 if (message->mime_part) {
261 changed = _g_mime_header_list_get_changed_event (message->mime_part->headers);
262 g_mime_event_remove (changed, (GMimeEventCallback) mime_part_headers_changed, message);
263 g_object_unref (message->mime_part);
266 G_OBJECT_CLASS (parent_class)->finalize (object);
270 typedef void (* token_skip_t) (const char **in);
272 struct _received_token {
278 static void skip_atom (const char **in);
279 static void skip_domain (const char **in);
280 static void skip_addr (const char **in);
281 static void skip_msgid (const char **in);
283 static struct _received_token received_tokens[] = {
284 { "from ", 5, skip_domain },
285 { "by ", 3, skip_domain },
286 { "via ", 4, skip_atom },
287 { "with ", 5, skip_atom },
288 { "id ", 3, skip_msgid },
289 { "for ", 4, skip_addr }
293 skip_atom (const char **in)
295 register const char *inptr;
299 while (is_atom (*inptr))
305 skip_comment (const char **in)
307 register const char *inptr = *in;
313 while (*inptr && depth > 0) {
316 else if (*inptr == ')')
328 skip_quoted_string (const char **in)
330 const char *inptr = *in;
332 decode_lwsp (&inptr);
335 while (*inptr && *inptr != '"') {
351 skip_word (const char **in)
355 skip_quoted_string (in);
362 skip_domain_subliteral (const char **in)
364 const char *inptr = *in;
366 while (*inptr && *inptr != '.' && *inptr != ']') {
367 if (is_dtext (*inptr)) {
369 } else if (is_lwsp (*inptr)) {
370 decode_lwsp (&inptr);
380 skip_domain_literal (const char **in)
382 const char *inptr = *in;
384 decode_lwsp (&inptr);
385 while (*inptr && *inptr != ']') {
386 skip_domain_subliteral (&inptr);
387 if (*inptr && *inptr != ']')
395 skip_domain (const char **in)
397 const char *save, *inptr = *in;
399 while (inptr && *inptr) {
400 decode_lwsp (&inptr);
404 skip_domain_literal (&inptr);
412 decode_lwsp (&inptr);
425 skip_addrspec (const char **in)
427 const char *inptr = *in;
429 decode_lwsp (&inptr);
431 decode_lwsp (&inptr);
433 while (*inptr == '.') {
436 decode_lwsp (&inptr);
441 skip_domain (&inptr);
448 skip_addr (const char **in)
450 const char *inptr = *in;
452 decode_lwsp (&inptr);
455 skip_addrspec (&inptr);
459 skip_addrspec (&inptr);
466 skip_msgid (const char **in)
468 const char *inptr = *in;
470 decode_lwsp (&inptr);
473 skip_addrspec (&inptr);
484 struct _received_part {
485 struct _received_part *next;
491 write_received (GMimeStream *stream, const char *name, const char *value)
493 struct _received_part *parts, *part, *tail;
494 const char *inptr, *lwsp = NULL;
500 while (is_lwsp (*value))
506 str = g_string_new (name);
507 g_string_append_len (str, ": ", 2);
510 tail = parts = part = g_alloca (sizeof (struct _received_part));
511 part->start = inptr = value;
515 for (i = 0; i < G_N_ELEMENTS (received_tokens); i++) {
516 if (!strncmp (inptr, received_tokens[i].token, received_tokens[i].len)) {
517 if (inptr > part->start) {
518 g_assert (lwsp != NULL);
519 part->len = lwsp - part->start;
521 part = g_alloca (sizeof (struct _received_part));
529 inptr += received_tokens[i].len;
530 received_tokens[i].skip (&inptr);
533 while (is_lwsp (*inptr))
539 part->len = inptr - part->start;
542 while (is_lwsp (*inptr))
545 part = g_alloca (sizeof (struct _received_part));
557 if (i == G_N_ELEMENTS (received_tokens)) {
558 while (*inptr && !is_lwsp (*inptr))
562 while (is_lwsp (*inptr))
567 skip_comment (&inptr);
570 while (is_lwsp (*inptr))
575 part->len = lwsp - part->start;
580 len += lwsp ? part->start - lwsp : 0;
581 if (len + part->len > GMIME_FOLD_LEN && part != parts) {
582 g_string_append (str, "\n\t");
585 g_string_append_len (str, lwsp, (size_t) (part->start - lwsp));
588 g_string_append_len (str, part->start, part->len);
589 lwsp = part->start + part->len;
593 } while (part != NULL);
595 g_string_append_c (str, '\n');
597 nwritten = g_mime_stream_write (stream, str->str, str->len);
598 g_string_free (str, TRUE);
604 write_subject (GMimeStream *stream, const char *name, const char *value)
606 char *unfolded, *folded;
609 unfolded = g_strdup_printf ("%s: %s\n", name, value);
610 folded = g_mime_utils_unstructured_header_fold (unfolded);
613 n = g_mime_stream_write_string (stream, folded);
620 write_msgid (GMimeStream *stream, const char *name, const char *value)
622 /* we don't want to wrap the Message-Id header - seems to
623 break a lot of clients (and servers) */
624 return g_mime_stream_printf (stream, "%s: %s\n", name, value);
628 write_structured (GMimeStream *stream, const char *name, const char *value)
630 char *unfolded, *folded;
633 unfolded = g_strdup_printf ("%s: %s\n", name, value);
634 folded = g_mime_utils_structured_header_fold (unfolded);
637 n = g_mime_stream_write_string (stream, folded);
644 write_addrspec (GMimeStream *stream, const char *name, const char *value)
646 InternetAddressList *addrlist;
650 str = g_string_new (name);
651 g_string_append (str, ": ");
653 if (value && (addrlist = internet_address_list_parse_string (value))) {
654 internet_address_list_writer (addrlist, str);
655 g_object_unref (addrlist);
658 g_string_append_c (str, '\n');
660 n = g_mime_stream_write (stream, str->str, str->len);
661 g_string_free (str, TRUE);
679 static const char *message_headers[] = {
698 message_add_recipients_from_string (GMimeMessage *message, int action, GMimeRecipientType type, const char *str)
700 InternetAddressList *recipients, *addrlist;
702 recipients = g_mime_message_get_recipients (message, type);
705 internet_address_list_clear (recipients);
707 if ((addrlist = internet_address_list_parse_string (str))) {
708 if (action == PREPEND)
709 internet_address_list_prepend (recipients, addrlist);
711 internet_address_list_append (recipients, addrlist);
713 g_object_unref (addrlist);
718 process_header (GMimeObject *object, int action, const char *header, const char *value)
720 GMimeMessage *message = (GMimeMessage *) object;
721 InternetAddressList *addrlist;
726 for (i = 0; i < G_N_ELEMENTS (message_headers); i++) {
727 if (!g_ascii_strcasecmp (message_headers[i], header))
733 g_free (message->from);
734 if ((addrlist = internet_address_list_parse_string (value))) {
735 message->from = internet_address_list_to_string (addrlist, FALSE);
736 g_object_unref (addrlist);
738 message->from = NULL;
741 case HEADER_REPLY_TO:
742 g_free (message->reply_to);
743 if ((addrlist = internet_address_list_parse_string (value))) {
744 message->reply_to = internet_address_list_to_string (addrlist, FALSE);
745 g_object_unref (addrlist);
747 message->reply_to = NULL;
751 block_changed_event (message, GMIME_RECIPIENT_TYPE_TO);
752 message_add_recipients_from_string (message, action, GMIME_RECIPIENT_TYPE_TO, value);
753 unblock_changed_event (message, GMIME_RECIPIENT_TYPE_TO);
756 block_changed_event (message, GMIME_RECIPIENT_TYPE_CC);
757 message_add_recipients_from_string (message, action, GMIME_RECIPIENT_TYPE_CC, value);
758 unblock_changed_event (message, GMIME_RECIPIENT_TYPE_CC);
761 block_changed_event (message, GMIME_RECIPIENT_TYPE_BCC);
762 message_add_recipients_from_string (message, action, GMIME_RECIPIENT_TYPE_BCC, value);
763 unblock_changed_event (message, GMIME_RECIPIENT_TYPE_BCC);
766 g_free (message->subject);
767 message->subject = g_mime_utils_header_decode_text (value);
771 date = g_mime_utils_header_decode_date (value, &offset);
772 message->date = date;
773 message->tz_offset = offset;
776 case HEADER_MESSAGE_ID:
777 g_free (message->message_id);
778 message->message_id = g_mime_utils_decode_message_id (value);
780 case HEADER_MIME_VERSION:
790 message_prepend_header (GMimeObject *object, const char *header, const char *value)
792 GMimeMessage *message = (GMimeMessage *) object;
794 /* Content-* headers don't belong on the message, they belong on the part. */
795 if (!g_ascii_strncasecmp ("Content-", header, 8)) {
796 if (message->mime_part)
797 g_mime_object_prepend_header (message->mime_part, header, value);
801 if (!process_header (object, PREPEND, header, value))
802 GMIME_OBJECT_CLASS (parent_class)->prepend_header (object, header, value);
804 g_mime_header_list_prepend (object->headers, header, value);
806 if (message->mime_part)
807 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
811 message_append_header (GMimeObject *object, const char *header, const char *value)
813 GMimeMessage *message = (GMimeMessage *) object;
815 /* Content-* headers don't belong on the message, they belong on the part. */
816 if (!g_ascii_strncasecmp ("Content-", header, 8)) {
817 if (message->mime_part)
818 g_mime_object_append_header (message->mime_part, header, value);
822 if (!process_header (object, APPEND, header, value))
823 GMIME_OBJECT_CLASS (parent_class)->append_header (object, header, value);
825 g_mime_header_list_append (object->headers, header, value);
827 if (message->mime_part)
828 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
832 message_set_header (GMimeObject *object, const char *header, const char *value)
834 GMimeMessage *message = (GMimeMessage *) object;
836 /* Content-* headers don't belong on the message, they belong on the part. */
837 if (!g_ascii_strncasecmp ("Content-", header, 8)) {
838 if (message->mime_part)
839 g_mime_object_set_header (message->mime_part, header, value);
843 if (!process_header (object, SET, header, value))
844 GMIME_OBJECT_CLASS (parent_class)->set_header (object, header, value);
846 g_mime_header_list_set (object->headers, header, value);
848 if (message->mime_part)
849 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
853 message_get_header (GMimeObject *object, const char *header)
855 GMimeMessage *message = (GMimeMessage *) object;
858 /* Content-* headers don't belong on the message, they belong on the part. */
859 if (g_ascii_strncasecmp ("Content-", header, 8) != 0) {
860 if ((value = GMIME_OBJECT_CLASS (parent_class)->get_header (object, header)))
863 if (!g_ascii_strcasecmp ("MIME-Version", header))
865 } else if (message->mime_part) {
866 return g_mime_object_get_header (message->mime_part, header);
873 message_remove_header (GMimeObject *object, const char *header)
875 GMimeMessage *message = (GMimeMessage *) object;
876 InternetAddressList *addrlist;
877 GMimeRecipientType type;
880 /* Content-* headers don't belong on the message, they belong on the part. */
881 if (!g_ascii_strncasecmp ("Content-", header, 8)) {
882 if (message->mime_part)
883 return g_mime_object_remove_header (message->mime_part, header);
888 for (i = 0; i < G_N_ELEMENTS (message_headers); i++) {
889 if (!g_ascii_strcasecmp (message_headers[i], header))
895 g_free (message->from);
896 message->from = NULL;
898 case HEADER_REPLY_TO:
899 g_free (message->reply_to);
900 message->reply_to = NULL;
903 type = GMIME_RECIPIENT_TYPE_TO;
904 block_changed_event (message, type);
905 addrlist = message->recipients[type];
906 internet_address_list_clear (addrlist);
907 unblock_changed_event (message, type);
910 type = GMIME_RECIPIENT_TYPE_CC;
911 block_changed_event (message, type);
912 addrlist = message->recipients[type];
913 internet_address_list_clear (addrlist);
914 unblock_changed_event (message, type);
917 type = GMIME_RECIPIENT_TYPE_BCC;
918 block_changed_event (message, type);
919 addrlist = message->recipients[type];
920 internet_address_list_clear (addrlist);
921 unblock_changed_event (message, type);
924 g_free (message->subject);
925 message->subject = NULL;
929 message->tz_offset = 0;
931 case HEADER_MESSAGE_ID:
932 g_free (message->message_id);
933 message->message_id = NULL;
939 if (message->mime_part)
940 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
942 return GMIME_OBJECT_CLASS (parent_class)->remove_header (object, header);
947 message_get_headers (GMimeObject *object)
949 GMimeMessage *message = (GMimeMessage *) object;
954 ba = g_byte_array_new ();
955 stream = g_mime_stream_mem_new ();
956 g_mime_stream_mem_set_byte_array (GMIME_STREAM_MEM (stream), ba);
958 if (message->mime_part && g_mime_header_list_get_stream (message->mime_part->headers)) {
959 /* if the mime part has raw headers, then it contains the message headers as well */
960 g_mime_header_list_write_to_stream (message->mime_part->headers, stream);
962 g_mime_header_list_write_to_stream (object->headers, stream);
963 if (message->mime_part) {
964 if (g_mime_object_get_header (message->mime_part, "Content-Type") &&
965 !g_mime_header_list_get (object->headers, "MIME-Version"))
966 g_mime_stream_write_string (stream, "MIME-Version: 1.0\n");
967 g_mime_header_list_write_to_stream (message->mime_part->headers, stream);
971 g_object_unref (stream);
972 g_byte_array_append (ba, (unsigned char *) "", 1);
973 str = (char *) ba->data;
974 g_byte_array_free (ba, FALSE);
980 message_write_to_stream (GMimeObject *object, GMimeStream *stream)
982 GMimeMessage *message = (GMimeMessage *) object;
983 ssize_t nwritten, total = 0;
985 if (message->mime_part) {
986 if (!g_mime_header_list_get_stream (message->mime_part->headers)) {
987 if ((nwritten = g_mime_header_list_write_to_stream (object->headers, stream)) == -1)
992 if (!g_mime_header_list_get (object->headers, "MIME-Version")) {
993 if ((nwritten = g_mime_stream_write_string (stream, "MIME-Version: 1.0\n")) == -1)
1000 if ((nwritten = g_mime_object_write_to_stream (message->mime_part, stream)) == -1)
1003 if ((nwritten = g_mime_header_list_write_to_stream (object->headers, stream)) == -1)
1008 if ((nwritten = g_mime_stream_write (stream, "\n", 1)) == -1)
1018 message_encode (GMimeObject *object, GMimeEncodingConstraint constraint)
1020 GMimeMessage *message = (GMimeMessage *) object;
1022 if (message->mime_part != NULL)
1023 g_mime_object_encode (message->mime_part, constraint);
1029 * g_mime_message_new:
1030 * @pretty_headers: make pretty headers
1032 * If @pretty_headers is %TRUE, then the standard rfc822 headers are
1033 * initialized so as to put headers in a nice friendly order. This is
1034 * strictly a cosmetic thing, so if you are unsure, it is safe to say
1037 * Returns: an empty #GMimeMessage object.
1040 g_mime_message_new (gboolean pretty_headers)
1042 GMimeHeaderList *headers;
1043 GMimeMessage *message;
1046 message = g_object_newv (GMIME_TYPE_MESSAGE, 0, NULL);
1048 if (pretty_headers) {
1049 /* Populate with the "standard" rfc822 headers so we can have a standard order */
1050 headers = ((GMimeObject *) message)->headers;
1051 for (i = 0; i < G_N_ELEMENTS (rfc822_headers); i++)
1052 g_mime_header_list_set (headers, rfc822_headers[i], NULL);
1060 * g_mime_message_set_sender:
1061 * @message: MIME Message to change
1062 * @sender: The name and address of the sender
1064 * Set the sender's name and address on the MIME Message.
1065 * (ex: "\"Joe Sixpack\" <joe@sixpack.org>")
1068 g_mime_message_set_sender (GMimeMessage *message, const char *sender)
1070 InternetAddressList *addrlist;
1073 g_return_if_fail (GMIME_IS_MESSAGE (message));
1074 g_return_if_fail (sender != NULL);
1076 g_free (message->from);
1078 if ((addrlist = internet_address_list_parse_string (sender))) {
1079 message->from = internet_address_list_to_string (addrlist, FALSE);
1080 encoded = internet_address_list_to_string (addrlist, TRUE);
1081 g_mime_header_list_set (GMIME_OBJECT (message)->headers, "From", encoded);
1082 g_object_unref (addrlist);
1085 g_mime_header_list_set (GMIME_OBJECT (message)->headers, "From", "");
1086 message->from = NULL;
1089 if (message->mime_part)
1090 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1095 * g_mime_message_get_sender:
1096 * @message: MIME Message
1098 * Gets the email address of the sender from @message.
1100 * Returns: the sender's name and address of the MIME Message.
1103 g_mime_message_get_sender (GMimeMessage *message)
1105 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1107 return message->from;
1112 * g_mime_message_set_reply_to:
1113 * @message: MIME Message to change
1114 * @reply_to: The Reply-To address
1116 * Set the sender's Reply-To address on the MIME Message.
1119 g_mime_message_set_reply_to (GMimeMessage *message, const char *reply_to)
1121 g_return_if_fail (GMIME_IS_MESSAGE (message));
1122 g_return_if_fail (reply_to != NULL);
1124 g_free (message->reply_to);
1125 message->reply_to = g_mime_strdup_trim (reply_to);
1127 g_mime_header_list_set (GMIME_OBJECT (message)->headers, "Reply-To", message->reply_to);
1129 if (message->mime_part)
1130 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1135 * g_mime_message_get_reply_to:
1136 * @message: MIME Message
1138 * Gets the Reply-To address from @message.
1140 * Returns: the sender's Reply-To address from the MIME Message.
1143 g_mime_message_get_reply_to (GMimeMessage *message)
1145 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1147 return message->reply_to;
1152 sync_recipient_header (GMimeMessage *message, GMimeRecipientType type)
1154 GMimeObject *object = (GMimeObject *) message;
1155 const char *name = recipient_types[type].name;
1156 InternetAddressList *list;
1159 /* sync the specified recipient header */
1160 if ((list = g_mime_message_get_recipients (message, type))) {
1161 string = internet_address_list_to_string (list, TRUE);
1162 g_mime_header_list_set (object->headers, name, string);
1165 /* list should never be NULL... */
1166 g_mime_header_list_set (object->headers, name, NULL);
1169 if (message->mime_part)
1170 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1174 to_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
1176 sync_recipient_header (message, GMIME_RECIPIENT_TYPE_TO);
1180 cc_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
1182 sync_recipient_header (message, GMIME_RECIPIENT_TYPE_CC);
1186 bcc_list_changed (InternetAddressList *list, gpointer args, GMimeMessage *message)
1188 sync_recipient_header (message, GMIME_RECIPIENT_TYPE_BCC);
1193 * g_mime_message_add_recipient:
1194 * @message: MIME Message to change
1195 * @type: A #GMimeRecipientType
1196 * @name: The recipient's name (or %NULL)
1197 * @addr: The recipient's address
1199 * Add a recipient of a chosen type to the MIME Message.
1202 g_mime_message_add_recipient (GMimeMessage *message, GMimeRecipientType type, const char *name, const char *addr)
1204 InternetAddressList *recipients;
1205 InternetAddress *ia;
1207 g_return_if_fail (GMIME_IS_MESSAGE (message));
1208 g_return_if_fail (type < N_RECIPIENT_TYPES);
1209 g_return_if_fail (addr != NULL);
1211 recipients = message->recipients[type];
1212 ia = internet_address_mailbox_new (name, addr);
1213 internet_address_list_add (recipients, ia);
1214 g_object_unref (ia);
1216 if (message->mime_part)
1217 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1219 g_mime_header_list_set_stream (((GMimeObject *) message)->headers, NULL);
1224 * g_mime_message_get_recipients:
1225 * @message: MIME Message
1226 * @type: A #GMimeRecipientType
1228 * Gets a list of recipients of type @type from @message.
1230 * Returns: a list of recipients of a chosen type from the MIME
1233 InternetAddressList *
1234 g_mime_message_get_recipients (GMimeMessage *message, GMimeRecipientType type)
1236 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1237 g_return_val_if_fail (type < N_RECIPIENT_TYPES, NULL);
1239 return message->recipients[type];
1244 * g_mime_message_get_all_recipients:
1245 * @message: MIME Message
1247 * Gets the complete list of recipients for @message.
1249 * Returns: a newly allocated #InternetAddressList containing all
1250 * recipients of the message or %NULL if no recipients are set.
1252 InternetAddressList *
1253 g_mime_message_get_all_recipients (GMimeMessage *message)
1255 InternetAddressList *recipients, *list = NULL;
1258 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1260 for (i = 0; i < N_RECIPIENT_TYPES; i++) {
1261 recipients = message->recipients[i];
1263 if (internet_address_list_length (recipients) == 0)
1267 list = internet_address_list_new ();
1269 internet_address_list_append (list, recipients);
1277 * g_mime_message_set_subject:
1278 * @message: MIME Message
1279 * @subject: Subject string
1281 * Set the unencoded UTF-8 Subject field on a MIME Message.
1284 g_mime_message_set_subject (GMimeMessage *message, const char *subject)
1288 g_return_if_fail (GMIME_IS_MESSAGE (message));
1289 g_return_if_fail (subject != NULL);
1291 g_free (message->subject);
1292 message->subject = g_mime_strdup_trim (subject);
1294 encoded = g_mime_utils_header_encode_text (message->subject);
1295 g_mime_object_set_header (GMIME_OBJECT (message), "Subject", encoded);
1298 if (message->mime_part)
1299 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1304 * g_mime_message_get_subject:
1305 * @message: MIME Message
1307 * Gets the message's subject.
1309 * Returns: the unencoded UTF-8 Subject field on a MIME Message.
1312 g_mime_message_get_subject (GMimeMessage *message)
1314 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1316 return message->subject;
1321 * g_mime_message_set_date:
1322 * @message: MIME Message
1323 * @date: a date to be used in the Date header
1324 * @tz_offset: timezone offset (in +/- hours)
1326 * Sets the Date header on a MIME Message.
1329 g_mime_message_set_date (GMimeMessage *message, time_t date, int tz_offset)
1333 g_return_if_fail (GMIME_IS_MESSAGE (message));
1335 message->date = date;
1336 message->tz_offset = tz_offset;
1338 str = g_mime_utils_header_format_date (date, tz_offset);
1339 g_mime_object_set_header (GMIME_OBJECT (message), "Date", str);
1342 if (message->mime_part)
1343 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1348 * g_mime_message_get_date:
1349 * @message: MIME Message
1350 * @date: pointer to a date in time_t
1351 * @tz_offset: pointer to timezone offset (in +/- hours)
1353 * Stores the date in time_t format in @date. If @tz_offset is
1354 * non-%NULL, then the timezone offset in will be stored in
1358 g_mime_message_get_date (GMimeMessage *message, time_t *date, int *tz_offset)
1360 g_return_if_fail (GMIME_IS_MESSAGE (message));
1361 g_return_if_fail (date != NULL);
1363 *date = message->date;
1366 *tz_offset = message->tz_offset;
1371 * g_mime_message_get_date_as_string:
1372 * @message: MIME Message
1374 * Gets the message's sent-date in string format.
1376 * Returns: a newly allocated string containing the Date header value.
1379 g_mime_message_get_date_as_string (GMimeMessage *message)
1381 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1383 return g_mime_utils_header_format_date (message->date, message->tz_offset);
1388 * g_mime_message_set_date_as_string:
1389 * @message: MIME Message
1390 * @str: a date string
1392 * Sets the sent-date of the message.
1395 g_mime_message_set_date_as_string (GMimeMessage *message, const char *str)
1401 g_return_if_fail (GMIME_IS_MESSAGE (message));
1403 date = g_mime_utils_header_decode_date (str, &tz_offset);
1404 message->tz_offset = tz_offset;
1405 message->date = date;
1407 buf = g_mime_utils_header_format_date (date, tz_offset);
1408 g_mime_object_set_header (GMIME_OBJECT (message), "Date", buf);
1411 if (message->mime_part)
1412 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1417 * g_mime_message_set_message_id:
1418 * @message: MIME Message
1419 * @message_id: message-id (addr-spec portion)
1421 * Set the Message-Id on a message.
1424 g_mime_message_set_message_id (GMimeMessage *message, const char *message_id)
1428 g_return_if_fail (GMIME_IS_MESSAGE (message));
1429 g_return_if_fail (message_id != NULL);
1431 g_free (message->message_id);
1432 message->message_id = g_mime_strdup_trim (message_id);
1434 msgid = g_strdup_printf ("<%s>", message_id);
1435 g_mime_object_set_header (GMIME_OBJECT (message), "Message-Id", msgid);
1438 if (message->mime_part)
1439 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1444 * g_mime_message_get_message_id:
1445 * @message: MIME Message
1447 * Gets the Message-Id header of @message.
1449 * Returns: the Message-Id of a message.
1452 g_mime_message_get_message_id (GMimeMessage *message)
1454 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1456 return message->message_id;
1461 * g_mime_message_get_mime_part:
1462 * @message: MIME Message
1464 * Gets the toplevel MIME part contained within @message.
1466 * Returns: the toplevel MIME part of @message.
1469 g_mime_message_get_mime_part (GMimeMessage *message)
1471 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1473 if (message->mime_part == NULL)
1476 return message->mime_part;
1481 * g_mime_message_set_mime_part:
1482 * @message: MIME Message
1483 * @mime_part: The root-level MIME Part
1485 * Set the root-level MIME part of the message.
1488 g_mime_message_set_mime_part (GMimeMessage *message, GMimeObject *mime_part)
1490 GMimeEvent *changed;
1492 g_return_if_fail (mime_part == NULL || GMIME_IS_OBJECT (mime_part));
1493 g_return_if_fail (GMIME_IS_MESSAGE (message));
1495 if (message->mime_part == mime_part)
1498 if (message->mime_part) {
1499 changed = _g_mime_header_list_get_changed_event (message->mime_part->headers);
1500 g_mime_event_remove (changed, (GMimeEventCallback) mime_part_headers_changed, message);
1502 g_mime_header_list_set_stream (message->mime_part->headers, NULL);
1503 g_object_unref (message->mime_part);
1507 changed = _g_mime_header_list_get_changed_event (mime_part->headers);
1508 g_mime_header_list_set_stream (mime_part->headers, NULL);
1509 g_mime_event_add (changed, (GMimeEventCallback) mime_part_headers_changed, message);
1510 g_object_ref (mime_part);
1513 g_mime_header_list_set_stream (((GMimeObject *) message)->headers, NULL);
1515 message->mime_part = mime_part;
1520 * g_mime_message_foreach:
1521 * @message: a #GMimeMessage
1522 * @callback: function to call on each of the mime parts contained by the mime message
1523 * @user_data: user-supplied callback data
1525 * Recursively calls @callback on each of the mime parts in the mime message.
1528 g_mime_message_foreach (GMimeMessage *message, GMimeObjectForeachFunc callback, gpointer user_data)
1530 g_return_if_fail (GMIME_IS_MESSAGE (message));
1531 g_return_if_fail (callback != NULL);
1533 callback ((GMimeObject *) message, message->mime_part, user_data);
1535 if (GMIME_IS_MULTIPART (message->mime_part))
1536 g_mime_multipart_foreach ((GMimeMultipart *) message->mime_part, callback, user_data);
1540 part_is_textual (GMimeObject *mime_part)
1542 GMimeContentType *type;
1544 type = g_mime_object_get_content_type (mime_part);
1546 return g_mime_content_type_is_type (type, "text", "*");
1549 static GMimeObject *
1550 multipart_guess_body (GMimeMultipart *multipart)
1552 GMimeContentType *type;
1553 GMimeObject *mime_part;
1556 if (GMIME_IS_MULTIPART_ENCRYPTED (multipart)) {
1557 /* nothing more we can do */
1558 return (GMimeObject *) multipart;
1561 type = g_mime_object_get_content_type ((GMimeObject *) multipart);
1562 if (g_mime_content_type_is_type (type, "multipart", "alternative")) {
1563 /* very likely that this is the body - leave it up to
1564 * our caller to decide which format of the body it
1566 return (GMimeObject *) multipart;
1569 count = g_mime_multipart_get_count (multipart);
1571 if (count >= 1 && GMIME_IS_MULTIPART_SIGNED (multipart)) {
1572 /* if the body is in here, it has to be the first part */
1576 for (i = 0; i < count; i++) {
1577 mime_part = g_mime_multipart_get_part (multipart, i);
1579 if (GMIME_IS_MULTIPART (mime_part)) {
1580 if ((mime_part = multipart_guess_body ((GMimeMultipart *) mime_part)))
1582 } else if (GMIME_IS_PART (mime_part)) {
1583 if (part_is_textual (mime_part))
1593 * g_mime_message_get_body:
1594 * @message: MIME Message
1596 * Attempts to identify the MIME part containing the body of the
1599 * Returns: a #GMimeObject containing the textual content that appears
1600 * to be the main body of the message.
1602 * Note: This function is NOT guarenteed to always work as it
1603 * makes some assumptions that are not necessarily true. It is
1604 * recommended that you traverse the MIME structure yourself.
1607 g_mime_message_get_body (GMimeMessage *message)
1609 GMimeObject *mime_part;
1611 g_return_val_if_fail (GMIME_IS_MESSAGE (message), NULL);
1613 if (!(mime_part = message->mime_part))
1616 if (GMIME_IS_MULTIPART (mime_part))
1617 return multipart_guess_body ((GMimeMultipart *) mime_part);
1618 else if (GMIME_IS_PART (mime_part) && part_is_textual (mime_part))