1 /*
2 * e-mail-parser-application-mbox.c
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 #include "evolution-config.h"
19
20 #include <string.h>
21 #include <glib/gi18n-lib.h>
22
23 #include <e-util/e-util.h>
24
25 #include "e-mail-parser-extension.h"
26 #include "e-mail-part-utils.h"
27
28 typedef EMailParserExtension EMailParserApplicationMBox;
29 typedef EMailParserExtensionClass EMailParserApplicationMBoxClass;
30
31 GType e_mail_parser_application_mbox_get_type (void);
32
33 G_DEFINE_TYPE (
34 EMailParserApplicationMBox,
35 e_mail_parser_application_mbox,
36 E_TYPE_MAIL_PARSER_EXTENSION)
37
38 static const gchar *parser_mime_types[] = {
39 "application/mbox",
40 NULL
41 };
42
43 static void
empe_app_mbox_add_message(EMailParser * parser,CamelMimeMessage * message,gint nth_message,GString * part_id,GCancellable * cancellable,GQueue * out_mail_parts)44 empe_app_mbox_add_message (EMailParser *parser,
45 CamelMimeMessage *message,
46 gint nth_message,
47 GString *part_id,
48 GCancellable *cancellable,
49 GQueue *out_mail_parts)
50 {
51 GQueue work_queue = G_QUEUE_INIT;
52 CamelMimePart *opart;
53 gint old_len;
54
55 old_len = part_id->len;
56
57 g_string_append_printf (part_id, ".mbox.%d", nth_message);
58
59 opart = camel_mime_part_new ();
60 camel_medium_set_content (CAMEL_MEDIUM (opart), CAMEL_DATA_WRAPPER (message));
61 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (opart), "message/rfc822");
62
63 e_mail_parser_parse_part_as (
64 parser, opart, part_id, "message/rfc822",
65 cancellable, &work_queue);
66
67 /* Wrap every message as attachment */
68 e_mail_parser_wrap_as_attachment (parser, opart, part_id, &work_queue);
69
70 /* Inline all messages in mbox */
71 if (!g_queue_is_empty (&work_queue)) {
72 EMailPart *pp = g_queue_peek_head (&work_queue);
73
74 pp->force_inline = TRUE;
75 }
76
77 e_queue_transfer (&work_queue, out_mail_parts);
78
79 g_string_truncate (part_id, old_len);
80
81 g_object_unref (opart);
82 }
83
84 static gboolean
empe_app_mbox_parse(EMailParserExtension * extension,EMailParser * parser,CamelMimePart * part,GString * part_id,GCancellable * cancellable,GQueue * out_mail_parts)85 empe_app_mbox_parse (EMailParserExtension *extension,
86 EMailParser *parser,
87 CamelMimePart *part,
88 GString *part_id,
89 GCancellable *cancellable,
90 GQueue *out_mail_parts)
91 {
92 CamelMimeParser *mime_parser;
93 CamelStream *mem_stream;
94 CamelMimeParserState state;
95 gint messages;
96 GError *error = NULL;
97
98 /* Extract messages from the application/mbox part and
99 * render them as a flat list of messages. */
100
101 /* XXX If the mbox has multiple messages, maybe render them
102 * as a multipart/digest so each message can be expanded
103 * or collapsed individually.
104 *
105 * See attachment_handler_mail_x_uid_list() for example. */
106
107 /* XXX This is based on em_utils_read_messages_from_stream().
108 * Perhaps refactor that function to return an array of
109 * messages instead of assuming we want to append them
110 * to a folder? */
111
112 mime_parser = camel_mime_parser_new ();
113 camel_mime_parser_scan_from (mime_parser, TRUE);
114
115 mem_stream = camel_stream_mem_new ();
116 camel_data_wrapper_decode_to_stream_sync (
117 camel_medium_get_content (CAMEL_MEDIUM (part)),
118 mem_stream, NULL, NULL);
119 g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, cancellable, NULL);
120
121 camel_mime_parser_init_with_stream (mime_parser, mem_stream, &error);
122 if (error != NULL) {
123 e_mail_parser_error (
124 parser, out_mail_parts,
125 _("Error parsing MBOX part: %s"),
126 error->message);
127 g_object_unref (mem_stream);
128 g_object_unref (mime_parser);
129 g_error_free (error);
130 return TRUE;
131 }
132
133 /* Extract messages from the mbox. */
134 messages = 0;
135 state = camel_mime_parser_step (mime_parser, NULL, NULL);
136
137 while (state == CAMEL_MIME_PARSER_STATE_FROM) {
138 CamelMimeMessage *message;
139
140 message = camel_mime_message_new ();
141
142 if (!camel_mime_part_construct_from_parser_sync (
143 CAMEL_MIME_PART (message), mime_parser, NULL, NULL)) {
144 g_object_unref (message);
145 break;
146 }
147
148 empe_app_mbox_add_message (parser, message, messages, part_id, cancellable, out_mail_parts);
149 messages++;
150
151 g_object_unref (message);
152
153 /* Skip past CAMEL_MIME_PARSER_STATE_FROM_END. */
154 camel_mime_parser_step (mime_parser, NULL, NULL);
155
156 state = camel_mime_parser_step (mime_parser, NULL, NULL);
157 }
158
159 if (!messages) {
160 CamelMimeMessage *message;
161
162 g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, cancellable, NULL);
163
164 message = camel_mime_message_new ();
165
166 if (camel_data_wrapper_construct_from_stream_sync (CAMEL_DATA_WRAPPER (message), mem_stream, NULL, NULL)) {
167 empe_app_mbox_add_message (parser, message, messages, part_id, cancellable, out_mail_parts);
168 messages++;
169 }
170
171 g_object_unref (message);
172 }
173
174 g_object_unref (mime_parser);
175 g_object_unref (mem_stream);
176
177 return messages > 0;
178 }
179
180 static void
e_mail_parser_application_mbox_class_init(EMailParserExtensionClass * class)181 e_mail_parser_application_mbox_class_init (EMailParserExtensionClass *class)
182 {
183 class->mime_types = parser_mime_types;
184 class->priority = G_PRIORITY_LOW;
185 class->flags =
186 E_MAIL_PARSER_EXTENSION_INLINE |
187 E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
188 class->parse = empe_app_mbox_parse;
189 }
190
191 static void
e_mail_parser_application_mbox_init(EMailParserExtension * extension)192 e_mail_parser_application_mbox_init (EMailParserExtension *extension)
193 {
194 }
195