Bug #615776 - Drop camel-private.h and offer a public alternative for locks
[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-stream-filter.h"
33 #include "camel-stream.h"
34
35 #define d(x)
36
37 struct _CamelDataWrapperPrivate {
38         GStaticMutex stream_lock;
39 };
40
41 static CamelObjectClass *parent_class = NULL;
42
43 static void
44 camel_data_wrapper_finalize (CamelObject *object)
45 {
46         CamelDataWrapper *camel_data_wrapper = CAMEL_DATA_WRAPPER (object);
47
48         g_static_mutex_free (&camel_data_wrapper->priv->stream_lock);
49
50         g_free (camel_data_wrapper->priv);
51
52         if (camel_data_wrapper->mime_type)
53                 camel_content_type_unref (camel_data_wrapper->mime_type);
54
55         if (camel_data_wrapper->stream)
56                 camel_object_unref (camel_data_wrapper->stream);
57 }
58
59 static gssize
60 data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper,
61                               CamelStream *stream)
62 {
63         gssize ret;
64
65         if (data_wrapper->stream == NULL) {
66                 return -1;
67         }
68
69         camel_data_wrapper_lock (data_wrapper, CDW_STREAM_LOCK);
70         if (camel_stream_reset (data_wrapper->stream) == -1) {
71                 camel_data_wrapper_unlock (data_wrapper, CDW_STREAM_LOCK);
72                 return -1;
73         }
74
75         ret = camel_stream_write_to_stream (data_wrapper->stream, stream);
76
77         camel_data_wrapper_unlock (data_wrapper, CDW_STREAM_LOCK);
78
79         return ret;
80 }
81
82 static gssize
83 data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper,
84                                CamelStream *stream)
85 {
86         CamelMimeFilter *filter;
87         CamelStream *fstream;
88         gssize ret;
89
90         fstream = camel_stream_filter_new (stream);
91
92         switch (data_wrapper->encoding) {
93         case CAMEL_TRANSFER_ENCODING_BASE64:
94                 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
95                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
96                 camel_object_unref (filter);
97                 break;
98         case CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE:
99                 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_QP_DEC);
100                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
101                 camel_object_unref (filter);
102                 break;
103         case CAMEL_TRANSFER_ENCODING_UUENCODE:
104                 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_UU_DEC);
105                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
106                 camel_object_unref (filter);
107                 break;
108         default:
109                 break;
110         }
111
112         if (camel_content_type_is (data_wrapper->mime_type, "text", "*")) {
113                 filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE,
114                                                      CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
115                 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
116                 camel_object_unref (filter);
117         }
118
119         ret = camel_data_wrapper_write_to_stream (data_wrapper, fstream);
120         camel_stream_flush (fstream);
121         camel_object_unref (fstream);
122
123         return ret;
124 }
125
126 static void
127 data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
128                             const gchar *mime_type)
129 {
130         if (data_wrapper->mime_type)
131                 camel_content_type_unref (data_wrapper->mime_type);
132         data_wrapper->mime_type = camel_content_type_decode (mime_type);
133 }
134
135 static gchar *
136 data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
137 {
138         return camel_content_type_simple (data_wrapper->mime_type);
139 }
140
141 static CamelContentType *
142 data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
143 {
144         return data_wrapper->mime_type;
145 }
146
147 static void
148 data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
149                                   CamelContentType *mime_type)
150 {
151         if (mime_type)
152                 camel_content_type_ref (mime_type);
153         if (data_wrapper->mime_type)
154                 camel_content_type_unref (data_wrapper->mime_type);
155         data_wrapper->mime_type = mime_type;
156 }
157
158 static gint
159 data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
160                                     CamelStream *stream)
161 {
162         if (data_wrapper->stream)
163                 camel_object_unref (data_wrapper->stream);
164
165         data_wrapper->stream = camel_object_ref (stream);
166
167         return 0;
168 }
169
170 static gboolean
171 data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
172 {
173         return data_wrapper->offline;
174 }
175
176 static void
177 camel_data_wrapper_class_init (CamelDataWrapperClass *class)
178 {
179         parent_class = camel_type_get_global_classfuncs (camel_object_get_type ());
180
181         class->write_to_stream = data_wrapper_write_to_stream;
182         class->decode_to_stream = data_wrapper_decode_to_stream;
183         class->set_mime_type = data_wrapper_set_mime_type;
184         class->get_mime_type = data_wrapper_get_mime_type;
185         class->get_mime_type_field = data_wrapper_get_mime_type_field;
186         class->set_mime_type_field = data_wrapper_set_mime_type_field;
187         class->construct_from_stream = data_wrapper_construct_from_stream;
188         class->is_offline = data_wrapper_is_offline;
189 }
190
191 static void
192 camel_data_wrapper_init (CamelDataWrapper *data_wrapper)
193 {
194         data_wrapper->priv = g_malloc (sizeof (struct _CamelDataWrapperPrivate));
195
196         g_static_mutex_init (&data_wrapper->priv->stream_lock);
197
198         data_wrapper->mime_type = camel_content_type_new (
199                 "application", "octet-stream");
200         data_wrapper->encoding = CAMEL_TRANSFER_ENCODING_DEFAULT;
201         data_wrapper->offline = FALSE;
202 }
203
204 CamelType
205 camel_data_wrapper_get_type (void)
206 {
207         static CamelType type = CAMEL_INVALID_TYPE;
208
209         if (type == CAMEL_INVALID_TYPE) {
210                 type = camel_type_register (CAMEL_TYPE_OBJECT,
211                                             "CamelDataWrapper",
212                                             sizeof (CamelDataWrapper),
213                                             sizeof (CamelDataWrapperClass),
214                                             (CamelObjectClassInitFunc) camel_data_wrapper_class_init,
215                                             NULL,
216                                             (CamelObjectInitFunc) camel_data_wrapper_init,
217                                             (CamelObjectFinalizeFunc) camel_data_wrapper_finalize);
218         }
219
220         return type;
221 }
222
223 /**
224  * camel_data_wrapper_new:
225  *
226  * Create a new #CamelDataWrapper object.
227  *
228  * Returns: a new #CamelDataWrapper object
229  **/
230 CamelDataWrapper *
231 camel_data_wrapper_new (void)
232 {
233         return (CamelDataWrapper *) camel_object_new (CAMEL_DATA_WRAPPER_TYPE);
234 }
235
236 /**
237  * camel_data_wrapper_write_to_stream:
238  * @data_wrapper: a #CamelDataWrapper object
239  * @stream: a #CamelStream for output
240  *
241  * Writes the content of @data_wrapper to @stream in a machine-independent
242  * format appropriate for the data. It should be possible to construct an
243  * equivalent data wrapper object later by passing this stream to
244  * #camel_data_wrapper_construct_from_stream.
245  *
246  * Returns: the number of bytes written, or %-1 on fail
247  **/
248 gssize
249 camel_data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper,
250                                     CamelStream *stream)
251 {
252         CamelDataWrapperClass *class;
253
254         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
255         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
256
257         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
258         g_return_val_if_fail (class->write_to_stream != NULL, -1);
259
260         return class->write_to_stream (data_wrapper, stream);
261 }
262
263 /**
264  * camel_data_wrapper_decode_to_stream:
265  * @data_wrapper: a #CamelDataWrapper object
266  * @stream: a #CamelStream for decoded data to be written to
267  *
268  * Writes the decoded data content to @stream.
269  *
270  * Returns: the number of bytes written, or %-1 on fail
271  **/
272 gssize
273 camel_data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper,
274                                      CamelStream *stream)
275 {
276         CamelDataWrapperClass *class;
277
278         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
279         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
280
281         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
282         g_return_val_if_fail (class->decode_to_stream != NULL, -1);
283
284         return class->decode_to_stream (data_wrapper, stream);
285 }
286
287 /**
288  * camel_data_wrapper_construct_from_stream:
289  * @data_wrapper: a #CamelDataWrapper object
290  * @stream: an input #CamelStream
291  *
292  * Constructs the content of @data_wrapper from the supplied @stream.
293  *
294  * Returns: %0 on success or %-1 on fail
295  **/
296 gint
297 camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
298                                           CamelStream *stream)
299 {
300         CamelDataWrapperClass *class;
301
302         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
303         g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
304
305         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
306         g_return_val_if_fail (class->construct_from_stream != NULL, -1);
307
308         return class->construct_from_stream (data_wrapper, stream);
309 }
310
311 /**
312  * camel_data_wrapper_set_mime_type:
313  * @data_wrapper: a #CamelDataWrapper object
314  * @mime_type: a MIME type
315  *
316  * This sets the data wrapper's MIME type.
317  *
318  * It might fail, but you won't know. It will allow you to set
319  * Content-Type parameters on the data wrapper, which are meaningless.
320  * You should not be allowed to change the MIME type of a data wrapper
321  * that contains data, or at least, if you do, it should invalidate the
322  * data.
323  **/
324 void
325 camel_data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
326                                   const gchar *mime_type)
327 {
328         CamelDataWrapperClass *class;
329
330         g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
331         g_return_if_fail (mime_type != NULL);
332
333         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
334         g_return_if_fail (class->set_mime_type);
335
336         class->set_mime_type (data_wrapper, mime_type);
337 }
338
339 /**
340  * camel_data_wrapper_get_mime_type:
341  * @data_wrapper: a #CamelDataWrapper object
342  *
343  * Returns: the MIME type which must be freed by the caller
344  **/
345 gchar *
346 camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
347 {
348         CamelDataWrapperClass *class;
349
350         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
351
352         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
353         g_return_val_if_fail (class->get_mime_type != NULL, NULL);
354
355         return class->get_mime_type (data_wrapper);
356 }
357
358 /**
359  * camel_data_wrapper_get_mime_type_field:
360  * @data_wrapper: a #CamelDataWrapper object
361  *
362  * Returns: the parsed form of the data wrapper's MIME type
363  **/
364 CamelContentType *
365 camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
366 {
367         CamelDataWrapperClass *class;
368
369         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
370
371         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
372         g_return_val_if_fail (class->get_mime_type_field != NULL, NULL);
373
374         return class->get_mime_type_field (data_wrapper);
375 }
376
377 /**
378  * camel_data_wrapper_set_mime_type_field:
379  * @data_wrapper: a #CamelDataWrapper object
380  * @mime_type: a #CamelContentType
381  *
382  * This sets the data wrapper's MIME type. It suffers from the same
383  * flaws as #camel_data_wrapper_set_mime_type.
384  **/
385 void
386 camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
387                                         CamelContentType *mime_type)
388 {
389         CamelDataWrapperClass *class;
390
391         g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
392         g_return_if_fail (mime_type != NULL);
393
394         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
395         g_return_if_fail (class->set_mime_type_field != NULL);
396
397         class->set_mime_type_field (data_wrapper, mime_type);
398 }
399
400 /**
401  * camel_data_wrapper_is_offline:
402  * @data_wrapper: a #CamelDataWrapper object
403  *
404  * Returns: whether @data_wrapper is "offline" (data stored
405  * remotely) or not. Some optional code paths may choose to not
406  * operate on offline data.
407  **/
408 gboolean
409 camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
410 {
411         CamelDataWrapperClass *class;
412
413         g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), TRUE);
414
415         class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
416         g_return_val_if_fail (class->is_offline != NULL, TRUE);
417
418         return class->is_offline (data_wrapper);
419 }
420
421 /**
422  * camel_data_wrapper_lock:
423  * @data_wrapper: a #CamelDataWrapper
424  * @lock: lock type to lock
425  *
426  * Locks #data_wrapper's #lock. Unlock it with camel_data_wrapper_unlock().
427  *
428  * Since: 2.31.1
429  **/
430 void
431 camel_data_wrapper_lock (CamelDataWrapper *data_wrapper, CamelDataWrapperLock lock)
432 {
433         g_return_if_fail (data_wrapper != NULL);
434         g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
435         g_return_if_fail (data_wrapper->priv != NULL);
436
437         switch (lock) {
438         case CDW_STREAM_LOCK:
439                 g_static_mutex_lock (&data_wrapper->priv->stream_lock);
440                 break;
441         default:
442                 g_return_if_reached ();
443         }
444 }
445
446 /**
447  * camel_data_wrapper_unlock:
448  * @data_wrapper: a #CamelDataWrapper
449  * @lock: lock type to unlock
450  *
451  * Unlocks #data_wrapper's #lock, previously locked with camel_data_wrapper_lock().
452  *
453  * Since: 2.31.1
454  **/
455 void
456 camel_data_wrapper_unlock (CamelDataWrapper *data_wrapper, CamelDataWrapperLock lock)
457 {
458         g_return_if_fail (data_wrapper != NULL);
459         g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
460         g_return_if_fail (data_wrapper->priv != NULL);
461
462         switch (lock) {
463         case CDW_STREAM_LOCK:
464                 g_static_mutex_unlock (&data_wrapper->priv->stream_lock);
465                 break;
466         default:
467                 g_return_if_reached ();
468         }
469 }