Extending test-client-custom-summary to try e_book_client_get_contacts_uids()
[platform/upstream/evolution-data-server.git] / camel / camel-mime-part-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */
2 /* camel-mime-part-utils : Utility for mime parsing and so on
3  *
4  * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
5  *          Michael Zucchi <notzed@ximian.com>
6  *          Jeffrey Stedfast <fejj@ximian.com>
7  *
8  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU Lesser General Public
12  * License as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22  * USA
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34
35 #include "camel-charset-map.h"
36 #include "camel-html-parser.h"
37 #include "camel-mime-filter-basic.h"
38 #include "camel-mime-filter-charset.h"
39 #include "camel-mime-filter-crlf.h"
40 #include "camel-mime-filter-save.h"
41 #include "camel-mime-message.h"
42 #include "camel-mime-part-utils.h"
43 #include "camel-multipart-encrypted.h"
44 #include "camel-multipart-signed.h"
45 #include "camel-multipart.h"
46 #include "camel-stream-filter.h"
47 #include "camel-stream-fs.h"
48 #include "camel-stream-mem.h"
49 #include "camel-stream-buffer.h"
50 #include "camel-utf8.h"
51
52 #define d(x) /* (printf("%s(%d): ", __FILE__, __LINE__),(x)) */
53
54 /* simple data wrapper */
55 static gboolean
56 simple_data_wrapper_construct_from_parser (CamelDataWrapper *dw,
57                                            CamelMimeParser *mp,
58                                            GCancellable *cancellable,
59                                            GError **error)
60 {
61         gchar *buf;
62         GByteArray *buffer;
63         CamelStream *mem;
64         gsize len;
65         gboolean success;
66
67         d (printf ("simple_data_wrapper_construct_from_parser()\n"));
68
69         /* read in the entire content */
70         buffer = g_byte_array_new ();
71         while (camel_mime_parser_step (mp, &buf, &len) != CAMEL_MIME_PARSER_STATE_BODY_END) {
72                 d (printf ("appending o/p data: %d: %.*s\n", len, len, buf));
73                 g_byte_array_append (buffer, (guint8 *) buf, len);
74         }
75
76         d (printf ("message part kept in memory!\n"));
77
78         mem = camel_stream_mem_new_with_byte_array (buffer);
79         success = camel_data_wrapper_construct_from_stream_sync (
80                 dw, mem, cancellable, error);
81         g_object_unref (mem);
82
83         return success;
84 }
85
86 /**
87  * camel_mime_part_construct_content_from_parser:
88  *
89  * Since: 2.24
90  **/
91 gboolean
92 camel_mime_part_construct_content_from_parser (CamelMimePart *dw,
93                                                CamelMimeParser *mp,
94                                                GCancellable *cancellable,
95                                                GError **error)
96 {
97         CamelDataWrapper *content = NULL;
98         CamelContentType *ct;
99         gchar *encoding;
100         gboolean success = TRUE;
101
102         g_return_val_if_fail (CAMEL_IS_MIME_PART (dw), FALSE);
103
104         ct = camel_mime_parser_content_type (mp);
105
106         encoding = camel_content_transfer_encoding_decode (camel_mime_parser_header (mp, "Content-Transfer-Encoding", NULL));
107
108         switch (camel_mime_parser_state (mp)) {
109         case CAMEL_MIME_PARSER_STATE_HEADER:
110                 d (printf ("Creating body part\n"));
111                 /* multipart/signed is some type that we must treat as binary data. */
112                 if (camel_content_type_is (ct, "multipart", "signed")) {
113                         content = (CamelDataWrapper *) camel_multipart_signed_new ();
114                         camel_multipart_construct_from_parser ((CamelMultipart *) content, mp);
115                 } else {
116                         content = camel_data_wrapper_new ();
117                         success = simple_data_wrapper_construct_from_parser (
118                                 content, mp, cancellable, error);
119                 }
120                 break;
121         case CAMEL_MIME_PARSER_STATE_MESSAGE:
122                 d (printf ("Creating message part\n"));
123                 content = (CamelDataWrapper *) camel_mime_message_new ();
124                 success = camel_mime_part_construct_from_parser_sync (
125                         (CamelMimePart *) content, mp, cancellable, error);
126                 break;
127         case CAMEL_MIME_PARSER_STATE_MULTIPART:
128                 d (printf ("Creating multi-part\n"));
129                 if (camel_content_type_is (ct, "multipart", "encrypted"))
130                         content = (CamelDataWrapper *) camel_multipart_encrypted_new ();
131                 else if (camel_content_type_is (ct, "multipart", "signed"))
132                         content = (CamelDataWrapper *) camel_multipart_signed_new ();
133                 else
134                         content = (CamelDataWrapper *) camel_multipart_new ();
135
136                 camel_multipart_construct_from_parser ((CamelMultipart *) content, mp);
137                 d (printf ("Created multi-part\n"));
138                 break;
139         default:
140                 g_warning ("Invalid state encountered???: %u", camel_mime_parser_state (mp));
141         }
142
143         if (content) {
144                 if (encoding)
145                         content->encoding = camel_transfer_encoding_from_string (encoding);
146
147                 /* would you believe you have to set this BEFORE you set the content object???  oh my god !!!! */
148                 camel_data_wrapper_set_mime_type_field (content, camel_mime_part_get_content_type (dw));
149                 camel_medium_set_content ((CamelMedium *) dw, content);
150                 g_object_unref (content);
151         }
152
153         g_free (encoding);
154
155         return success;
156 }
157
158 /**
159  * camel_mime_message_build_preview:
160  *
161  * <note>
162  *   <para>
163  *     This function blocks like crazy.
164  *   </para>
165  * </note>
166  *
167  * Since: 2.28
168  **/
169 gboolean
170 camel_mime_message_build_preview (CamelMimePart *msg,
171                                   CamelMessageInfo *info)
172 {
173         CamelDataWrapper *dw;
174         gboolean got_plain = FALSE;
175
176         dw = camel_medium_get_content ((CamelMedium *) msg);
177         if (camel_content_type_is (dw->mime_type, "multipart", "*")) {
178                 gint i, nparts;
179                 CamelMultipart *mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) msg);
180
181                 if (!CAMEL_IS_MULTIPART (mp))
182                         g_assert (0);
183                 nparts = camel_multipart_get_number (mp);
184                 for (i = 0; i < nparts && !got_plain; i++) {
185                         CamelMimePart *part = camel_multipart_get_part (mp, i);
186                         got_plain = camel_mime_message_build_preview (part, info);
187                 }
188
189         } else if (camel_content_type_is (dw->mime_type, "text", "*") &&
190                 /*    !camel_content_type_is (dw->mime_type, "text", "html") && */
191                     !camel_content_type_is (dw->mime_type, "text", "calendar")) {
192                 CamelStream *mstream, *bstream;
193
194                 /* FIXME Pass a GCancellable and GError here. */
195                 mstream = camel_stream_mem_new ();
196                 if (camel_data_wrapper_decode_to_stream_sync (dw, mstream, NULL, NULL) > 0) {
197                         gchar *line = NULL;
198                         GString *str = g_string_new (NULL);
199
200                         g_seekable_seek (
201                                 G_SEEKABLE (mstream), 0,
202                                 G_SEEK_SET, NULL, NULL);
203
204                         bstream = camel_stream_buffer_new (mstream, CAMEL_STREAM_BUFFER_READ | CAMEL_STREAM_BUFFER_BUFFER);
205
206                         /* We should fetch just 200 unquoted lines. */
207                         while ((line = camel_stream_buffer_read_line ((CamelStreamBuffer *) bstream, NULL, NULL)) && str->len < 200) {
208                                 gchar *tmp = line;
209
210                                 if (*line == '>' || strstr (line, "wrote:")) {
211                                         g_free (tmp);
212                                         continue;
213                                 }
214                                 if (g_str_has_prefix (line, "--")) {
215                                         g_free (tmp);
216                                         line = NULL;
217                                         break;
218                                 }
219                                 while (*line && ((*line == ' ') || *line == '\t'))
220                                         line++;
221                                 if (*line == '\0' || *line == '\n') {
222                                         g_free (tmp);
223                                         continue;
224                                 }
225
226                                 g_string_append (str, " ");
227                                 g_string_append (str, line);
228                                 g_free (tmp);
229                                 line = NULL;
230                         }
231                         if (str->len > 100) {
232                                 g_string_insert (str, 100, "\n");
233                         }
234                         /* We don't mark dirty, as we don't store these */
235                         ((CamelMessageInfoBase *) info)->preview = camel_utf8_make_valid (str->str);
236                         g_string_free (str, TRUE);
237
238                         g_object_unref (bstream);
239                 }
240                 g_object_unref (mstream);
241                 return TRUE;
242         }
243
244         return got_plain;
245 }