f13ff9c0ed74f5802321e6a9761bf755947cd138
[platform/upstream/evolution-data-server.git] / camel / camel-data-wrapper.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; -*- */
2 /*
3  *
4  * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
5  *
6  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2 of the GNU Lesser General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20  * USA
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28
29 #include "camel-data-wrapper.h"
30 #include "camel-mime-filter-basic.h"
31 #include "camel-mime-filter-crlf.h"
32 #include "camel-private.h"
33 #include "camel-stream-filter.h"
34 #include "camel-stream.h"
35
36 #define d(x)
37
38 static CamelObjectClass *parent_class = NULL;
39
40 static void
41 camel_data_wrapper_finalize (CamelObject *object)
42 {
43         CamelDataWrapper *camel_data_wrapper = CAMEL_DATA_WRAPPER (object);
44
45         g_static_mutex_free (&camel_data_wrapper->priv->stream_lock);
46
47         g_free (camel_data_wrapper->priv);
48
49         if (camel_data_wrapper->mime_type)
50                 camel_content_type_unref (camel_data_wrapper->mime_type);
51
52         if (camel_data_wrapper->stream)
53                 camel_object_unref (camel_data_wrapper->stream);
54 }
55
56 static gssize
57 data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper,
58                               CamelStream *stream)
59 {
60         gssize ret;
61
62         if (data_wrapper->stream == NULL) {
63                 return -1;
64         }
65
66         CAMEL_DATA_WRAPPER_LOCK (data_wrapper, stream_lock);
67         if (camel_stream_reset (data_wrapper->stream) == -1) {
68                 CAMEL_DATA_WRAPPER_UNLOCK (data_wrapper, stream_lock);
69                 return -1;
70         }
71
72         ret = camel_stream_write_to_stream (data_wrapper->stream, stream);
73
74         CAMEL_DATA_WRAPPER_UNLOCK (data_wrapper, stream_lock);
75
76         return ret;
77 }
78
79 static gssize
80 data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper,
81                                CamelStream *stream)
82 {
83         CamelMimeFilter *filter;
84         CamelStream *fstream;
85         gssize ret;
86
87         fstream = camel_stream_filter_new (stream);
88
89         switch (data_wrapper->encoding) {
90         case CAMEL_TRANSFER_ENCODING_BASE64:
91                 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
92                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
93                 camel_object_unref (filter);
94                 break;
95         case CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE:
96                 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_QP_DEC);
97                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
98                 camel_object_unref (filter);
99                 break;
100         case CAMEL_TRANSFER_ENCODING_UUENCODE:
101                 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_UU_DEC);
102                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
103                 camel_object_unref (filter);
104                 break;
105         default:
106                 break;
107         }
108
109         if (camel_content_type_is (data_wrapper->mime_type, "text", "*")) {
110                 filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE,
111                                                      CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
112                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
113                 camel_object_unref (filter);
114         }
115
116         ret = camel_data_wrapper_write_to_stream (data_wrapper, fstream);
117         camel_stream_flush (fstream);
118         camel_object_unref (fstream);
119
120         return ret;
121 }
122
123 static void
124 data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
125                             const gchar *mime_type)
126 {
127         if (data_wrapper->mime_type)
128                 camel_content_type_unref (data_wrapper->mime_type);
129         data_wrapper->mime_type = camel_content_type_decode (mime_type);
130 }
131
132 static gchar *
133 data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
134 {
135         return camel_content_type_simple (data_wrapper->mime_type);
136 }
137
138 static CamelContentType *
139 data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
140 {
141         return data_wrapper->mime_type;
142 }
143
144 static void
145 data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
146                                   CamelContentType *mime_type)
147 {
148         if (mime_type)
149                 camel_content_type_ref (mime_type);
150         if (data_wrapper->mime_type)
151                 camel_content_type_unref (data_wrapper->mime_type);
152         data_wrapper->mime_type = mime_type;
153 }
154
155 static gint
156 data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
157                                     CamelStream *stream)
158 {
159         if (data_wrapper->stream)
160                 camel_object_unref (data_wrapper->stream);
161
162         data_wrapper->stream = camel_object_ref (stream);
163
164         return 0;
165 }
166
167 static gboolean
168 data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
169 {
170         return data_wrapper->offline;
171 }
172
173 static void
174 camel_data_wrapper_class_init (CamelDataWrapperClass *class)
175 {
176         parent_class = camel_type_get_global_classfuncs (camel_object_get_type ());
177
178         class->write_to_stream = data_wrapper_write_to_stream;
179         class->decode_to_stream = data_wrapper_decode_to_stream;
180         class->set_mime_type = data_wrapper_set_mime_type;
181         class->get_mime_type = data_wrapper_get_mime_type;
182         class->get_mime_type_field = data_wrapper_get_mime_type_field;
183         class->set_mime_type_field = data_wrapper_set_mime_type_field;
184         class->construct_from_stream = data_wrapper_construct_from_stream;
185         class->is_offline = data_wrapper_is_offline;
186 }
187
188 static void
189 camel_data_wrapper_init (CamelDataWrapper *data_wrapper)
190 {
191         data_wrapper->priv = g_malloc (sizeof (struct _CamelDataWrapperPrivate));
192
193         g_static_mutex_init (&data_wrapper->priv->stream_lock);
194
195         data_wrapper->mime_type = camel_content_type_new (
196                 "application", "octet-stream");
197         data_wrapper->encoding = CAMEL_TRANSFER_ENCODING_DEFAULT;
198         data_wrapper->offline = FALSE;
199 }
200
201 CamelType
202 camel_data_wrapper_get_type (void)
203 {
204         static CamelType type = CAMEL_INVALID_TYPE;
205
206         if (type == CAMEL_INVALID_TYPE) {
207                 type = camel_type_register (CAMEL_TYPE_OBJECT,
208                                             "CamelDataWrapper",
209                                             sizeof (CamelDataWrapper),
210                                             sizeof (CamelDataWrapperClass),
211                                             (CamelObjectClassInitFunc) camel_data_wrapper_class_init,
212                                             NULL,
213                                             (CamelObjectInitFunc) camel_data_wrapper_init,
214                                             (CamelObjectFinalizeFunc) camel_data_wrapper_finalize);
215         }
216
217         return type;
218 }
219
220 /**
221  * camel_data_wrapper_new:
222  *
223  * Create a new #CamelDataWrapper object.
224  *
225  * Returns: a new #CamelDataWrapper object
226  **/
227 CamelDataWrapper *
228 camel_data_wrapper_new (void)
229 {
230         return (CamelDataWrapper *) camel_object_new (CAMEL_DATA_WRAPPER_TYPE);
231 }
232
233 /**
234  * camel_data_wrapper_write_to_stream:
235  * @data_wrapper: a #CamelDataWrapper object
236  * @stream: a #CamelStream for output
237  *
238  * Writes the content of @data_wrapper to @stream in a machine-independent
239  * format appropriate for the data. It should be possible to construct an
240  * equivalent data wrapper object later by passing this stream to
241  * #camel_data_wrapper_construct_from_stream.
242  *
243  * Returns: the number of bytes written, or %-1 on fail
244  **/
245 gssize
246 camel_data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper,
247                                     CamelStream *stream)
248 {
249         CamelDataWrapperClass *class;
250
251         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
252         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
253
254         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
255         g_return_val_if_fail (class->write_to_stream != NULL, -1);
256
257         return class->write_to_stream (data_wrapper, stream);
258 }
259
260 /**
261  * camel_data_wrapper_decode_to_stream:
262  * @data_wrapper: a #CamelDataWrapper object
263  * @stream: a #CamelStream for decoded data to be written to
264  *
265  * Writes the decoded data content to @stream.
266  *
267  * Returns: the number of bytes written, or %-1 on fail
268  **/
269 gssize
270 camel_data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper,
271                                      CamelStream *stream)
272 {
273         CamelDataWrapperClass *class;
274
275         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
276         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
277
278         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
279         g_return_val_if_fail (class->decode_to_stream != NULL, -1);
280
281         return class->decode_to_stream (data_wrapper, stream);
282 }
283
284 /**
285  * camel_data_wrapper_construct_from_stream:
286  * @data_wrapper: a #CamelDataWrapper object
287  * @stream: an input #CamelStream
288  *
289  * Constructs the content of @data_wrapper from the supplied @stream.
290  *
291  * Returns: %0 on success or %-1 on fail
292  **/
293 gint
294 camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
295                                           CamelStream *stream)
296 {
297         CamelDataWrapperClass *class;
298
299         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
300         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
301
302         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
303         g_return_val_if_fail (class->construct_from_stream != NULL, -1);
304
305         return class->construct_from_stream (data_wrapper, stream);
306 }
307
308 /**
309  * camel_data_wrapper_set_mime_type:
310  * @data_wrapper: a #CamelDataWrapper object
311  * @mime_type: a MIME type
312  *
313  * This sets the data wrapper's MIME type.
314  *
315  * It might fail, but you won't know. It will allow you to set
316  * Content-Type parameters on the data wrapper, which are meaningless.
317  * You should not be allowed to change the MIME type of a data wrapper
318  * that contains data, or at least, if you do, it should invalidate the
319  * data.
320  **/
321 void
322 camel_data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
323                                   const gchar *mime_type)
324 {
325         CamelDataWrapperClass *class;
326
327         g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
328         g_return_if_fail (mime_type != NULL);
329
330         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
331         g_return_if_fail (class->set_mime_type);
332
333         class->set_mime_type (data_wrapper, mime_type);
334 }
335
336 /**
337  * camel_data_wrapper_get_mime_type:
338  * @data_wrapper: a #CamelDataWrapper object
339  *
340  * Returns: the MIME type which must be freed by the caller
341  **/
342 gchar *
343 camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
344 {
345         CamelDataWrapperClass *class;
346
347         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
348
349         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
350         g_return_val_if_fail (class->get_mime_type != NULL, NULL);
351
352         return class->get_mime_type (data_wrapper);
353 }
354
355 /**
356  * camel_data_wrapper_get_mime_type_field:
357  * @data_wrapper: a #CamelDataWrapper object
358  *
359  * Returns: the parsed form of the data wrapper's MIME type
360  **/
361 CamelContentType *
362 camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
363 {
364         CamelDataWrapperClass *class;
365
366         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
367
368         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
369         g_return_val_if_fail (class->get_mime_type_field != NULL, NULL);
370
371         return class->get_mime_type_field (data_wrapper);
372 }
373
374 /**
375  * camel_data_wrapper_set_mime_type_field:
376  * @data_wrapper: a #CamelDataWrapper object
377  * @mime_type: a #CamelContentType
378  *
379  * This sets the data wrapper's MIME type. It suffers from the same
380  * flaws as #camel_data_wrapper_set_mime_type.
381  **/
382 void
383 camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
384                                         CamelContentType *mime_type)
385 {
386         CamelDataWrapperClass *class;
387
388         g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
389         g_return_if_fail (mime_type != NULL);
390
391         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
392         g_return_if_fail (class->set_mime_type_field != NULL);
393
394         class->set_mime_type_field (data_wrapper, mime_type);
395 }
396
397 /**
398  * camel_data_wrapper_is_offline:
399  * @data_wrapper: a #CamelDataWrapper object
400  *
401  * Returns: whether @data_wrapper is "offline" (data stored
402  * remotely) or not. Some optional code paths may choose to not
403  * operate on offline data.
404  **/
405 gboolean
406 camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
407 {
408         CamelDataWrapperClass *class;
409
410         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), TRUE);
411
412         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
413         g_return_val_if_fail (class->is_offline != NULL, TRUE);
414
415         return class->is_offline (data_wrapper);
416 }