/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; -*- */ /* * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * * This library is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . * * Authors: Bertrand Guiheneuf */ #include "evolution-data-server-config.h" #include #include #include "camel-data-wrapper.h" #include "camel-debug.h" #include "camel-filter-output-stream.h" #include "camel-mime-filter-basic.h" #include "camel-mime-filter-crlf.h" #include "camel-stream-filter.h" #include "camel-stream-mem.h" #include "camel-stream-null.h" #define d(x) typedef struct _AsyncContext AsyncContext; struct _CamelDataWrapperPrivate { GMutex stream_lock; GByteArray *byte_array; CamelTransferEncoding encoding; CamelContentType *mime_type; guint offline : 1; }; struct _AsyncContext { CamelStream *stream; GInputStream *input_stream; GOutputStream *output_stream; }; G_DEFINE_TYPE_WITH_PRIVATE (CamelDataWrapper, camel_data_wrapper, G_TYPE_OBJECT) static void async_context_free (AsyncContext *async_context) { g_clear_object (&async_context->stream); g_clear_object (&async_context->input_stream); g_clear_object (&async_context->output_stream); g_slice_free (AsyncContext, async_context); } static void data_wrapper_dispose (GObject *object) { CamelDataWrapper *data_wrapper = CAMEL_DATA_WRAPPER (object); g_clear_pointer (&data_wrapper->priv->mime_type, camel_content_type_unref); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (camel_data_wrapper_parent_class)->dispose (object); } static void data_wrapper_finalize (GObject *object) { CamelDataWrapperPrivate *priv; priv = CAMEL_DATA_WRAPPER (object)->priv; g_mutex_clear (&priv->stream_lock); g_byte_array_free (priv->byte_array, TRUE); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (camel_data_wrapper_parent_class)->finalize (object); } static void data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper, const gchar *mime_type) { if (data_wrapper->priv->mime_type) camel_content_type_unref (data_wrapper->priv->mime_type); data_wrapper->priv->mime_type = camel_content_type_decode (mime_type); } static gchar * data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper) { return camel_content_type_simple (data_wrapper->priv->mime_type); } static CamelContentType * data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper) { return data_wrapper->priv->mime_type; } static void data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper, CamelContentType *mime_type) { if (mime_type) camel_content_type_ref (mime_type); if (data_wrapper->priv->mime_type) camel_content_type_unref (data_wrapper->priv->mime_type); data_wrapper->priv->mime_type = mime_type; } static gboolean data_wrapper_is_offline (CamelDataWrapper *data_wrapper) { return data_wrapper->priv->offline; } static gssize data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelStream *memory_stream; gssize ret; g_mutex_lock (&data_wrapper->priv->stream_lock); /* Check for cancellation after locking. */ if (g_cancellable_set_error_if_cancelled (cancellable, error)) { g_mutex_unlock (&data_wrapper->priv->stream_lock); return -1; } memory_stream = camel_stream_mem_new (); /* We retain ownership of the byte array. */ camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (memory_stream), data_wrapper->priv->byte_array); ret = camel_stream_write_to_stream ( memory_stream, stream, cancellable, error); g_object_unref (memory_stream); g_mutex_unlock (&data_wrapper->priv->stream_lock); return ret; } static gssize data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelMimeFilter *filter; CamelStream *fstream; gssize ret; fstream = camel_stream_filter_new (stream); switch (data_wrapper->priv->encoding) { case CAMEL_TRANSFER_ENCODING_BASE64: filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_BASE64_DEC); camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter); g_object_unref (filter); break; case CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE: filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_QP_DEC); camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter); g_object_unref (filter); break; case CAMEL_TRANSFER_ENCODING_UUENCODE: filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_UU_DEC); camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter); g_object_unref (filter); break; default: break; } ret = camel_data_wrapper_write_to_stream_sync ( data_wrapper, fstream, cancellable, error); camel_stream_flush (fstream, NULL, NULL); g_object_unref (fstream); return ret; } static gboolean data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelStream *memory_stream; gssize bytes_written; g_mutex_lock (&data_wrapper->priv->stream_lock); /* Check for cancellation after locking. */ if (g_cancellable_set_error_if_cancelled (cancellable, error)) { g_mutex_unlock (&data_wrapper->priv->stream_lock); return FALSE; } if (G_IS_SEEKABLE (stream)) { if (!g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, cancellable, error)) { g_mutex_unlock (&data_wrapper->priv->stream_lock); return FALSE; } } /* Wipe any previous contents from our byte array. */ g_byte_array_set_size (data_wrapper->priv->byte_array, 0); memory_stream = camel_stream_mem_new (); /* We retain ownership of the byte array. */ camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (memory_stream), data_wrapper->priv->byte_array); /* Transfer incoming contents to our byte array. */ bytes_written = camel_stream_write_to_stream ( stream, memory_stream, cancellable, error); g_object_unref (memory_stream); g_mutex_unlock (&data_wrapper->priv->stream_lock); return (bytes_written >= 0); } static gssize data_wrapper_write_to_output_stream_sync (CamelDataWrapper *data_wrapper, GOutputStream *output_stream, GCancellable *cancellable, GError **error) { GInputStream *input_stream; gssize bytes_written; /* XXX Should keep the internal data as a reference-counted * GBytes to avoid locking while writing to the stream. */ g_mutex_lock (&data_wrapper->priv->stream_lock); /* We retain ownership of the byte array content. */ input_stream = g_memory_input_stream_new_from_data ( data_wrapper->priv->byte_array->data, data_wrapper->priv->byte_array->len, (GDestroyNotify) NULL); bytes_written = g_output_stream_splice ( output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_NONE, cancellable, error); g_object_unref (input_stream); g_mutex_unlock (&data_wrapper->priv->stream_lock); return bytes_written; } static gssize data_wrapper_decode_to_output_stream_sync (CamelDataWrapper *data_wrapper, GOutputStream *output_stream, GCancellable *cancellable, GError **error) { CamelMimeFilter *filter = NULL; GOutputStream *filter_stream = NULL; gboolean content_type_is_text; gssize bytes_written; switch (data_wrapper->priv->encoding) { case CAMEL_TRANSFER_ENCODING_BASE64: filter = camel_mime_filter_basic_new ( CAMEL_MIME_FILTER_BASIC_BASE64_DEC); filter_stream = camel_filter_output_stream_new ( output_stream, filter); g_filter_output_stream_set_close_base_stream ( G_FILTER_OUTPUT_STREAM (filter_stream), FALSE); g_object_unref (filter); break; case CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE: filter = camel_mime_filter_basic_new ( CAMEL_MIME_FILTER_BASIC_QP_DEC); filter_stream = camel_filter_output_stream_new ( output_stream, filter); g_filter_output_stream_set_close_base_stream ( G_FILTER_OUTPUT_STREAM (filter_stream), FALSE); g_object_unref (filter); break; case CAMEL_TRANSFER_ENCODING_UUENCODE: filter = camel_mime_filter_basic_new ( CAMEL_MIME_FILTER_BASIC_UU_DEC); filter_stream = camel_filter_output_stream_new ( output_stream, filter); g_filter_output_stream_set_close_base_stream ( G_FILTER_OUTPUT_STREAM (filter_stream), FALSE); g_object_unref (filter); break; default: /* Write directly to the output stream. */ filter_stream = g_object_ref (output_stream); break; } content_type_is_text = camel_content_type_is (data_wrapper->priv->mime_type, "text", "*") && !camel_content_type_is (data_wrapper->priv->mime_type, "text", "pdf"); if (content_type_is_text) { GOutputStream *temp_stream; filter = camel_mime_filter_crlf_new ( CAMEL_MIME_FILTER_CRLF_DECODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); temp_stream = camel_filter_output_stream_new ( filter_stream, filter); g_filter_output_stream_set_close_base_stream ( G_FILTER_OUTPUT_STREAM (temp_stream), FALSE); g_object_unref (filter); g_object_unref (filter_stream); filter_stream = temp_stream; } bytes_written = camel_data_wrapper_write_to_output_stream_sync ( data_wrapper, filter_stream, cancellable, error); g_object_unref (filter_stream); return bytes_written; } static gboolean data_wrapper_construct_from_input_stream_sync (CamelDataWrapper *data_wrapper, GInputStream *input_stream, GCancellable *cancellable, GError **error) { GOutputStream *output_stream; gssize bytes_written; gboolean success; /* XXX Should keep the internal data as a reference-counted * GBytes to avoid locking while reading from the stream. */ g_mutex_lock (&data_wrapper->priv->stream_lock); /* Check for cancellation after locking. */ if (g_cancellable_set_error_if_cancelled (cancellable, error)) { g_mutex_unlock (&data_wrapper->priv->stream_lock); return FALSE; } if (G_IS_SEEKABLE (input_stream)) { success = g_seekable_seek ( G_SEEKABLE (input_stream), 0, G_SEEK_SET, cancellable, error); if (!success) { g_mutex_unlock (&data_wrapper->priv->stream_lock); return FALSE; } } output_stream = g_memory_output_stream_new_resizable (); bytes_written = g_output_stream_splice ( output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, cancellable, error); success = (bytes_written >= 0); if (success) { GBytes *bytes; bytes = g_memory_output_stream_steal_as_bytes ( G_MEMORY_OUTPUT_STREAM (output_stream)); g_byte_array_free (data_wrapper->priv->byte_array, TRUE); data_wrapper->priv->byte_array = g_bytes_unref_to_array (bytes); } g_object_unref (output_stream); g_mutex_unlock (&data_wrapper->priv->stream_lock); return success; } static void camel_data_wrapper_class_init (CamelDataWrapperClass *class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (class); object_class->dispose = data_wrapper_dispose; object_class->finalize = data_wrapper_finalize; class->set_mime_type = data_wrapper_set_mime_type; class->get_mime_type = data_wrapper_get_mime_type; class->get_mime_type_field = data_wrapper_get_mime_type_field; class->set_mime_type_field = data_wrapper_set_mime_type_field; class->is_offline = data_wrapper_is_offline; class->write_to_stream_sync = data_wrapper_write_to_stream_sync; class->decode_to_stream_sync = data_wrapper_decode_to_stream_sync; class->construct_from_stream_sync = data_wrapper_construct_from_stream_sync; class->write_to_output_stream_sync = data_wrapper_write_to_output_stream_sync; class->decode_to_output_stream_sync = data_wrapper_decode_to_output_stream_sync; class->construct_from_input_stream_sync = data_wrapper_construct_from_input_stream_sync; } static void camel_data_wrapper_init (CamelDataWrapper *data_wrapper) { data_wrapper->priv = camel_data_wrapper_get_instance_private (data_wrapper); g_mutex_init (&data_wrapper->priv->stream_lock); data_wrapper->priv->byte_array = g_byte_array_new (); data_wrapper->priv->mime_type = camel_content_type_new ("application", "octet-stream"); data_wrapper->priv->encoding = CAMEL_TRANSFER_ENCODING_DEFAULT; data_wrapper->priv->offline = FALSE; } /** * camel_data_wrapper_new: * * Create a new #CamelDataWrapper object. * * Returns: a new #CamelDataWrapper object **/ CamelDataWrapper * camel_data_wrapper_new (void) { return g_object_new (CAMEL_TYPE_DATA_WRAPPER, NULL); } /** * camel_data_wrapper_get_byte_array: * @data_wrapper: a #CamelDataWrapper * * Returns the #GByteArray being used to hold the contents of @data_wrapper. * * Note, it's up to the caller to use this in a thread-safe manner. * * Returns: (transfer none): the #GByteArray for @data_wrapper * * Since: 3.2 **/ GByteArray * camel_data_wrapper_get_byte_array (CamelDataWrapper *data_wrapper) { g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL); return data_wrapper->priv->byte_array; } /** * camel_data_wrapper_get_encoding: * @data_wrapper: a #CamelDataWrapper * * Returns: An encoding (#CamelTransferEncoding) of the @data_wrapper * * Since: 3.24 **/ CamelTransferEncoding camel_data_wrapper_get_encoding (CamelDataWrapper *data_wrapper) { g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), CAMEL_TRANSFER_ENCODING_DEFAULT); return data_wrapper->priv->encoding; } /** * camel_data_wrapper_set_encoding: * @data_wrapper: a #CamelDataWrapper * @encoding: an encoding to set * * Sets encoding (#CamelTransferEncoding) for the @data_wrapper. * It doesn't re-encode the content, if the encoding changes. * * Since: 3.24 **/ void camel_data_wrapper_set_encoding (CamelDataWrapper *data_wrapper, CamelTransferEncoding encoding) { g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); data_wrapper->priv->encoding = encoding; } /** * camel_data_wrapper_set_mime_type: * @data_wrapper: a #CamelDataWrapper * @mime_type: a MIME type * * This sets the data wrapper's MIME type. * * It might fail, but you won't know. It will allow you to set * Content-Type parameters on the data wrapper, which are meaningless. * You should not be allowed to change the MIME type of a data wrapper * that contains data, or at least, if you do, it should invalidate the * data. **/ void camel_data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper, const gchar *mime_type) { CamelDataWrapperClass *class; g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (mime_type != NULL); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_if_fail (class != NULL); g_return_if_fail (class->set_mime_type != NULL); class->set_mime_type (data_wrapper, mime_type); } /** * camel_data_wrapper_get_mime_type: * @data_wrapper: a #CamelDataWrapper * * Returns: the MIME type which must be freed by the caller **/ gchar * camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper) { CamelDataWrapperClass *class; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, NULL); g_return_val_if_fail (class->get_mime_type != NULL, NULL); return class->get_mime_type (data_wrapper); } /** * camel_data_wrapper_get_mime_type_field: * @data_wrapper: a #CamelDataWrapper * * Returns: (transfer none) (nullable): the parsed form of the data wrapper's MIME type **/ CamelContentType * camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper) { CamelDataWrapperClass *class; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), NULL); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, NULL); g_return_val_if_fail (class->get_mime_type_field != NULL, NULL); return class->get_mime_type_field (data_wrapper); } /** * camel_data_wrapper_set_mime_type_field: * @data_wrapper: a #CamelDataWrapper * @mime_type: (nullable): a #CamelContentType * * This sets the data wrapper's MIME type. It adds its own reference * to @mime_type, if not %NULL. * * It suffers from the same flaws as camel_data_wrapper_set_mime_type(). **/ void camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper, CamelContentType *mime_type) { CamelDataWrapperClass *class; g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (mime_type != NULL); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_if_fail (class != NULL); g_return_if_fail (class->set_mime_type_field != NULL); class->set_mime_type_field (data_wrapper, mime_type); } /** * camel_data_wrapper_take_mime_type_field: * @data_wrapper: a #CamelDataWrapper * @mime_type: (nullable) (transfer full): a #CamelContentType * * Sets mime-type filed to be @mime_type and consumes it, aka unlike * camel_data_wrapper_set_mime_type_field(), this doesn't add its own * reference to @mime_type. * * It suffers from the same flaws as camel_data_wrapper_set_mime_type(). * * Since: 3.24 **/ void camel_data_wrapper_take_mime_type_field (CamelDataWrapper *data_wrapper, CamelContentType *mime_type) { g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (mime_type != NULL); camel_data_wrapper_set_mime_type_field (data_wrapper, mime_type); if (mime_type) camel_content_type_unref (mime_type); } /** * camel_data_wrapper_is_offline: * @data_wrapper: a #CamelDataWrapper * * Returns: whether @data_wrapper is "offline" (data stored * remotely) or not. Some optional code paths may choose to not * operate on offline data. **/ gboolean camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper) { CamelDataWrapperClass *class; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), TRUE); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, TRUE); g_return_val_if_fail (class->is_offline != NULL, TRUE); return class->is_offline (data_wrapper); } /** * camel_data_wrapper_set_offline: * @data_wrapper: a #CamelDataWrapper * @offline: whether the @data_wrapper is "offline" * * Sets whether the @data_wrapper is "offline". It applies only to this * concrete instance. See camel_data_wrapper_is_offline(). * * Since: 3.24 **/ void camel_data_wrapper_set_offline (CamelDataWrapper *data_wrapper, gboolean offline) { g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); data_wrapper->priv->offline = offline; } /** * camel_data_wrapper_write_to_stream_sync: * @data_wrapper: a #CamelDataWrapper * @stream: a #CamelStream for output * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Writes the content of @data_wrapper to @stream in a machine-independent * format appropriate for the data. It should be possible to construct an * equivalent data wrapper object later by passing this stream to * camel_data_wrapper_construct_from_stream_sync(). * * * * This function may block even if the given output stream does not. * For example, the content may have to be fetched across a network * before it can be written to @stream. * * * * Returns: the number of bytes written, or -1 on error * * Since: 3.0 **/ gssize camel_data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelDataWrapperClass *class; gssize bytes_written; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, -1); g_return_val_if_fail (class->write_to_stream_sync != NULL, -1); bytes_written = class->write_to_stream_sync ( data_wrapper, stream, cancellable, error); CAMEL_CHECK_GERROR ( data_wrapper, write_to_stream_sync, bytes_written >= 0, error); return bytes_written; } /* Helper for camel_data_wrapper_write_to_stream() */ static void data_wrapper_write_to_stream_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { gssize bytes_written; AsyncContext *async_context; GError *local_error = NULL; async_context = (AsyncContext *) task_data; bytes_written = camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (source_object), async_context->stream, cancellable, &local_error); if (local_error != NULL) { g_task_return_error (task, local_error); } else { g_task_return_int (task, bytes_written); } } /** * camel_data_wrapper_write_to_stream: * @data_wrapper: a #CamelDataWrapper * @stream: a #CamelStream for writed data to be written to * @io_priority: the I/O priority of the request * @cancellable: optional #GCancellable object, or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: data to pass to the callback function * * Asynchronously writes the content of @data_wrapper to @stream in a * machine-independent format appropriate for the data. It should be * possible to construct an equivalent data wrapper object later by * passing this stream to camel_data_wrapper_construct_from_stream(). * * When the operation is finished, @callback will be called. You can then * call camel_data_wrapper_write_to_stream_finish() to get the result of * the operation. * * Since: 3.0 **/ void camel_data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; AsyncContext *async_context; g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (CAMEL_IS_STREAM (stream)); async_context = g_slice_new0 (AsyncContext); async_context->stream = g_object_ref (stream); task = g_task_new (data_wrapper, cancellable, callback, user_data); g_task_set_source_tag (task, camel_data_wrapper_write_to_stream); g_task_set_priority (task, io_priority); g_task_set_task_data ( task, async_context, (GDestroyNotify) async_context_free); g_task_run_in_thread (task, data_wrapper_write_to_stream_thread); g_object_unref (task); } /** * camel_data_wrapper_write_to_stream_finish: * @data_wrapper: a #CamelDataWrapper * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * * Finishes the operation started with camel_data_wrapper_write_to_stream(). * * Returns: the number of bytes written, or -1 or error * * Since: 3.0 **/ gssize camel_data_wrapper_write_to_stream_finish (CamelDataWrapper *data_wrapper, GAsyncResult *result, GError **error) { g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (g_task_is_valid (result, data_wrapper), -1); g_return_val_if_fail ( g_async_result_is_tagged ( result, camel_data_wrapper_write_to_stream), -1); return g_task_propagate_int (G_TASK (result), error); } /** * camel_data_wrapper_decode_to_stream_sync: * @data_wrapper: a #CamelDataWrapper * @stream: a #CamelStream for decoded data to be written to * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Writes the decoded data content to @stream. * * * * This function may block even if the given output stream does not. * For example, the content may have to be fetched across a network * before it can be written to @stream. * * * * Returns: the number of bytes written, or -1 on error * * Since: 3.0 **/ gssize camel_data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelDataWrapperClass *class; gssize bytes_written; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, -1); g_return_val_if_fail (class->decode_to_stream_sync != NULL, -1); bytes_written = class->decode_to_stream_sync ( data_wrapper, stream, cancellable, error); CAMEL_CHECK_GERROR ( data_wrapper, decode_to_stream_sync, bytes_written >= 0, error); return bytes_written; } /* Helper for camel_data_wrapper_decode_to_stream() */ static void data_wrapper_decode_to_stream_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { gssize bytes_written; AsyncContext *async_context; GError *local_error = NULL; async_context = (AsyncContext *) task_data; bytes_written = camel_data_wrapper_decode_to_stream_sync ( CAMEL_DATA_WRAPPER (source_object), async_context->stream, cancellable, &local_error); if (local_error != NULL) { g_task_return_error (task, local_error); } else { g_task_return_int (task, bytes_written); } } /** * camel_data_wrapper_decode_to_stream: * @data_wrapper: a #CamelDataWrapper * @stream: a #CamelStream for decoded data to be written to * @io_priority: the I/O priority of the request * @cancellable: optional #GCancellable object, or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: data to pass to the callback function * * Asynchronously writes the decoded data content to @stream. * * When the operation is finished, @callback will be called. You can then * call camel_data_wrapper_decode_to_stream_finish() to get the result of * the operation. * * Since: 3.0 **/ void camel_data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; AsyncContext *async_context; g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (CAMEL_IS_STREAM (stream)); async_context = g_slice_new0 (AsyncContext); async_context->stream = g_object_ref (stream); task = g_task_new (data_wrapper, cancellable, callback, user_data); g_task_set_source_tag (task, camel_data_wrapper_decode_to_stream); g_task_set_priority (task, io_priority); g_task_set_task_data ( task, async_context, (GDestroyNotify) async_context_free); g_task_run_in_thread (task, data_wrapper_decode_to_stream_thread); g_object_unref (task); } /** * camel_data_wrapper_decode_to_stream_finish: * @data_wrapper: a #CamelDataWrapper * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * * Finishes the operation started with camel_data_wrapper_decode_to_stream(). * * Returns: the number of bytes written, or -1 on error * * Since: 3.0 **/ gssize camel_data_wrapper_decode_to_stream_finish (CamelDataWrapper *data_wrapper, GAsyncResult *result, GError **error) { g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (g_task_is_valid (result, data_wrapper), -1); g_return_val_if_fail ( g_async_result_is_tagged ( result, camel_data_wrapper_decode_to_stream), -1); return g_task_propagate_int (G_TASK (result), error); } /** * camel_data_wrapper_construct_from_stream_sync: * @data_wrapper: a #CamelDataWrapper * @stream: an input #CamelStream * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Constructs the content of @data_wrapper from the given @stream. * * Returns: %TRUE on success, %FALSE on error * * Since: 3.0 **/ gboolean camel_data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelDataWrapperClass *class; gboolean success; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE); g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, FALSE); g_return_val_if_fail (class->construct_from_stream_sync != NULL, FALSE); success = class->construct_from_stream_sync ( data_wrapper, stream, cancellable, error); CAMEL_CHECK_GERROR ( data_wrapper, construct_from_stream_sync, success, error); return success; } /* Helper for camel_data_wrapper_construct_from_stream() */ static void data_wrapper_construct_from_stream_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { gboolean success; AsyncContext *async_context; GError *local_error = NULL; async_context = (AsyncContext *) task_data; success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (source_object), async_context->stream, cancellable, &local_error); if (local_error != NULL) { g_task_return_error (task, local_error); } else { g_task_return_boolean (task, success); } } /** * camel_data_wrapper_construct_from_stream: * @data_wrapper: a #CamelDataWrapper * @stream: an input #CamelStream * @io_priority: the I/O priority of the request * @cancellable: optional #GCancellable object, or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: data to pass to the callback function * * Asynchronously constructs the content of @data_wrapper from the given * @stream. * * When the operation is finished, @callback will be called. You can then * call camel_data_wrapper_construct_from_stream_finish() to get the result * of the operation. * * Since: 3.0 **/ void camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper, CamelStream *stream, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; AsyncContext *async_context; g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (CAMEL_IS_STREAM (stream)); async_context = g_slice_new0 (AsyncContext); async_context->stream = g_object_ref (stream); task = g_task_new (data_wrapper, cancellable, callback, user_data); g_task_set_source_tag (task, camel_data_wrapper_construct_from_stream); g_task_set_priority (task, io_priority); g_task_set_task_data ( task, async_context, (GDestroyNotify) async_context_free); g_task_run_in_thread (task, data_wrapper_construct_from_stream_thread); g_object_unref (task); } /** * camel_data_wrapper_construct_from_stream_finish: * @data_wrapper: a #CamelDataWrapper * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * * Finishes the operation started with * camel_data_wrapper_construct_from_stream(). * * Returns: %TRUE on success, %FALSE on error * * Since: 3.0 **/ gboolean camel_data_wrapper_construct_from_stream_finish (CamelDataWrapper *data_wrapper, GAsyncResult *result, GError **error) { g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE); g_return_val_if_fail (g_task_is_valid (result, data_wrapper), FALSE); g_return_val_if_fail ( g_async_result_is_tagged ( result, camel_data_wrapper_construct_from_stream), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } /** * camel_data_wrapper_write_to_output_stream_sync: * @data_wrapper: a #CamelDataWrapper * @output_stream: a #GOutputStream * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Writes the content of @data_wrapper to @output_stream in a * machine-independent format appropriate for the data. * * * * This function may block even if the given output stream does not. * For example, the content may have to be fetched across a network * before it can be written to @output_stream. * * * * Returns: the number of bytes written, or -1 on error * * Since: 3.12 **/ gssize camel_data_wrapper_write_to_output_stream_sync (CamelDataWrapper *data_wrapper, GOutputStream *output_stream, GCancellable *cancellable, GError **error) { CamelDataWrapperClass *class; gssize bytes_written; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, -1); g_return_val_if_fail (class->write_to_output_stream_sync != NULL, -1); bytes_written = class->write_to_output_stream_sync ( data_wrapper, output_stream, cancellable, error); CAMEL_CHECK_GERROR ( data_wrapper, write_to_output_stream_sync, bytes_written >= 0, error); if (bytes_written >= 0) { if (!g_output_stream_flush (output_stream, cancellable, error)) bytes_written = -1; } return bytes_written; } /* Helper for camel_data_wrapper_write_to_output_stream() */ static void data_wrapper_write_to_output_stream_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { gssize bytes_written; AsyncContext *async_context; GError *local_error = NULL; async_context = (AsyncContext *) task_data; bytes_written = camel_data_wrapper_write_to_output_stream_sync ( CAMEL_DATA_WRAPPER (source_object), async_context->output_stream, cancellable, &local_error); if (local_error != NULL) { g_task_return_error (task, local_error); } else { g_task_return_int (task, bytes_written); } } /** * camel_data_wrapper_write_to_output_stream: * @data_wrapper: a #CamelDataWrapper * @output_stream: a #GOutputStream * @io_priority: the I/O priority of the request * @cancellable: optional #GCancellable object, or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: data to pass to the callback function * * Asynchronously writes the content of @data_wrapper to @output_stream in * a machine-independent format appropriate for the data. * * When the operation is finished, @callback will be called. You can then * call camel_data_wrapper_write_to_output_stream_finish() to get the result * of the operation. * * Since: 3.12 **/ void camel_data_wrapper_write_to_output_stream (CamelDataWrapper *data_wrapper, GOutputStream *output_stream, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; AsyncContext *async_context; g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (G_IS_OUTPUT_STREAM (output_stream)); async_context = g_slice_new0 (AsyncContext); async_context->output_stream = g_object_ref (output_stream); task = g_task_new (data_wrapper, cancellable, callback, user_data); g_task_set_source_tag (task, camel_data_wrapper_write_to_output_stream); g_task_set_priority (task, io_priority); g_task_set_task_data ( task, async_context, (GDestroyNotify) async_context_free); g_task_run_in_thread ( task, data_wrapper_write_to_output_stream_thread); g_object_unref (task); } /** * camel_data_wrapper_write_to_output_stream_finish: * @data_wrapper: a #CamelDataWrapper * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * * Finishes the operation started with * camel_data_wrapper_write_to_output_stream(). * * Returns: the number of bytes written, or -1 on error * * Since: 3.12 **/ gssize camel_data_wrapper_write_to_output_stream_finish (CamelDataWrapper *data_wrapper, GAsyncResult *result, GError **error) { g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (g_task_is_valid (result, data_wrapper), -1); g_return_val_if_fail ( g_async_result_is_tagged ( result, camel_data_wrapper_write_to_output_stream), -1); return g_task_propagate_int (G_TASK (result), error); } /** * camel_data_wrapper_decode_to_output_stream_sync: * @data_wrapper: a #CamelDataWrapper * @output_stream: a #GOutputStream * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Writes the decoded data content to @output_stream. * * * * This function may block even if the given output stream does not. * For example, the content may have to be fetched across a network * before it can be written to @output_stream. * * * * Returns: the number of bytes written, or -1 on error * * Since: 3.12 **/ gssize camel_data_wrapper_decode_to_output_stream_sync (CamelDataWrapper *data_wrapper, GOutputStream *output_stream, GCancellable *cancellable, GError **error) { CamelDataWrapperClass *class; gssize bytes_written; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, -1); g_return_val_if_fail (class->decode_to_output_stream_sync != NULL, -1); bytes_written = class->decode_to_output_stream_sync ( data_wrapper, output_stream, cancellable, error); CAMEL_CHECK_GERROR ( data_wrapper, decode_to_output_stream_sync, bytes_written >= 0, error); return bytes_written; } /* Helper for camel_data_wrapper_decode_to_output_stream() */ static void data_wrapper_decode_to_output_stream_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { gssize bytes_written; AsyncContext *async_context; GError *local_error = NULL; async_context = (AsyncContext *) task_data; bytes_written = camel_data_wrapper_decode_to_output_stream_sync ( CAMEL_DATA_WRAPPER (source_object), async_context->output_stream, cancellable, &local_error); if (local_error != NULL) { g_task_return_error (task, local_error); } else { g_task_return_int (task, bytes_written); } } /** * camel_data_wrapper_decode_to_output_stream: * @data_wrapper: a #CamelDataWrapper * @output_stream: a #GOutputStream * @io_priority: the I/O priority of the request * @cancellable: optional #GCancellable object, or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: data to pass to the callback function * * Asynchronously writes the decoded data content to @output_stream. * * When the operation is finished, @callback will be called. You can then * call camel_data_wrapper_decode_to_output_stream_finish() to get the result * of the operation. * * Since: 3.12 **/ void camel_data_wrapper_decode_to_output_stream (CamelDataWrapper *data_wrapper, GOutputStream *output_stream, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; AsyncContext *async_context; g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (G_IS_OUTPUT_STREAM (output_stream)); async_context = g_slice_new0 (AsyncContext); async_context->output_stream = g_object_ref (output_stream); task = g_task_new (data_wrapper, cancellable, callback, user_data); g_task_set_source_tag (task, camel_data_wrapper_decode_to_output_stream); g_task_set_priority (task, io_priority); g_task_set_task_data ( task, async_context, (GDestroyNotify) async_context_free); g_task_run_in_thread ( task, data_wrapper_decode_to_output_stream_thread); g_object_unref (task); } /** * camel_data_wrapper_decode_to_output_stream_finish: * @data_wrapper: a #CamelDataWrapper * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * * Finishes the operation started with * camel_data_wrapper_decode_to_output_stream(). * * Returns: the number of bytes written, or -1 on error * * Since: 3.12 **/ gssize camel_data_wrapper_decode_to_output_stream_finish (CamelDataWrapper *data_wrapper, GAsyncResult *result, GError **error) { g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (g_task_is_valid (result, data_wrapper), -1); g_return_val_if_fail ( g_async_result_is_tagged ( result, camel_data_wrapper_decode_to_output_stream), -1); return g_task_propagate_int (G_TASK (result), error); } /** * camel_data_wrapper_construct_from_input_stream_sync: * @data_wrapper: a #CamelDataWrapper * @input_stream: a #GInputStream * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Constructs the content of @data_wrapper from @input_stream. * * Returns: %TRUE on success, %FALSE on error * * Since: 3.12 **/ gboolean camel_data_wrapper_construct_from_input_stream_sync (CamelDataWrapper *data_wrapper, GInputStream *input_stream, GCancellable *cancellable, GError **error) { CamelDataWrapperClass *class; gboolean success; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE); g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), FALSE); class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class != NULL, FALSE); g_return_val_if_fail (class->construct_from_input_stream_sync != NULL, FALSE); success = class->construct_from_input_stream_sync ( data_wrapper, input_stream, cancellable, error); CAMEL_CHECK_GERROR ( data_wrapper, construct_from_input_stream_sync, success, error); return success; } /* Helper for camel_data_wrapper_construct_from_input_stream() */ static void data_wrapper_construct_from_input_stream_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { gboolean success; AsyncContext *async_context; GError *local_error = NULL; async_context = (AsyncContext *) task_data; success = camel_data_wrapper_construct_from_input_stream_sync ( CAMEL_DATA_WRAPPER (source_object), async_context->input_stream, cancellable, &local_error); if (local_error != NULL) { g_task_return_error (task, local_error); } else { g_task_return_boolean (task, success); } } /** * camel_data_wrapper_construct_from_input_stream: * @data_wrapper: a #CamelDataWrapper * @input_stream: a #GInputStream * @io_priority: the I/O priority of the request * @cancellable: optional #GCancellable object, or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: data to pass to the callback function * * Asynchronously constructs the content of @data_wrapper from @input_stream. * * When the operation is finished, @callback will be called. You can then * call camel_data_wrapper_construct_from_input_stream_finish() to get the * result of the operation. * * Since: 3.12 **/ void camel_data_wrapper_construct_from_input_stream (CamelDataWrapper *data_wrapper, GInputStream *input_stream, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; AsyncContext *async_context; g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); g_return_if_fail (G_IS_INPUT_STREAM (input_stream)); async_context = g_slice_new0 (AsyncContext); async_context->input_stream = g_object_ref (input_stream); task = g_task_new (data_wrapper, cancellable, callback, user_data); g_task_set_source_tag (task, camel_data_wrapper_construct_from_input_stream); g_task_set_priority (task, io_priority); g_task_set_task_data ( task, async_context, (GDestroyNotify) async_context_free); g_task_run_in_thread (task, data_wrapper_construct_from_input_stream_thread); g_object_unref (task); } /** * camel_data_wrapper_construct_from_input_stream_finish: * @data_wrapper: a #CamelDataWrapper * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * * Finishes the operation started with * camel_data_wrapper_construct_from_input_stream(). * * Returns: %TRUE on success, %FALSE on error * * Since: 3.12 **/ gboolean camel_data_wrapper_construct_from_input_stream_finish (CamelDataWrapper *data_wrapper, GAsyncResult *result, GError **error) { g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE); g_return_val_if_fail (g_task_is_valid (result, data_wrapper), FALSE); g_return_val_if_fail ( g_async_result_is_tagged ( result, camel_data_wrapper_construct_from_input_stream), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } /** * camel_data_wrapper_construct_from_data_sync: * @data_wrapper: a #CamelDataWrapper * @data: (not nullable): data to set * @data_len: length of @data * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Constructs the content of @data_wrapper from @data of length @data_len. * * Returns: %TRUE on success, %FALSE on error * * Since: 3.46 **/ gboolean camel_data_wrapper_construct_from_data_sync (CamelDataWrapper *data_wrapper, gconstpointer data, gssize data_len, GCancellable *cancellable, GError **error) { GInputStream *input_stream; gboolean success; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE); g_return_val_if_fail (data != NULL, FALSE); input_stream = g_memory_input_stream_new_from_data (data, data_len, NULL); success = camel_data_wrapper_construct_from_input_stream_sync (data_wrapper, input_stream, cancellable, error); g_clear_object (&input_stream); return success; } /** * camel_data_wrapper_calculate_size_sync: * @data_wrapper: a #CamelDataWrapper * @cancellable: a #GCancellable, or %NULL * @error: return location for a #GError, or %NULL * * Calculates size of the @data_wrapper by saving it to a null-stream * and returns how many bytes had been written. It's using * camel_data_wrapper_write_to_stream_sync() internally. * * Returns: how many bytes the @data_wrapper would use when saved, * or -1 on error. * * Since: 3.24 **/ gsize camel_data_wrapper_calculate_size_sync (CamelDataWrapper *data_wrapper, GCancellable *cancellable, GError **error) { CamelStream *stream; gsize bytes_written = -1; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); stream = camel_stream_null_new (); if (camel_data_wrapper_write_to_stream_sync (data_wrapper, stream, cancellable, error)) bytes_written = camel_stream_null_get_bytes_written (CAMEL_STREAM_NULL (stream)); g_object_unref (stream); return bytes_written; } /** * camel_data_wrapper_calculate_decoded_size_sync: * @data_wrapper: a #CamelDataWrapper * @cancellable: a #GCancellable, or %NULL * @error: return location for a #GError, or %NULL * * Calculates decoded size of the @data_wrapper by saving it to a null-stream * and returns how many bytes had been written. It's using * camel_data_wrapper_decode_to_stream_sync() internally. * * Returns: how many bytes the @data_wrapper would use when saved, * or -1 on error. * * Since: 3.24 **/ gsize camel_data_wrapper_calculate_decoded_size_sync (CamelDataWrapper *data_wrapper, GCancellable *cancellable, GError **error) { CamelStream *stream; gsize bytes_written = -1; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); stream = camel_stream_null_new (); if (camel_data_wrapper_decode_to_stream_sync (data_wrapper, stream, cancellable, error)) bytes_written = camel_stream_null_get_bytes_written (CAMEL_STREAM_NULL (stream)); g_object_unref (stream); return bytes_written; }