1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; -*- */
2 /*
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 *
5 * This library is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
18 */
19
20 #include "evolution-data-server-config.h"
21
22 #include <errno.h>
23 #include <glib/gi18n-lib.h>
24
25 #include "camel-data-wrapper.h"
26 #include "camel-debug.h"
27 #include "camel-filter-output-stream.h"
28 #include "camel-mime-filter-basic.h"
29 #include "camel-mime-filter-crlf.h"
30 #include "camel-stream-filter.h"
31 #include "camel-stream-mem.h"
32 #include "camel-stream-null.h"
33
34 #define d(x)
35
36 typedef struct _AsyncContext AsyncContext;
37
38 struct _CamelDataWrapperPrivate {
39 GMutex stream_lock;
40 GByteArray *byte_array;
41
42 CamelTransferEncoding encoding;
43
44 CamelContentType *mime_type;
45
46 guint offline : 1;
47 };
48
49 struct _AsyncContext {
50 CamelStream *stream;
51 GInputStream *input_stream;
52 GOutputStream *output_stream;
53 };
54
G_DEFINE_TYPE_WITH_PRIVATE(CamelDataWrapper,camel_data_wrapper,G_TYPE_OBJECT)55 G_DEFINE_TYPE_WITH_PRIVATE (CamelDataWrapper, camel_data_wrapper, G_TYPE_OBJECT)
56
57 static void
58 async_context_free (AsyncContext *async_context)
59 {
60 g_clear_object (&async_context->stream);
61 g_clear_object (&async_context->input_stream);
62 g_clear_object (&async_context->output_stream);
63
64 g_slice_free (AsyncContext, async_context);
65 }
66
67 static void
data_wrapper_dispose(GObject * object)68 data_wrapper_dispose (GObject *object)
69 {
70 CamelDataWrapper *data_wrapper = CAMEL_DATA_WRAPPER (object);
71
72 g_clear_pointer (&data_wrapper->priv->mime_type, camel_content_type_unref);
73
74 /* Chain up to parent's dispose() method. */
75 G_OBJECT_CLASS (camel_data_wrapper_parent_class)->dispose (object);
76 }
77
78 static void
data_wrapper_finalize(GObject * object)79 data_wrapper_finalize (GObject *object)
80 {
81 CamelDataWrapperPrivate *priv;
82
83 priv = CAMEL_DATA_WRAPPER (object)->priv;
84
85 g_mutex_clear (&priv->stream_lock);
86 g_byte_array_free (priv->byte_array, TRUE);
87
88 /* Chain up to parent's finalize() method. */
89 G_OBJECT_CLASS (camel_data_wrapper_parent_class)->finalize (object);
90 }
91
92 static void
data_wrapper_set_mime_type(CamelDataWrapper * data_wrapper,const gchar * mime_type)93 data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
94 const gchar *mime_type)
95 {
96 if (data_wrapper->priv->mime_type)
97 camel_content_type_unref (data_wrapper->priv->mime_type);
98 data_wrapper->priv->mime_type = camel_content_type_decode (mime_type);
99 }
100
101 static gchar *
data_wrapper_get_mime_type(CamelDataWrapper * data_wrapper)102 data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
103 {
104 return camel_content_type_simple (data_wrapper->priv->mime_type);
105 }
106
107 static CamelContentType *
data_wrapper_get_mime_type_field(CamelDataWrapper * data_wrapper)108 data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
109 {
110 return data_wrapper->priv->mime_type;
111 }
112
113 static void
data_wrapper_set_mime_type_field(CamelDataWrapper * data_wrapper,CamelContentType * mime_type)114 data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
115 CamelContentType *mime_type)
116 {
117 if (mime_type)
118 camel_content_type_ref (mime_type);
119 if (data_wrapper->priv->mime_type)
120 camel_content_type_unref (data_wrapper->priv->mime_type);
121 data_wrapper->priv->mime_type = mime_type;
122 }
123
124 static gboolean
data_wrapper_is_offline(CamelDataWrapper * data_wrapper)125 data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
126 {
127 return data_wrapper->priv->offline;
128 }
129
130 static gssize
data_wrapper_write_to_stream_sync(CamelDataWrapper * data_wrapper,CamelStream * stream,GCancellable * cancellable,GError ** error)131 data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper,
132 CamelStream *stream,
133 GCancellable *cancellable,
134 GError **error)
135 {
136 CamelStream *memory_stream;
137 gssize ret;
138
139 g_mutex_lock (&data_wrapper->priv->stream_lock);
140
141 /* Check for cancellation after locking. */
142 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
143 g_mutex_unlock (&data_wrapper->priv->stream_lock);
144 return -1;
145 }
146
147 memory_stream = camel_stream_mem_new ();
148
149 /* We retain ownership of the byte array. */
150 camel_stream_mem_set_byte_array (
151 CAMEL_STREAM_MEM (memory_stream),
152 data_wrapper->priv->byte_array);
153
154 ret = camel_stream_write_to_stream (
155 memory_stream, stream, cancellable, error);
156
157 g_object_unref (memory_stream);
158
159 g_mutex_unlock (&data_wrapper->priv->stream_lock);
160
161 return ret;
162 }
163
164 static gssize
data_wrapper_decode_to_stream_sync(CamelDataWrapper * data_wrapper,CamelStream * stream,GCancellable * cancellable,GError ** error)165 data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper,
166 CamelStream *stream,
167 GCancellable *cancellable,
168 GError **error)
169 {
170 CamelMimeFilter *filter;
171 CamelStream *fstream;
172 gssize ret;
173
174 fstream = camel_stream_filter_new (stream);
175
176 switch (data_wrapper->priv->encoding) {
177 case CAMEL_TRANSFER_ENCODING_BASE64:
178 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
179 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
180 g_object_unref (filter);
181 break;
182 case CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE:
183 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_QP_DEC);
184 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
185 g_object_unref (filter);
186 break;
187 case CAMEL_TRANSFER_ENCODING_UUENCODE:
188 filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_UU_DEC);
189 camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
190 g_object_unref (filter);
191 break;
192 default:
193 break;
194 }
195
196 ret = camel_data_wrapper_write_to_stream_sync (
197 data_wrapper, fstream, cancellable, error);
198
199 camel_stream_flush (fstream, NULL, NULL);
200 g_object_unref (fstream);
201
202 return ret;
203 }
204
205 static gboolean
data_wrapper_construct_from_stream_sync(CamelDataWrapper * data_wrapper,CamelStream * stream,GCancellable * cancellable,GError ** error)206 data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
207 CamelStream *stream,
208 GCancellable *cancellable,
209 GError **error)
210 {
211 CamelStream *memory_stream;
212 gssize bytes_written;
213
214 g_mutex_lock (&data_wrapper->priv->stream_lock);
215
216 /* Check for cancellation after locking. */
217 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
218 g_mutex_unlock (&data_wrapper->priv->stream_lock);
219 return FALSE;
220 }
221
222 if (G_IS_SEEKABLE (stream)) {
223 if (!g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, cancellable, error)) {
224 g_mutex_unlock (&data_wrapper->priv->stream_lock);
225 return FALSE;
226 }
227 }
228
229 /* Wipe any previous contents from our byte array. */
230 g_byte_array_set_size (data_wrapper->priv->byte_array, 0);
231
232 memory_stream = camel_stream_mem_new ();
233
234 /* We retain ownership of the byte array. */
235 camel_stream_mem_set_byte_array (
236 CAMEL_STREAM_MEM (memory_stream),
237 data_wrapper->priv->byte_array);
238
239 /* Transfer incoming contents to our byte array. */
240 bytes_written = camel_stream_write_to_stream (
241 stream, memory_stream, cancellable, error);
242
243 g_object_unref (memory_stream);
244
245 g_mutex_unlock (&data_wrapper->priv->stream_lock);
246
247 return (bytes_written >= 0);
248 }
249
250 static gssize
data_wrapper_write_to_output_stream_sync(CamelDataWrapper * data_wrapper,GOutputStream * output_stream,GCancellable * cancellable,GError ** error)251 data_wrapper_write_to_output_stream_sync (CamelDataWrapper *data_wrapper,
252 GOutputStream *output_stream,
253 GCancellable *cancellable,
254 GError **error)
255 {
256 GInputStream *input_stream;
257 gssize bytes_written;
258
259 /* XXX Should keep the internal data as a reference-counted
260 * GBytes to avoid locking while writing to the stream. */
261
262 g_mutex_lock (&data_wrapper->priv->stream_lock);
263
264 /* We retain ownership of the byte array content. */
265 input_stream = g_memory_input_stream_new_from_data (
266 data_wrapper->priv->byte_array->data,
267 data_wrapper->priv->byte_array->len,
268 (GDestroyNotify) NULL);
269
270 bytes_written = g_output_stream_splice (
271 output_stream, input_stream,
272 G_OUTPUT_STREAM_SPLICE_NONE,
273 cancellable, error);
274
275 g_object_unref (input_stream);
276
277 g_mutex_unlock (&data_wrapper->priv->stream_lock);
278
279 return bytes_written;
280 }
281
282 static gssize
data_wrapper_decode_to_output_stream_sync(CamelDataWrapper * data_wrapper,GOutputStream * output_stream,GCancellable * cancellable,GError ** error)283 data_wrapper_decode_to_output_stream_sync (CamelDataWrapper *data_wrapper,
284 GOutputStream *output_stream,
285 GCancellable *cancellable,
286 GError **error)
287 {
288 CamelMimeFilter *filter = NULL;
289 GOutputStream *filter_stream = NULL;
290 gboolean content_type_is_text;
291 gssize bytes_written;
292
293 switch (data_wrapper->priv->encoding) {
294 case CAMEL_TRANSFER_ENCODING_BASE64:
295 filter = camel_mime_filter_basic_new (
296 CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
297 filter_stream = camel_filter_output_stream_new (
298 output_stream, filter);
299 g_filter_output_stream_set_close_base_stream (
300 G_FILTER_OUTPUT_STREAM (filter_stream), FALSE);
301 g_object_unref (filter);
302 break;
303 case CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE:
304 filter = camel_mime_filter_basic_new (
305 CAMEL_MIME_FILTER_BASIC_QP_DEC);
306 filter_stream = camel_filter_output_stream_new (
307 output_stream, filter);
308 g_filter_output_stream_set_close_base_stream (
309 G_FILTER_OUTPUT_STREAM (filter_stream), FALSE);
310 g_object_unref (filter);
311 break;
312 case CAMEL_TRANSFER_ENCODING_UUENCODE:
313 filter = camel_mime_filter_basic_new (
314 CAMEL_MIME_FILTER_BASIC_UU_DEC);
315 filter_stream = camel_filter_output_stream_new (
316 output_stream, filter);
317 g_filter_output_stream_set_close_base_stream (
318 G_FILTER_OUTPUT_STREAM (filter_stream), FALSE);
319 g_object_unref (filter);
320 break;
321 default:
322 /* Write directly to the output stream. */
323 filter_stream = g_object_ref (output_stream);
324 break;
325 }
326
327 content_type_is_text =
328 camel_content_type_is (data_wrapper->priv->mime_type, "text", "*") &&
329 !camel_content_type_is (data_wrapper->priv->mime_type, "text", "pdf");
330
331 if (content_type_is_text) {
332 GOutputStream *temp_stream;
333
334 filter = camel_mime_filter_crlf_new (
335 CAMEL_MIME_FILTER_CRLF_DECODE,
336 CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
337 temp_stream = camel_filter_output_stream_new (
338 filter_stream, filter);
339 g_filter_output_stream_set_close_base_stream (
340 G_FILTER_OUTPUT_STREAM (temp_stream), FALSE);
341 g_object_unref (filter);
342
343 g_object_unref (filter_stream);
344 filter_stream = temp_stream;
345 }
346
347 bytes_written = camel_data_wrapper_write_to_output_stream_sync (
348 data_wrapper, filter_stream, cancellable, error);
349
350 g_object_unref (filter_stream);
351
352 return bytes_written;
353 }
354
355 static gboolean
data_wrapper_construct_from_input_stream_sync(CamelDataWrapper * data_wrapper,GInputStream * input_stream,GCancellable * cancellable,GError ** error)356 data_wrapper_construct_from_input_stream_sync (CamelDataWrapper *data_wrapper,
357 GInputStream *input_stream,
358 GCancellable *cancellable,
359 GError **error)
360 {
361 GOutputStream *output_stream;
362 gssize bytes_written;
363 gboolean success;
364
365 /* XXX Should keep the internal data as a reference-counted
366 * GBytes to avoid locking while reading from the stream. */
367
368 g_mutex_lock (&data_wrapper->priv->stream_lock);
369
370 /* Check for cancellation after locking. */
371 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
372 g_mutex_unlock (&data_wrapper->priv->stream_lock);
373 return FALSE;
374 }
375
376 if (G_IS_SEEKABLE (input_stream)) {
377 success = g_seekable_seek (
378 G_SEEKABLE (input_stream), 0,
379 G_SEEK_SET, cancellable, error);
380 if (!success) {
381 g_mutex_unlock (&data_wrapper->priv->stream_lock);
382 return FALSE;
383 }
384 }
385
386 output_stream = g_memory_output_stream_new_resizable ();
387
388 bytes_written = g_output_stream_splice (
389 output_stream, input_stream,
390 G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
391 cancellable, error);
392
393 success = (bytes_written >= 0);
394
395 if (success) {
396 GBytes *bytes;
397
398 bytes = g_memory_output_stream_steal_as_bytes (
399 G_MEMORY_OUTPUT_STREAM (output_stream));
400
401 g_byte_array_free (data_wrapper->priv->byte_array, TRUE);
402 data_wrapper->priv->byte_array = g_bytes_unref_to_array (bytes);
403 }
404
405 g_object_unref (output_stream);
406
407 g_mutex_unlock (&data_wrapper->priv->stream_lock);
408
409 return success;
410 }
411
412 static void
camel_data_wrapper_class_init(CamelDataWrapperClass * class)413 camel_data_wrapper_class_init (CamelDataWrapperClass *class)
414 {
415 GObjectClass *object_class;
416
417 object_class = G_OBJECT_CLASS (class);
418 object_class->dispose = data_wrapper_dispose;
419 object_class->finalize = data_wrapper_finalize;
420
421 class->set_mime_type = data_wrapper_set_mime_type;
422 class->get_mime_type = data_wrapper_get_mime_type;
423 class->get_mime_type_field = data_wrapper_get_mime_type_field;
424 class->set_mime_type_field = data_wrapper_set_mime_type_field;
425 class->is_offline = data_wrapper_is_offline;
426
427 class->write_to_stream_sync = data_wrapper_write_to_stream_sync;
428 class->decode_to_stream_sync = data_wrapper_decode_to_stream_sync;
429 class->construct_from_stream_sync = data_wrapper_construct_from_stream_sync;
430 class->write_to_output_stream_sync = data_wrapper_write_to_output_stream_sync;
431 class->decode_to_output_stream_sync = data_wrapper_decode_to_output_stream_sync;
432 class->construct_from_input_stream_sync = data_wrapper_construct_from_input_stream_sync;
433 }
434
435 static void
camel_data_wrapper_init(CamelDataWrapper * data_wrapper)436 camel_data_wrapper_init (CamelDataWrapper *data_wrapper)
437 {
438 data_wrapper->priv = camel_data_wrapper_get_instance_private (data_wrapper);
439
440 g_mutex_init (&data_wrapper->priv->stream_lock);
441 data_wrapper->priv->byte_array = g_byte_array_new ();
442
443 data_wrapper->priv->mime_type = camel_content_type_new ("application", "octet-stream");
444 data_wrapper->priv->encoding = CAMEL_TRANSFER_ENCODING_DEFAULT;
445 data_wrapper->priv->offline = FALSE;
446 }
447
448 /**
449 * camel_data_wrapper_new:
450 *
451 * Create a new #CamelDataWrapper object.
452 *
453 * Returns: a new #CamelDataWrapper object
454 **/
455 CamelDataWrapper *
camel_data_wrapper_new(void)456 camel_data_wrapper_new (void)
457 {
458 return g_object_new (CAMEL_TYPE_DATA_WRAPPER, NULL);
459 }
460
461 /**
462 * camel_data_wrapper_get_byte_array:
463 * @data_wrapper: a #CamelDataWrapper
464 *
465 * Returns the #GByteArray being used to hold the contents of @data_wrapper.
466 *
467 * Note, it's up to the caller to use this in a thread-safe manner.
468 *
469 * Returns: (transfer none): the #GByteArray for @data_wrapper
470 *
471 * Since: 3.2
472 **/
473 GByteArray *
camel_data_wrapper_get_byte_array(CamelDataWrapper * data_wrapper)474 camel_data_wrapper_get_byte_array (CamelDataWrapper *data_wrapper)
475 {
476 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
477
478 return data_wrapper->priv->byte_array;
479 }
480
481 /**
482 * camel_data_wrapper_get_encoding:
483 * @data_wrapper: a #CamelDataWrapper
484 *
485 * Returns: An encoding (#CamelTransferEncoding) of the @data_wrapper
486 *
487 * Since: 3.24
488 **/
489 CamelTransferEncoding
camel_data_wrapper_get_encoding(CamelDataWrapper * data_wrapper)490 camel_data_wrapper_get_encoding (CamelDataWrapper *data_wrapper)
491 {
492 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), CAMEL_TRANSFER_ENCODING_DEFAULT);
493
494 return data_wrapper->priv->encoding;
495 }
496
497 /**
498 * camel_data_wrapper_set_encoding:
499 * @data_wrapper: a #CamelDataWrapper
500 * @encoding: an encoding to set
501 *
502 * Sets encoding (#CamelTransferEncoding) for the @data_wrapper.
503 * It doesn't re-encode the content, if the encoding changes.
504 *
505 * Since: 3.24
506 **/
507 void
camel_data_wrapper_set_encoding(CamelDataWrapper * data_wrapper,CamelTransferEncoding encoding)508 camel_data_wrapper_set_encoding (CamelDataWrapper *data_wrapper,
509 CamelTransferEncoding encoding)
510 {
511 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
512
513 data_wrapper->priv->encoding = encoding;
514 }
515
516 /**
517 * camel_data_wrapper_set_mime_type:
518 * @data_wrapper: a #CamelDataWrapper
519 * @mime_type: a MIME type
520 *
521 * This sets the data wrapper's MIME type.
522 *
523 * It might fail, but you won't know. It will allow you to set
524 * Content-Type parameters on the data wrapper, which are meaningless.
525 * You should not be allowed to change the MIME type of a data wrapper
526 * that contains data, or at least, if you do, it should invalidate the
527 * data.
528 **/
529 void
camel_data_wrapper_set_mime_type(CamelDataWrapper * data_wrapper,const gchar * mime_type)530 camel_data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
531 const gchar *mime_type)
532 {
533 CamelDataWrapperClass *class;
534
535 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
536 g_return_if_fail (mime_type != NULL);
537
538 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
539 g_return_if_fail (class != NULL);
540 g_return_if_fail (class->set_mime_type != NULL);
541
542 class->set_mime_type (data_wrapper, mime_type);
543 }
544
545 /**
546 * camel_data_wrapper_get_mime_type:
547 * @data_wrapper: a #CamelDataWrapper
548 *
549 * Returns: the MIME type which must be freed by the caller
550 **/
551 gchar *
camel_data_wrapper_get_mime_type(CamelDataWrapper * data_wrapper)552 camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
553 {
554 CamelDataWrapperClass *class;
555
556 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
557
558 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
559 g_return_val_if_fail (class != NULL, NULL);
560 g_return_val_if_fail (class->get_mime_type != NULL, NULL);
561
562 return class->get_mime_type (data_wrapper);
563 }
564
565 /**
566 * camel_data_wrapper_get_mime_type_field:
567 * @data_wrapper: a #CamelDataWrapper
568 *
569 * Returns: (transfer none): the parsed form of the data wrapper's MIME type
570 **/
571 CamelContentType *
camel_data_wrapper_get_mime_type_field(CamelDataWrapper * data_wrapper)572 camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
573 {
574 CamelDataWrapperClass *class;
575
576 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL);
577
578 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
579 g_return_val_if_fail (class != NULL, NULL);
580 g_return_val_if_fail (class->get_mime_type_field != NULL, NULL);
581
582 return class->get_mime_type_field (data_wrapper);
583 }
584
585 /**
586 * camel_data_wrapper_set_mime_type_field:
587 * @data_wrapper: a #CamelDataWrapper
588 * @mime_type: (nullable): a #CamelContentType
589 *
590 * This sets the data wrapper's MIME type. It adds its own reference
591 * to @mime_type, if not %NULL.
592 *
593 * It suffers from the same flaws as camel_data_wrapper_set_mime_type().
594 **/
595 void
camel_data_wrapper_set_mime_type_field(CamelDataWrapper * data_wrapper,CamelContentType * mime_type)596 camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
597 CamelContentType *mime_type)
598 {
599 CamelDataWrapperClass *class;
600
601 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
602 g_return_if_fail (mime_type != NULL);
603
604 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
605 g_return_if_fail (class != NULL);
606 g_return_if_fail (class->set_mime_type_field != NULL);
607
608 class->set_mime_type_field (data_wrapper, mime_type);
609 }
610
611 /**
612 * camel_data_wrapper_take_mime_type_field:
613 * @data_wrapper: a #CamelDataWrapper
614 * @mime_type: (nullable) (transfer full): a #CamelContentType
615 *
616 * Sets mime-type filed to be @mime_type and consumes it, aka unlike
617 * camel_data_wrapper_set_mime_type_field(), this doesn't add its own
618 * reference to @mime_type.
619 *
620 * It suffers from the same flaws as camel_data_wrapper_set_mime_type().
621 *
622 * Since: 3.24
623 **/
624 void
camel_data_wrapper_take_mime_type_field(CamelDataWrapper * data_wrapper,CamelContentType * mime_type)625 camel_data_wrapper_take_mime_type_field (CamelDataWrapper *data_wrapper,
626 CamelContentType *mime_type)
627 {
628 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
629 g_return_if_fail (mime_type != NULL);
630
631 camel_data_wrapper_set_mime_type_field (data_wrapper, mime_type);
632
633 if (mime_type)
634 camel_content_type_unref (mime_type);
635 }
636
637 /**
638 * camel_data_wrapper_is_offline:
639 * @data_wrapper: a #CamelDataWrapper
640 *
641 * Returns: whether @data_wrapper is "offline" (data stored
642 * remotely) or not. Some optional code paths may choose to not
643 * operate on offline data.
644 **/
645 gboolean
camel_data_wrapper_is_offline(CamelDataWrapper * data_wrapper)646 camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
647 {
648 CamelDataWrapperClass *class;
649
650 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), TRUE);
651
652 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
653 g_return_val_if_fail (class != NULL, TRUE);
654 g_return_val_if_fail (class->is_offline != NULL, TRUE);
655
656 return class->is_offline (data_wrapper);
657 }
658
659 /**
660 * camel_data_wrapper_set_offline:
661 * @data_wrapper: a #CamelDataWrapper
662 * @offline: whether the @data_wrapper is "offline"
663 *
664 * Sets whether the @data_wrapper is "offline". It applies only to this
665 * concrete instance. See camel_data_wrapper_is_offline().
666 *
667 * Since: 3.24
668 **/
669 void
camel_data_wrapper_set_offline(CamelDataWrapper * data_wrapper,gboolean offline)670 camel_data_wrapper_set_offline (CamelDataWrapper *data_wrapper,
671 gboolean offline)
672 {
673 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
674
675 data_wrapper->priv->offline = offline;
676 }
677
678 /**
679 * camel_data_wrapper_write_to_stream_sync:
680 * @data_wrapper: a #CamelDataWrapper
681 * @stream: a #CamelStream for output
682 * @cancellable: optional #GCancellable object, or %NULL
683 * @error: return location for a #GError, or %NULL
684 *
685 * Writes the content of @data_wrapper to @stream in a machine-independent
686 * format appropriate for the data. It should be possible to construct an
687 * equivalent data wrapper object later by passing this stream to
688 * camel_data_wrapper_construct_from_stream_sync().
689 *
690 * <note>
691 * <para>
692 * This function may block even if the given output stream does not.
693 * For example, the content may have to be fetched across a network
694 * before it can be written to @stream.
695 * </para>
696 * </note>
697 *
698 * Returns: the number of bytes written, or -1 on error
699 *
700 * Since: 3.0
701 **/
702 gssize
camel_data_wrapper_write_to_stream_sync(CamelDataWrapper * data_wrapper,CamelStream * stream,GCancellable * cancellable,GError ** error)703 camel_data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper,
704 CamelStream *stream,
705 GCancellable *cancellable,
706 GError **error)
707 {
708 CamelDataWrapperClass *class;
709 gssize bytes_written;
710
711 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
712 g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
713
714 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
715 g_return_val_if_fail (class != NULL, -1);
716 g_return_val_if_fail (class->write_to_stream_sync != NULL, -1);
717
718 bytes_written = class->write_to_stream_sync (
719 data_wrapper, stream, cancellable, error);
720 CAMEL_CHECK_GERROR (
721 data_wrapper, write_to_stream_sync,
722 bytes_written >= 0, error);
723
724 return bytes_written;
725 }
726
727 /* Helper for camel_data_wrapper_write_to_stream() */
728 static void
data_wrapper_write_to_stream_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)729 data_wrapper_write_to_stream_thread (GTask *task,
730 gpointer source_object,
731 gpointer task_data,
732 GCancellable *cancellable)
733 {
734 gssize bytes_written;
735 AsyncContext *async_context;
736 GError *local_error = NULL;
737
738 async_context = (AsyncContext *) task_data;
739
740 bytes_written = camel_data_wrapper_write_to_stream_sync (
741 CAMEL_DATA_WRAPPER (source_object),
742 async_context->stream,
743 cancellable, &local_error);
744
745 if (local_error != NULL) {
746 g_task_return_error (task, local_error);
747 } else {
748 g_task_return_int (task, bytes_written);
749 }
750 }
751
752 /**
753 * camel_data_wrapper_write_to_stream:
754 * @data_wrapper: a #CamelDataWrapper
755 * @stream: a #CamelStream for writed data to be written to
756 * @io_priority: the I/O priority of the request
757 * @cancellable: optional #GCancellable object, or %NULL
758 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
759 * @user_data: data to pass to the callback function
760 *
761 * Asynchronously writes the content of @data_wrapper to @stream in a
762 * machine-independent format appropriate for the data. It should be
763 * possible to construct an equivalent data wrapper object later by
764 * passing this stream to camel_data_wrapper_construct_from_stream().
765 *
766 * When the operation is finished, @callback will be called. You can then
767 * call camel_data_wrapper_write_to_stream_finish() to get the result of
768 * the operation.
769 *
770 * Since: 3.0
771 **/
772 void
camel_data_wrapper_write_to_stream(CamelDataWrapper * data_wrapper,CamelStream * stream,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)773 camel_data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper,
774 CamelStream *stream,
775 gint io_priority,
776 GCancellable *cancellable,
777 GAsyncReadyCallback callback,
778 gpointer user_data)
779 {
780 GTask *task;
781 AsyncContext *async_context;
782
783 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
784 g_return_if_fail (CAMEL_IS_STREAM (stream));
785
786 async_context = g_slice_new0 (AsyncContext);
787 async_context->stream = g_object_ref (stream);
788
789 task = g_task_new (data_wrapper, cancellable, callback, user_data);
790 g_task_set_source_tag (task, camel_data_wrapper_write_to_stream);
791 g_task_set_priority (task, io_priority);
792
793 g_task_set_task_data (
794 task, async_context,
795 (GDestroyNotify) async_context_free);
796
797 g_task_run_in_thread (task, data_wrapper_write_to_stream_thread);
798
799 g_object_unref (task);
800 }
801
802 /**
803 * camel_data_wrapper_write_to_stream_finish:
804 * @data_wrapper: a #CamelDataWrapper
805 * @result: a #GAsyncResult
806 * @error: return location for a #GError, or %NULL
807 *
808 * Finishes the operation started with camel_data_wrapper_write_to_stream().
809 *
810 * Returns: the number of bytes written, or -1 or error
811 *
812 * Since: 3.0
813 **/
814 gssize
camel_data_wrapper_write_to_stream_finish(CamelDataWrapper * data_wrapper,GAsyncResult * result,GError ** error)815 camel_data_wrapper_write_to_stream_finish (CamelDataWrapper *data_wrapper,
816 GAsyncResult *result,
817 GError **error)
818 {
819 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
820 g_return_val_if_fail (g_task_is_valid (result, data_wrapper), -1);
821
822 g_return_val_if_fail (
823 g_async_result_is_tagged (
824 result, camel_data_wrapper_write_to_stream), -1);
825
826 return g_task_propagate_int (G_TASK (result), error);
827 }
828
829 /**
830 * camel_data_wrapper_decode_to_stream_sync:
831 * @data_wrapper: a #CamelDataWrapper
832 * @stream: a #CamelStream for decoded data to be written to
833 * @cancellable: optional #GCancellable object, or %NULL
834 * @error: return location for a #GError, or %NULL
835 *
836 * Writes the decoded data content to @stream.
837 *
838 * <note>
839 * <para>
840 * This function may block even if the given output stream does not.
841 * For example, the content may have to be fetched across a network
842 * before it can be written to @stream.
843 * </para>
844 * </note>
845 *
846 * Returns: the number of bytes written, or -1 on error
847 *
848 * Since: 3.0
849 **/
850 gssize
camel_data_wrapper_decode_to_stream_sync(CamelDataWrapper * data_wrapper,CamelStream * stream,GCancellable * cancellable,GError ** error)851 camel_data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper,
852 CamelStream *stream,
853 GCancellable *cancellable,
854 GError **error)
855 {
856 CamelDataWrapperClass *class;
857 gssize bytes_written;
858
859 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
860 g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
861
862 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
863 g_return_val_if_fail (class != NULL, -1);
864 g_return_val_if_fail (class->decode_to_stream_sync != NULL, -1);
865
866 bytes_written = class->decode_to_stream_sync (
867 data_wrapper, stream, cancellable, error);
868 CAMEL_CHECK_GERROR (
869 data_wrapper, decode_to_stream_sync,
870 bytes_written >= 0, error);
871
872 return bytes_written;
873 }
874
875 /* Helper for camel_data_wrapper_decode_to_stream() */
876 static void
data_wrapper_decode_to_stream_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)877 data_wrapper_decode_to_stream_thread (GTask *task,
878 gpointer source_object,
879 gpointer task_data,
880 GCancellable *cancellable)
881 {
882 gssize bytes_written;
883 AsyncContext *async_context;
884 GError *local_error = NULL;
885
886 async_context = (AsyncContext *) task_data;
887
888 bytes_written = camel_data_wrapper_decode_to_stream_sync (
889 CAMEL_DATA_WRAPPER (source_object),
890 async_context->stream,
891 cancellable, &local_error);
892
893 if (local_error != NULL) {
894 g_task_return_error (task, local_error);
895 } else {
896 g_task_return_int (task, bytes_written);
897 }
898 }
899
900 /**
901 * camel_data_wrapper_decode_to_stream:
902 * @data_wrapper: a #CamelDataWrapper
903 * @stream: a #CamelStream for decoded data to be written to
904 * @io_priority: the I/O priority of the request
905 * @cancellable: optional #GCancellable object, or %NULL
906 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
907 * @user_data: data to pass to the callback function
908 *
909 * Asynchronously writes the decoded data content to @stream.
910 *
911 * When the operation is finished, @callback will be called. You can then
912 * call camel_data_wrapper_decode_to_stream_finish() to get the result of
913 * the operation.
914 *
915 * Since: 3.0
916 **/
917 void
camel_data_wrapper_decode_to_stream(CamelDataWrapper * data_wrapper,CamelStream * stream,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)918 camel_data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper,
919 CamelStream *stream,
920 gint io_priority,
921 GCancellable *cancellable,
922 GAsyncReadyCallback callback,
923 gpointer user_data)
924 {
925 GTask *task;
926 AsyncContext *async_context;
927
928 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
929 g_return_if_fail (CAMEL_IS_STREAM (stream));
930
931 async_context = g_slice_new0 (AsyncContext);
932 async_context->stream = g_object_ref (stream);
933
934 task = g_task_new (data_wrapper, cancellable, callback, user_data);
935 g_task_set_source_tag (task, camel_data_wrapper_decode_to_stream);
936 g_task_set_priority (task, io_priority);
937
938 g_task_set_task_data (
939 task, async_context,
940 (GDestroyNotify) async_context_free);
941
942 g_task_run_in_thread (task, data_wrapper_decode_to_stream_thread);
943
944 g_object_unref (task);
945 }
946
947 /**
948 * camel_data_wrapper_decode_to_stream_finish:
949 * @data_wrapper: a #CamelDataWrapper
950 * @result: a #GAsyncResult
951 * @error: return location for a #GError, or %NULL
952 *
953 * Finishes the operation started with camel_data_wrapper_decode_to_stream().
954 *
955 * Returns: the number of bytes written, or -1 on error
956 *
957 * Since: 3.0
958 **/
959 gssize
camel_data_wrapper_decode_to_stream_finish(CamelDataWrapper * data_wrapper,GAsyncResult * result,GError ** error)960 camel_data_wrapper_decode_to_stream_finish (CamelDataWrapper *data_wrapper,
961 GAsyncResult *result,
962 GError **error)
963 {
964 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
965 g_return_val_if_fail (g_task_is_valid (result, data_wrapper), -1);
966
967 g_return_val_if_fail (
968 g_async_result_is_tagged (
969 result, camel_data_wrapper_decode_to_stream), -1);
970
971 return g_task_propagate_int (G_TASK (result), error);
972 }
973
974 /**
975 * camel_data_wrapper_construct_from_stream_sync:
976 * @data_wrapper: a #CamelDataWrapper
977 * @stream: an input #CamelStream
978 * @cancellable: optional #GCancellable object, or %NULL
979 * @error: return location for a #GError, or %NULL
980 *
981 * Constructs the content of @data_wrapper from the given @stream.
982 *
983 * Returns: %TRUE on success, %FALSE on error
984 *
985 * Since: 3.0
986 **/
987 gboolean
camel_data_wrapper_construct_from_stream_sync(CamelDataWrapper * data_wrapper,CamelStream * stream,GCancellable * cancellable,GError ** error)988 camel_data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
989 CamelStream *stream,
990 GCancellable *cancellable,
991 GError **error)
992 {
993 CamelDataWrapperClass *class;
994 gboolean success;
995
996 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE);
997 g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE);
998
999 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
1000 g_return_val_if_fail (class != NULL, FALSE);
1001 g_return_val_if_fail (class->construct_from_stream_sync != NULL, FALSE);
1002
1003 success = class->construct_from_stream_sync (
1004 data_wrapper, stream, cancellable, error);
1005 CAMEL_CHECK_GERROR (
1006 data_wrapper, construct_from_stream_sync, success, error);
1007
1008 return success;
1009 }
1010
1011 /* Helper for camel_data_wrapper_construct_from_stream() */
1012 static void
data_wrapper_construct_from_stream_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1013 data_wrapper_construct_from_stream_thread (GTask *task,
1014 gpointer source_object,
1015 gpointer task_data,
1016 GCancellable *cancellable)
1017 {
1018 gboolean success;
1019 AsyncContext *async_context;
1020 GError *local_error = NULL;
1021
1022 async_context = (AsyncContext *) task_data;
1023
1024 success = camel_data_wrapper_construct_from_stream_sync (
1025 CAMEL_DATA_WRAPPER (source_object),
1026 async_context->stream,
1027 cancellable, &local_error);
1028
1029 if (local_error != NULL) {
1030 g_task_return_error (task, local_error);
1031 } else {
1032 g_task_return_boolean (task, success);
1033 }
1034 }
1035
1036 /**
1037 * camel_data_wrapper_construct_from_stream:
1038 * @data_wrapper: a #CamelDataWrapper
1039 * @stream: an input #CamelStream
1040 * @io_priority: the I/O priority of the request
1041 * @cancellable: optional #GCancellable object, or %NULL
1042 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1043 * @user_data: data to pass to the callback function
1044 *
1045 * Asynchronously constructs the content of @data_wrapper from the given
1046 * @stream.
1047 *
1048 * When the operation is finished, @callback will be called. You can then
1049 * call camel_data_wrapper_construct_from_stream_finish() to get the result
1050 * of the operation.
1051 *
1052 * Since: 3.0
1053 **/
1054 void
camel_data_wrapper_construct_from_stream(CamelDataWrapper * data_wrapper,CamelStream * stream,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1055 camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
1056 CamelStream *stream,
1057 gint io_priority,
1058 GCancellable *cancellable,
1059 GAsyncReadyCallback callback,
1060 gpointer user_data)
1061 {
1062 GTask *task;
1063 AsyncContext *async_context;
1064
1065 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
1066 g_return_if_fail (CAMEL_IS_STREAM (stream));
1067
1068 async_context = g_slice_new0 (AsyncContext);
1069 async_context->stream = g_object_ref (stream);
1070
1071 task = g_task_new (data_wrapper, cancellable, callback, user_data);
1072 g_task_set_source_tag (task, camel_data_wrapper_construct_from_stream);
1073 g_task_set_priority (task, io_priority);
1074
1075 g_task_set_task_data (
1076 task, async_context,
1077 (GDestroyNotify) async_context_free);
1078
1079 g_task_run_in_thread (task, data_wrapper_construct_from_stream_thread);
1080
1081 g_object_unref (task);
1082 }
1083
1084 /**
1085 * camel_data_wrapper_construct_from_stream_finish:
1086 * @data_wrapper: a #CamelDataWrapper
1087 * @result: a #GAsyncResult
1088 * @error: return location for a #GError, or %NULL
1089 *
1090 * Finishes the operation started with
1091 * camel_data_wrapper_construct_from_stream().
1092 *
1093 * Returns: %TRUE on success, %FALSE on error
1094 *
1095 * Since: 3.0
1096 **/
1097 gboolean
camel_data_wrapper_construct_from_stream_finish(CamelDataWrapper * data_wrapper,GAsyncResult * result,GError ** error)1098 camel_data_wrapper_construct_from_stream_finish (CamelDataWrapper *data_wrapper,
1099 GAsyncResult *result,
1100 GError **error)
1101 {
1102 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE);
1103 g_return_val_if_fail (g_task_is_valid (result, data_wrapper), FALSE);
1104
1105 g_return_val_if_fail (
1106 g_async_result_is_tagged (
1107 result, camel_data_wrapper_construct_from_stream), FALSE);
1108
1109 return g_task_propagate_boolean (G_TASK (result), error);
1110 }
1111
1112 /**
1113 * camel_data_wrapper_write_to_output_stream_sync:
1114 * @data_wrapper: a #CamelDataWrapper
1115 * @output_stream: a #GOutputStream
1116 * @cancellable: optional #GCancellable object, or %NULL
1117 * @error: return location for a #GError, or %NULL
1118 *
1119 * Writes the content of @data_wrapper to @output_stream in a
1120 * machine-independent format appropriate for the data.
1121 *
1122 * <note>
1123 * <para>
1124 * This function may block even if the given output stream does not.
1125 * For example, the content may have to be fetched across a network
1126 * before it can be written to @output_stream.
1127 * </para>
1128 * </note>
1129 *
1130 * Returns: the number of bytes written, or -1 on error
1131 *
1132 * Since: 3.12
1133 **/
1134 gssize
camel_data_wrapper_write_to_output_stream_sync(CamelDataWrapper * data_wrapper,GOutputStream * output_stream,GCancellable * cancellable,GError ** error)1135 camel_data_wrapper_write_to_output_stream_sync (CamelDataWrapper *data_wrapper,
1136 GOutputStream *output_stream,
1137 GCancellable *cancellable,
1138 GError **error)
1139 {
1140 CamelDataWrapperClass *class;
1141 gssize bytes_written;
1142
1143 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
1144 g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1);
1145
1146 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
1147 g_return_val_if_fail (class != NULL, -1);
1148 g_return_val_if_fail (class->write_to_output_stream_sync != NULL, -1);
1149
1150 bytes_written = class->write_to_output_stream_sync (
1151 data_wrapper, output_stream, cancellable, error);
1152 CAMEL_CHECK_GERROR (
1153 data_wrapper, write_to_output_stream_sync,
1154 bytes_written >= 0, error);
1155
1156 if (bytes_written >= 0) {
1157 if (!g_output_stream_flush (output_stream, cancellable, error))
1158 bytes_written = -1;
1159 }
1160
1161 return bytes_written;
1162 }
1163
1164 /* Helper for camel_data_wrapper_write_to_output_stream() */
1165 static void
data_wrapper_write_to_output_stream_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1166 data_wrapper_write_to_output_stream_thread (GTask *task,
1167 gpointer source_object,
1168 gpointer task_data,
1169 GCancellable *cancellable)
1170 {
1171 gssize bytes_written;
1172 AsyncContext *async_context;
1173 GError *local_error = NULL;
1174
1175 async_context = (AsyncContext *) task_data;
1176
1177 bytes_written = camel_data_wrapper_write_to_output_stream_sync (
1178 CAMEL_DATA_WRAPPER (source_object),
1179 async_context->output_stream,
1180 cancellable, &local_error);
1181
1182 if (local_error != NULL) {
1183 g_task_return_error (task, local_error);
1184 } else {
1185 g_task_return_int (task, bytes_written);
1186 }
1187 }
1188
1189 /**
1190 * camel_data_wrapper_write_to_output_stream:
1191 * @data_wrapper: a #CamelDataWrapper
1192 * @output_stream: a #GOutputStream
1193 * @io_priority: the I/O priority of the request
1194 * @cancellable: optional #GCancellable object, or %NULL
1195 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1196 * @user_data: data to pass to the callback function
1197 *
1198 * Asynchronously writes the content of @data_wrapper to @output_stream in
1199 * a machine-independent format appropriate for the data.
1200 *
1201 * When the operation is finished, @callback will be called. You can then
1202 * call camel_data_wrapper_write_to_output_stream_finish() to get the result
1203 * of the operation.
1204 *
1205 * Since: 3.12
1206 **/
1207 void
camel_data_wrapper_write_to_output_stream(CamelDataWrapper * data_wrapper,GOutputStream * output_stream,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1208 camel_data_wrapper_write_to_output_stream (CamelDataWrapper *data_wrapper,
1209 GOutputStream *output_stream,
1210 gint io_priority,
1211 GCancellable *cancellable,
1212 GAsyncReadyCallback callback,
1213 gpointer user_data)
1214 {
1215 GTask *task;
1216 AsyncContext *async_context;
1217
1218 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
1219 g_return_if_fail (G_IS_OUTPUT_STREAM (output_stream));
1220
1221 async_context = g_slice_new0 (AsyncContext);
1222 async_context->output_stream = g_object_ref (output_stream);
1223
1224 task = g_task_new (data_wrapper, cancellable, callback, user_data);
1225 g_task_set_source_tag (task, camel_data_wrapper_write_to_output_stream);
1226 g_task_set_priority (task, io_priority);
1227
1228 g_task_set_task_data (
1229 task, async_context,
1230 (GDestroyNotify) async_context_free);
1231
1232 g_task_run_in_thread (
1233 task, data_wrapper_write_to_output_stream_thread);
1234
1235 g_object_unref (task);
1236 }
1237
1238 /**
1239 * camel_data_wrapper_write_to_output_stream_finish:
1240 * @data_wrapper: a #CamelDataWrapper
1241 * @result: a #GAsyncResult
1242 * @error: return location for a #GError, or %NULL
1243 *
1244 * Finishes the operation started with
1245 * camel_data_wrapper_write_to_output_stream().
1246 *
1247 * Returns: the number of bytes written, or -1 on error
1248 *
1249 * Since: 3.12
1250 **/
1251 gssize
camel_data_wrapper_write_to_output_stream_finish(CamelDataWrapper * data_wrapper,GAsyncResult * result,GError ** error)1252 camel_data_wrapper_write_to_output_stream_finish (CamelDataWrapper *data_wrapper,
1253 GAsyncResult *result,
1254 GError **error)
1255 {
1256 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
1257 g_return_val_if_fail (g_task_is_valid (result, data_wrapper), -1);
1258
1259 g_return_val_if_fail (
1260 g_async_result_is_tagged (
1261 result, camel_data_wrapper_write_to_output_stream), -1);
1262
1263 return g_task_propagate_int (G_TASK (result), error);
1264 }
1265
1266 /**
1267 * camel_data_wrapper_decode_to_output_stream_sync:
1268 * @data_wrapper: a #CamelDataWrapper
1269 * @output_stream: a #GOutputStream
1270 * @cancellable: optional #GCancellable object, or %NULL
1271 * @error: return location for a #GError, or %NULL
1272 *
1273 * Writes the decoded data content to @output_stream.
1274 *
1275 * <note>
1276 * <para>
1277 * This function may block even if the given output stream does not.
1278 * For example, the content may have to be fetched across a network
1279 * before it can be written to @output_stream.
1280 * </para>
1281 * </note>
1282 *
1283 * Returns: the number of bytes written, or -1 on error
1284 *
1285 * Since: 3.12
1286 **/
1287 gssize
camel_data_wrapper_decode_to_output_stream_sync(CamelDataWrapper * data_wrapper,GOutputStream * output_stream,GCancellable * cancellable,GError ** error)1288 camel_data_wrapper_decode_to_output_stream_sync (CamelDataWrapper *data_wrapper,
1289 GOutputStream *output_stream,
1290 GCancellable *cancellable,
1291 GError **error)
1292 {
1293 CamelDataWrapperClass *class;
1294 gssize bytes_written;
1295
1296 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
1297 g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1);
1298
1299 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
1300 g_return_val_if_fail (class != NULL, -1);
1301 g_return_val_if_fail (class->decode_to_output_stream_sync != NULL, -1);
1302
1303 bytes_written = class->decode_to_output_stream_sync (
1304 data_wrapper, output_stream, cancellable, error);
1305 CAMEL_CHECK_GERROR (
1306 data_wrapper, decode_to_output_stream_sync,
1307 bytes_written >= 0, error);
1308
1309 return bytes_written;
1310 }
1311
1312 /* Helper for camel_data_wrapper_decode_to_output_stream() */
1313 static void
data_wrapper_decode_to_output_stream_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1314 data_wrapper_decode_to_output_stream_thread (GTask *task,
1315 gpointer source_object,
1316 gpointer task_data,
1317 GCancellable *cancellable)
1318 {
1319 gssize bytes_written;
1320 AsyncContext *async_context;
1321 GError *local_error = NULL;
1322
1323 async_context = (AsyncContext *) task_data;
1324
1325 bytes_written = camel_data_wrapper_decode_to_output_stream_sync (
1326 CAMEL_DATA_WRAPPER (source_object),
1327 async_context->output_stream,
1328 cancellable, &local_error);
1329
1330 if (local_error != NULL) {
1331 g_task_return_error (task, local_error);
1332 } else {
1333 g_task_return_int (task, bytes_written);
1334 }
1335 }
1336
1337 /**
1338 * camel_data_wrapper_decode_to_output_stream:
1339 * @data_wrapper: a #CamelDataWrapper
1340 * @output_stream: a #GOutputStream
1341 * @io_priority: the I/O priority of the request
1342 * @cancellable: optional #GCancellable object, or %NULL
1343 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1344 * @user_data: data to pass to the callback function
1345 *
1346 * Asynchronously writes the decoded data content to @output_stream.
1347 *
1348 * When the operation is finished, @callback will be called. You can then
1349 * call camel_data_wrapper_decode_to_output_stream_finish() to get the result
1350 * of the operation.
1351 *
1352 * Since: 3.12
1353 **/
1354 void
camel_data_wrapper_decode_to_output_stream(CamelDataWrapper * data_wrapper,GOutputStream * output_stream,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1355 camel_data_wrapper_decode_to_output_stream (CamelDataWrapper *data_wrapper,
1356 GOutputStream *output_stream,
1357 gint io_priority,
1358 GCancellable *cancellable,
1359 GAsyncReadyCallback callback,
1360 gpointer user_data)
1361 {
1362 GTask *task;
1363 AsyncContext *async_context;
1364
1365 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
1366 g_return_if_fail (G_IS_OUTPUT_STREAM (output_stream));
1367
1368 async_context = g_slice_new0 (AsyncContext);
1369 async_context->output_stream = g_object_ref (output_stream);
1370
1371 task = g_task_new (data_wrapper, cancellable, callback, user_data);
1372 g_task_set_source_tag (task, camel_data_wrapper_decode_to_output_stream);
1373 g_task_set_priority (task, io_priority);
1374
1375 g_task_set_task_data (
1376 task, async_context,
1377 (GDestroyNotify) async_context_free);
1378
1379 g_task_run_in_thread (
1380 task, data_wrapper_decode_to_output_stream_thread);
1381
1382 g_object_unref (task);
1383 }
1384
1385 /**
1386 * camel_data_wrapper_decode_to_output_stream_finish:
1387 * @data_wrapper: a #CamelDataWrapper
1388 * @result: a #GAsyncResult
1389 * @error: return location for a #GError, or %NULL
1390 *
1391 * Finishes the operation started with
1392 * camel_data_wrapper_decode_to_output_stream().
1393 *
1394 * Returns: the number of bytes written, or -1 on error
1395 *
1396 * Since: 3.12
1397 **/
1398 gssize
camel_data_wrapper_decode_to_output_stream_finish(CamelDataWrapper * data_wrapper,GAsyncResult * result,GError ** error)1399 camel_data_wrapper_decode_to_output_stream_finish (CamelDataWrapper *data_wrapper,
1400 GAsyncResult *result,
1401 GError **error)
1402 {
1403 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
1404 g_return_val_if_fail (g_task_is_valid (result, data_wrapper), -1);
1405
1406 g_return_val_if_fail (
1407 g_async_result_is_tagged (
1408 result, camel_data_wrapper_decode_to_output_stream), -1);
1409
1410 return g_task_propagate_int (G_TASK (result), error);
1411 }
1412
1413 /**
1414 * camel_data_wrapper_construct_from_input_stream_sync:
1415 * @data_wrapper: a #CamelDataWrapper
1416 * @input_stream: a #GInputStream
1417 * @cancellable: optional #GCancellable object, or %NULL
1418 * @error: return location for a #GError, or %NULL
1419 *
1420 * Constructs the content of @data_wrapper from @input_stream.
1421 *
1422 * Returns: %TRUE on success, %FALSE on error
1423 *
1424 * Since: 3.12
1425 **/
1426 gboolean
camel_data_wrapper_construct_from_input_stream_sync(CamelDataWrapper * data_wrapper,GInputStream * input_stream,GCancellable * cancellable,GError ** error)1427 camel_data_wrapper_construct_from_input_stream_sync (CamelDataWrapper *data_wrapper,
1428 GInputStream *input_stream,
1429 GCancellable *cancellable,
1430 GError **error)
1431 {
1432 CamelDataWrapperClass *class;
1433 gboolean success;
1434
1435 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE);
1436 g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), FALSE);
1437
1438 class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
1439 g_return_val_if_fail (class != NULL, FALSE);
1440 g_return_val_if_fail (class->construct_from_input_stream_sync != NULL, FALSE);
1441
1442 success = class->construct_from_input_stream_sync (
1443 data_wrapper, input_stream, cancellable, error);
1444 CAMEL_CHECK_GERROR (
1445 data_wrapper, construct_from_input_stream_sync, success, error);
1446
1447 return success;
1448 }
1449
1450 /* Helper for camel_data_wrapper_construct_from_input_stream() */
1451 static void
data_wrapper_construct_from_input_stream_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1452 data_wrapper_construct_from_input_stream_thread (GTask *task,
1453 gpointer source_object,
1454 gpointer task_data,
1455 GCancellable *cancellable)
1456 {
1457 gboolean success;
1458 AsyncContext *async_context;
1459 GError *local_error = NULL;
1460
1461 async_context = (AsyncContext *) task_data;
1462
1463 success = camel_data_wrapper_construct_from_input_stream_sync (
1464 CAMEL_DATA_WRAPPER (source_object),
1465 async_context->input_stream,
1466 cancellable, &local_error);
1467
1468 if (local_error != NULL) {
1469 g_task_return_error (task, local_error);
1470 } else {
1471 g_task_return_boolean (task, success);
1472 }
1473 }
1474
1475 /**
1476 * camel_data_wrapper_construct_from_input_stream:
1477 * @data_wrapper: a #CamelDataWrapper
1478 * @input_stream: a #GInputStream
1479 * @io_priority: the I/O priority of the request
1480 * @cancellable: optional #GCancellable object, or %NULL
1481 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1482 * @user_data: data to pass to the callback function
1483 *
1484 * Asynchronously constructs the content of @data_wrapper from @input_stream.
1485 *
1486 * When the operation is finished, @callback will be called. You can then
1487 * call camel_data_wrapper_construct_from_input_stream_finish() to get the
1488 * result of the operation.
1489 *
1490 * Since: 3.12
1491 **/
1492 void
camel_data_wrapper_construct_from_input_stream(CamelDataWrapper * data_wrapper,GInputStream * input_stream,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1493 camel_data_wrapper_construct_from_input_stream (CamelDataWrapper *data_wrapper,
1494 GInputStream *input_stream,
1495 gint io_priority,
1496 GCancellable *cancellable,
1497 GAsyncReadyCallback callback,
1498 gpointer user_data)
1499 {
1500 GTask *task;
1501 AsyncContext *async_context;
1502
1503 g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
1504 g_return_if_fail (G_IS_INPUT_STREAM (input_stream));
1505
1506 async_context = g_slice_new0 (AsyncContext);
1507 async_context->input_stream = g_object_ref (input_stream);
1508
1509 task = g_task_new (data_wrapper, cancellable, callback, user_data);
1510 g_task_set_source_tag (task, camel_data_wrapper_construct_from_input_stream);
1511 g_task_set_priority (task, io_priority);
1512
1513 g_task_set_task_data (
1514 task, async_context,
1515 (GDestroyNotify) async_context_free);
1516
1517 g_task_run_in_thread (task, data_wrapper_construct_from_input_stream_thread);
1518
1519 g_object_unref (task);
1520 }
1521
1522 /**
1523 * camel_data_wrapper_construct_from_input_stream_finish:
1524 * @data_wrapper: a #CamelDataWrapper
1525 * @result: a #GAsyncResult
1526 * @error: return location for a #GError, or %NULL
1527 *
1528 * Finishes the operation started with
1529 * camel_data_wrapper_construct_from_input_stream().
1530 *
1531 * Returns: %TRUE on success, %FALSE on error
1532 *
1533 * Since: 3.12
1534 **/
1535 gboolean
camel_data_wrapper_construct_from_input_stream_finish(CamelDataWrapper * data_wrapper,GAsyncResult * result,GError ** error)1536 camel_data_wrapper_construct_from_input_stream_finish (CamelDataWrapper *data_wrapper,
1537 GAsyncResult *result,
1538 GError **error)
1539 {
1540 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE);
1541 g_return_val_if_fail (g_task_is_valid (result, data_wrapper), FALSE);
1542
1543 g_return_val_if_fail (
1544 g_async_result_is_tagged (
1545 result, camel_data_wrapper_construct_from_input_stream), FALSE);
1546
1547 return g_task_propagate_boolean (G_TASK (result), error);
1548 }
1549
1550 /**
1551 * camel_data_wrapper_calculate_size_sync:
1552 * @data_wrapper: a #CamelDataWrapper
1553 * @cancellable: a #GCancellable, or %NULL
1554 * @error: return location for a #GError, or %NULL
1555 *
1556 * Calculates size of the @data_wrapper by saving it to a null-stream
1557 * and returns how many bytes had been written. It's using
1558 * camel_data_wrapper_write_to_stream_sync() internally.
1559 *
1560 * Returns: how many bytes the @data_wrapper would use when saved,
1561 * or -1 on error.
1562 *
1563 * Since: 3.24
1564 **/
1565 gsize
camel_data_wrapper_calculate_size_sync(CamelDataWrapper * data_wrapper,GCancellable * cancellable,GError ** error)1566 camel_data_wrapper_calculate_size_sync (CamelDataWrapper *data_wrapper,
1567 GCancellable *cancellable,
1568 GError **error)
1569 {
1570 CamelStream *stream;
1571 gsize bytes_written = -1;
1572
1573 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
1574
1575 stream = camel_stream_null_new ();
1576
1577 if (camel_data_wrapper_write_to_stream_sync (data_wrapper, stream, cancellable, error))
1578 bytes_written = camel_stream_null_get_bytes_written (CAMEL_STREAM_NULL (stream));
1579
1580 g_object_unref (stream);
1581
1582 return bytes_written;
1583 }
1584
1585 /**
1586 * camel_data_wrapper_calculate_decoded_size_sync:
1587 * @data_wrapper: a #CamelDataWrapper
1588 * @cancellable: a #GCancellable, or %NULL
1589 * @error: return location for a #GError, or %NULL
1590 *
1591 * Calculates decoded size of the @data_wrapper by saving it to a null-stream
1592 * and returns how many bytes had been written. It's using
1593 * camel_data_wrapper_decode_to_stream_sync() internally.
1594 *
1595 * Returns: how many bytes the @data_wrapper would use when saved,
1596 * or -1 on error.
1597 *
1598 * Since: 3.24
1599 **/
1600 gsize
camel_data_wrapper_calculate_decoded_size_sync(CamelDataWrapper * data_wrapper,GCancellable * cancellable,GError ** error)1601 camel_data_wrapper_calculate_decoded_size_sync (CamelDataWrapper *data_wrapper,
1602 GCancellable *cancellable,
1603 GError **error)
1604 {
1605 CamelStream *stream;
1606 gsize bytes_written = -1;
1607
1608 g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
1609
1610 stream = camel_stream_null_new ();
1611
1612 if (camel_data_wrapper_decode_to_stream_sync (data_wrapper, stream, cancellable, error))
1613 bytes_written = camel_stream_null_get_bytes_written (CAMEL_STREAM_NULL (stream));
1614
1615 g_object_unref (stream);
1616
1617 return bytes_written;
1618 }
1619