Fix FSF address (Tobias Mueller, #470445)
[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 1999-2003 Ximian, Inc. (www.ximian.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
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <errno.h>
29
30 #include "camel-data-wrapper.h"
31 #include "camel-exception.h"
32 #include "camel-mime-filter-basic.h"
33 #include "camel-mime-filter-crlf.h"
34 #include "camel-private.h"
35 #include "camel-stream-filter.h"
36 #include "camel-stream.h"
37
38 #define d(x)
39
40 static CamelObjectClass *parent_class = NULL;
41
42 /* Returns the class for a CamelDataWrapper */
43 #define CDW_CLASS(so) CAMEL_DATA_WRAPPER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
44
45 static int construct_from_stream(CamelDataWrapper *, CamelStream *);
46 static ssize_t write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream);
47 static ssize_t decode_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream);
48 static void set_mime_type (CamelDataWrapper *data_wrapper, const char *mime_type);
49 static gchar *get_mime_type (CamelDataWrapper *data_wrapper);
50 static CamelContentType *get_mime_type_field (CamelDataWrapper *data_wrapper);
51 static void set_mime_type_field (CamelDataWrapper *data_wrapper, CamelContentType *mime_type);
52 static gboolean is_offline (CamelDataWrapper *data_wrapper);
53
54 static void
55 camel_data_wrapper_class_init (CamelDataWrapperClass *camel_data_wrapper_class)
56 {
57         parent_class = camel_type_get_global_classfuncs (camel_object_get_type ());
58
59         /* virtual method definition */
60         camel_data_wrapper_class->write_to_stream = write_to_stream;
61         camel_data_wrapper_class->decode_to_stream = decode_to_stream;
62         camel_data_wrapper_class->set_mime_type = set_mime_type;
63         camel_data_wrapper_class->get_mime_type = get_mime_type;
64         camel_data_wrapper_class->get_mime_type_field = get_mime_type_field;
65         camel_data_wrapper_class->set_mime_type_field = set_mime_type_field;
66         camel_data_wrapper_class->construct_from_stream = construct_from_stream;
67         camel_data_wrapper_class->is_offline = is_offline;
68 }
69
70 static void
71 camel_data_wrapper_init (gpointer object, gpointer klass)
72 {
73         CamelDataWrapper *camel_data_wrapper = CAMEL_DATA_WRAPPER (object);
74         
75         camel_data_wrapper->priv = g_malloc (sizeof (struct _CamelDataWrapperPrivate));
76         pthread_mutex_init (&camel_data_wrapper->priv->stream_lock, NULL);
77         
78         camel_data_wrapper->mime_type = camel_content_type_new ("application", "octet-stream");
79         camel_data_wrapper->encoding = CAMEL_TRANSFER_ENCODING_DEFAULT;
80         camel_data_wrapper->offline = FALSE;
81 }
82
83 static void
84 camel_data_wrapper_finalize (CamelObject *object)
85 {
86         CamelDataWrapper *camel_data_wrapper = CAMEL_DATA_WRAPPER (object);
87         
88         pthread_mutex_destroy (&camel_data_wrapper->priv->stream_lock);
89         
90         g_free (camel_data_wrapper->priv);
91         
92         if (camel_data_wrapper->mime_type)
93                 camel_content_type_unref (camel_data_wrapper->mime_type);
94         
95         if (camel_data_wrapper->stream)
96                 camel_object_unref (camel_data_wrapper->stream);
97 }
98
99 CamelType
100 camel_data_wrapper_get_type (void)
101 {
102         static CamelType type = CAMEL_INVALID_TYPE;
103         
104         if (type == CAMEL_INVALID_TYPE) {
105                 type = camel_type_register (CAMEL_OBJECT_TYPE,
106                                             "CamelDataWrapper",
107                                             sizeof (CamelDataWrapper),
108                                             sizeof (CamelDataWrapperClass),
109                                             (CamelObjectClassInitFunc) camel_data_wrapper_class_init,
110                                             NULL,
111                                             (CamelObjectInitFunc) camel_data_wrapper_init,
112                                             (CamelObjectFinalizeFunc) camel_data_wrapper_finalize);
113         }
114         
115         return type;
116 }
117
118
119 /**
120  * camel_data_wrapper_new:
121  *
122  * Create a new #CamelDataWrapper object.
123  *
124  * Returns a new #CamelDataWrapper object
125  **/
126 CamelDataWrapper *
127 camel_data_wrapper_new (void)
128 {
129         return (CamelDataWrapper *) camel_object_new (CAMEL_DATA_WRAPPER_TYPE);
130 }
131
132 static ssize_t
133 write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
134 {
135         ssize_t ret;
136         
137         if (data_wrapper->stream == NULL) {
138                 return -1;
139         }
140         
141         CAMEL_DATA_WRAPPER_LOCK (data_wrapper, stream_lock);
142         if (camel_stream_reset (data_wrapper->stream) == -1) {
143                 CAMEL_DATA_WRAPPER_UNLOCK (data_wrapper, stream_lock);
144                 return -1;
145         }
146         
147         ret = camel_stream_write_to_stream (data_wrapper->stream, stream);
148         
149         CAMEL_DATA_WRAPPER_UNLOCK (data_wrapper, stream_lock);
150         
151         return ret;
152 }
153
154
155 /**
156  * camel_data_wrapper_write_to_stream:
157  * @data_wrapper: a #CamelDataWrapper object
158  * @stream: a #CamelStream for output
159  *
160  * Writes the content of @data_wrapper to @stream in a machine-independent
161  * format appropriate for the data. It should be possible to construct an
162  * equivalent data wrapper object later by passing this stream to
163  * #camel_data_wrapper_construct_from_stream.
164  *
165  * Returns the number of bytes written, or %-1 on fail
166  **/
167 ssize_t
168 camel_data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper,
169                                     CamelStream *stream)
170 {
171         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
172         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
173
174         return CDW_CLASS (data_wrapper)->write_to_stream (data_wrapper, stream);
175 }
176
177
178 static ssize_t
179 decode_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
180 {
181         CamelMimeFilter *filter;
182         CamelStream *fstream;
183         ssize_t ret;
184         
185         fstream = (CamelStream *) camel_stream_filter_new_with_stream (stream);
186         
187         switch (data_wrapper->encoding) {
188         case CAMEL_TRANSFER_ENCODING_BASE64:
189                 filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
190                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
191                 camel_object_unref (filter);
192                 break;
193         case CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE:
194                 filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_QP_DEC);
195                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
196                 camel_object_unref (filter);
197                 break;
198         case CAMEL_TRANSFER_ENCODING_UUENCODE:
199                 filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_UU_DEC);
200                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
201                 camel_object_unref (filter);
202                 break;
203         default:
204                 break;
205         }
206         
207         if (camel_content_type_is (data_wrapper->mime_type, "text", "*")) {
208                 filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE,
209                                                      CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
210                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
211                 camel_object_unref (filter);
212         }
213         
214         ret = camel_data_wrapper_write_to_stream (data_wrapper, fstream);
215         camel_stream_flush (fstream);
216         camel_object_unref (fstream);
217         
218         return ret;
219 }
220
221
222 /**
223  * camel_data_wrapper_decode_to_stream:
224  * @data_wrapper: a #CamelDataWrapper object
225  * @stream: a #CamelStream for decoded data to be written to
226  *
227  * Writes the decoded data content to @stream.
228  *
229  * Returns the number of bytes written, or %-1 on fail
230  **/
231 ssize_t
232 camel_data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper,
233                                      CamelStream *stream)
234 {
235         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
236         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
237         
238         return CDW_CLASS (data_wrapper)->decode_to_stream (data_wrapper, stream);
239 }
240
241
242 static int
243 construct_from_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
244 {
245         if (data_wrapper->stream)
246                 camel_object_unref (data_wrapper->stream);
247         
248         data_wrapper->stream = stream;
249         camel_object_ref (stream);
250         return 0;
251 }
252
253
254 /**
255  * camel_data_wrapper_construct_from_stream:
256  * @data_wrapper: a #CamelDataWrapper object
257  * @stream: an input #CamelStream
258  *
259  * Constructs the content of @data_wrapper from the supplied @stream.
260  *
261  * Returns %0 on success or %-1 on fail
262  **/
263 int
264 camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
265                                           CamelStream *stream)
266 {
267         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
268         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
269         
270         return CDW_CLASS (data_wrapper)->construct_from_stream (data_wrapper, stream);
271 }
272
273
274 static void
275 set_mime_type (CamelDataWrapper *data_wrapper, const char *mime_type)
276 {
277         if (data_wrapper->mime_type)
278                 camel_content_type_unref (data_wrapper->mime_type);
279         data_wrapper->mime_type = camel_content_type_decode (mime_type);
280 }
281
282
283 /**
284  * camel_data_wrapper_set_mime_type:
285  * @data_wrapper: a #CamelDataWrapper object
286  * @mime_type: a MIME type
287  *
288  * This sets the data wrapper's MIME type.
289  *
290  * It might fail, but you won't know. It will allow you to set
291  * Content-Type parameters on the data wrapper, which are meaningless.
292  * You should not be allowed to change the MIME type of a data wrapper
293  * that contains data, or at least, if you do, it should invalidate the
294  * data.
295  **/
296 void
297 camel_data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
298                                   const char *mime_type)
299 {
300         g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
301         g_return_if_fail (mime_type != NULL);
302
303         CDW_CLASS (data_wrapper)->set_mime_type (data_wrapper, mime_type);
304 }
305
306 static char *
307 get_mime_type (CamelDataWrapper *data_wrapper)
308 {
309         return camel_content_type_simple (data_wrapper->mime_type);
310 }
311
312
313 /**
314  * camel_data_wrapper_get_mime_type:
315  * @data_wrapper: a #CamelDataWrapper object
316  *
317  * Returns the MIME type which must be freed by the caller
318  **/
319 char *
320 camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
321 {
322         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
323
324         return CDW_CLASS (data_wrapper)->get_mime_type (data_wrapper);
325 }
326
327
328 static CamelContentType *
329 get_mime_type_field (CamelDataWrapper *data_wrapper)
330 {
331         return data_wrapper->mime_type;
332 }
333
334
335 /**
336  * camel_data_wrapper_get_mime_type_field:
337  * @data_wrapper: a #CamelDataWrapper object
338  *
339  * Returns the parsed form of the data wrapper's MIME type
340  **/
341 CamelContentType *
342 camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
343 {
344         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
345
346         return CDW_CLASS (data_wrapper)->get_mime_type_field (data_wrapper);
347 }
348
349 static void
350 set_mime_type_field (CamelDataWrapper *data_wrapper,
351                      CamelContentType *mime_type)
352 {
353         if (mime_type)
354                 camel_content_type_ref (mime_type);
355         if (data_wrapper->mime_type)
356                 camel_content_type_unref (data_wrapper->mime_type);
357         data_wrapper->mime_type = mime_type;
358 }
359
360
361 /**
362  * camel_data_wrapper_set_mime_type_field:
363  * @data_wrapper: a #CamelDataWrapper object
364  * @mime_type: a #CamelContentType
365  *
366  * This sets the data wrapper's MIME type. It suffers from the same
367  * flaws as #camel_data_wrapper_set_mime_type.
368  **/
369 void
370 camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
371                                         CamelContentType *mime_type)
372 {
373         g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
374         g_return_if_fail (mime_type != NULL);
375
376         CDW_CLASS (data_wrapper)->set_mime_type_field (data_wrapper, mime_type);
377 }
378
379
380 static gboolean
381 is_offline (CamelDataWrapper *data_wrapper)
382 {
383         return data_wrapper->offline;
384 }
385
386
387 /**
388  * camel_data_wrapper_is_offline:
389  * @data_wrapper: a #CamelDataWrapper object
390  *
391  * Returns whether @data_wrapper is "offline" (data stored
392  * remotely) or not. Some optional code paths may choose to not
393  * operate on offline data.
394  **/
395 gboolean
396 camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
397 {
398         return CDW_CLASS (data_wrapper)->is_offline (data_wrapper);
399 }