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