From: Matthew Barnes Date: Thu, 23 Sep 2010 18:04:32 +0000 (-0400) Subject: Camel: Add an asynchronous API. X-Git-Tag: upstream/3.7.4~2553 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cea02d071c2e5334d5f38b802d32e47bf06766cc;p=platform%2Fupstream%2Fevolution-data-server.git Camel: Add an asynchronous API. Add pairs of asynchronous "dispatch" and "finish" methods for most blocking "sync" methods in Camel's public API. All asynchronous methods have default implementations that just call its synchronous counterpart from a thread in GIO's thread pool (which is roughly equivalent to what Evolution is doing from its own thread pool). The possibility for Camel providers to implement an asynchronous architecture by overriding the asynchronous methods exists, but first requires some cleanup in the synchronous dispatching functions, many of which are not "pure" in the sense that they do extra stuff before and after calling the class method they wrap. That extra logic needs to somehow run as part of the class method itself, either via chaining up from subclasses or some other means. In simpler terms, the following invariant must hold before providers can override asynchronous methods and expect correct behavior from Camel: Calling camel_foo_frobnicate_sync(foo) is equivalent to calling CAMEL_FOO_GET_CLASS (foo)->frobnicate_sync (foo), just with fewer runtime checks. --- diff --git a/camel/camel-cipher-context.c b/camel/camel-cipher-context.c index 3ffa355..782e997 100644 --- a/camel/camel-cipher-context.c +++ b/camel/camel-cipher-context.c @@ -50,11 +50,26 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_CIPHER_CONTEXT, CamelCipherContextPrivate)) +typedef struct _AsyncContext AsyncContext; + struct _CamelCipherContextPrivate { CamelSession *session; GMutex *lock; }; +struct _AsyncContext { + /* arguments */ + CamelCipherHash hash; + CamelMimePart *ipart; + CamelMimePart *opart; + CamelStream *stream; + GPtrArray *strings; + gchar *userid; + + /* results */ + CamelCipherValidity *validity; +}; + enum { PROP_0, PROP_SESSION @@ -63,6 +78,32 @@ enum { G_DEFINE_TYPE (CamelCipherContext, camel_cipher_context, CAMEL_TYPE_OBJECT) static void +async_context_free (AsyncContext *async_context) +{ + if (async_context->ipart != NULL) + g_object_unref (async_context->ipart); + + if (async_context->opart != NULL) + g_object_unref (async_context->opart); + + if (async_context->stream != NULL) + g_object_unref (async_context->stream); + + if (async_context->strings != NULL) { + g_ptr_array_foreach ( + async_context->strings, (GFunc) g_free, NULL); + g_ptr_array_free (async_context->strings, TRUE); + } + + if (async_context->validity != NULL) + camel_cipher_validity_free (async_context->validity); + + g_free (async_context->userid); + + g_slice_free (AsyncContext, async_context); +} + +static void cipher_context_set_session (CamelCipherContext *context, CamelSession *session) { @@ -136,40 +177,40 @@ cipher_context_finalize (GObject *object) } static const gchar * -cipher_hash_to_id (CamelCipherContext *context, - CamelCipherHash hash) +cipher_context_hash_to_id (CamelCipherContext *context, + CamelCipherHash hash) { return NULL; } static CamelCipherHash -cipher_id_to_hash (CamelCipherContext *context, - const gchar *id) +cipher_context_id_to_hash (CamelCipherContext *context, + const gchar *id) { return CAMEL_CIPHER_HASH_DEFAULT; } -static gint -cipher_sign_sync (CamelCipherContext *ctx, - const gchar *userid, - CamelCipherHash hash, - CamelMimePart *ipart, - CamelMimePart *opart, - GCancellable *cancellable, - GError **error) +static gboolean +cipher_context_sign_sync (CamelCipherContext *ctx, + const gchar *userid, + CamelCipherHash hash, + CamelMimePart *ipart, + CamelMimePart *opart, + GCancellable *cancellable, + GError **error) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Signing is not supported by this cipher")); - return -1; + return FALSE; } static CamelCipherValidity * -cipher_verify_sync (CamelCipherContext *context, - CamelMimePart *sigpart, - GCancellable *cancellable, - GError **error) +cipher_context_verify_sync (CamelCipherContext *context, + CamelMimePart *sigpart, + GCancellable *cancellable, + GError **error) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, @@ -178,28 +219,28 @@ cipher_verify_sync (CamelCipherContext *context, return NULL; } -static gint -cipher_encrypt_sync (CamelCipherContext *context, - const gchar *userid, - GPtrArray *recipients, - CamelMimePart *ipart, - CamelMimePart *opart, - GCancellable *cancellable, - GError **error) +static gboolean +cipher_context_encrypt_sync (CamelCipherContext *context, + const gchar *userid, + GPtrArray *recipients, + CamelMimePart *ipart, + CamelMimePart *opart, + GCancellable *cancellable, + GError **error) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Encryption is not supported by this cipher")); - return -1; + return FALSE; } static CamelCipherValidity * -cipher_decrypt_sync (CamelCipherContext *context, - CamelMimePart *ipart, - CamelMimePart *opart, - GCancellable *cancellable, - GError **error) +cipher_context_decrypt_sync (CamelCipherContext *context, + CamelMimePart *ipart, + CamelMimePart *opart, + GCancellable *cancellable, + GError **error) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, @@ -208,31 +249,469 @@ cipher_decrypt_sync (CamelCipherContext *context, return NULL; } -static gint -cipher_import_keys_sync (CamelCipherContext *context, - CamelStream *istream, - GCancellable *cancellable, - GError **error) +static gboolean +cipher_context_import_keys_sync (CamelCipherContext *context, + CamelStream *istream, + GCancellable *cancellable, + GError **error) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("You may not import keys with this cipher")); - return -1; + return FALSE; } static gint -cipher_export_keys_sync (CamelCipherContext *context, - GPtrArray *keys, - CamelStream *ostream, - GCancellable *cancellable, - GError **error) +cipher_context_export_keys_sync (CamelCipherContext *context, + GPtrArray *keys, + CamelStream *ostream, + GCancellable *cancellable, + GError **error) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("You may not export keys with this cipher")); - return -1; + return FALSE; +} + +static void +cipher_context_sign_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_cipher_context_sign_sync ( + CAMEL_CIPHER_CONTEXT (object), + async_context->userid, async_context->hash, + async_context->ipart, async_context->opart, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +cipher_context_sign (CamelCipherContext *context, + const gchar *userid, + CamelCipherHash hash, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->userid = g_strdup (userid); + async_context->hash = hash; + async_context->ipart = g_object_ref (ipart); + async_context->opart = g_object_ref (opart); + + simple = g_simple_async_result_new ( + G_OBJECT (context), callback, user_data, cipher_context_sign); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, cipher_context_sign_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +cipher_context_sign_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (context), cipher_context_sign), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +cipher_context_verify_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->validity = camel_cipher_context_verify_sync ( + CAMEL_CIPHER_CONTEXT (object), async_context->ipart, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +cipher_context_verify (CamelCipherContext *context, + CamelMimePart *ipart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->ipart = g_object_ref (ipart); + + simple = g_simple_async_result_new ( + G_OBJECT (context), callback, + user_data, cipher_context_verify); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, cipher_context_verify_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static CamelCipherValidity * +cipher_context_verify_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + CamelCipherValidity *validity; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (context), cipher_context_verify), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + validity = async_context->validity; + async_context->validity = NULL; + + return validity; +} + +static void +cipher_context_encrypt_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_cipher_context_encrypt_sync ( + CAMEL_CIPHER_CONTEXT (object), + async_context->userid, async_context->strings, + async_context->ipart, async_context->opart, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +cipher_context_encrypt (CamelCipherContext *context, + const gchar *userid, + GPtrArray *recipients, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + guint ii; + + async_context = g_slice_new0 (AsyncContext); + async_context->userid = g_strdup (userid); + async_context->strings = g_ptr_array_new (); + async_context->ipart = g_object_ref (ipart); + async_context->opart = g_object_ref (opart); + + for (ii = 0; ii < recipients->len; ii++) + g_ptr_array_add ( + async_context->strings, + g_strdup (recipients->pdata[ii])); + + simple = g_simple_async_result_new ( + G_OBJECT (context), callback, + user_data, cipher_context_encrypt); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, cipher_context_encrypt_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +cipher_context_encrypt_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (context), cipher_context_encrypt), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +cipher_context_decrypt_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->validity = camel_cipher_context_decrypt_sync ( + CAMEL_CIPHER_CONTEXT (object), async_context->ipart, + async_context->opart, cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +cipher_context_decrypt (CamelCipherContext *context, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->ipart = g_object_ref (ipart); + async_context->opart = g_object_ref (opart); + + simple = g_simple_async_result_new ( + G_OBJECT (context), callback, + user_data, cipher_context_decrypt); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, cipher_context_decrypt_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static CamelCipherValidity * +cipher_context_decrypt_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + CamelCipherValidity *validity; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (context), cipher_context_decrypt), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + validity = async_context->validity; + async_context->validity = NULL; + + return validity; +} + +static void +cipher_context_import_keys_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_cipher_context_import_keys_sync ( + CAMEL_CIPHER_CONTEXT (object), async_context->stream, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +cipher_context_import_keys (CamelCipherContext *context, + CamelStream *istream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->stream = g_object_ref (istream); + + simple = g_simple_async_result_new ( + G_OBJECT (context), callback, + user_data, cipher_context_import_keys); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, cipher_context_import_keys_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +cipher_context_import_keys_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (context), + cipher_context_import_keys), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +cipher_context_export_keys_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_cipher_context_export_keys_sync ( + CAMEL_CIPHER_CONTEXT (object), async_context->strings, + async_context->stream, cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +cipher_context_export_keys (CamelCipherContext *context, + GPtrArray *keys, + CamelStream *ostream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + guint ii; + + async_context = g_slice_new0 (AsyncContext); + async_context->strings = g_ptr_array_new (); + async_context->stream = g_object_ref (ostream); + + for (ii = 0; ii < keys->len; ii++) + g_ptr_array_add ( + async_context->strings, + g_strdup (keys->pdata[ii])); + + simple = g_simple_async_result_new ( + G_OBJECT (context), callback, + user_data, cipher_context_export_keys); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, cipher_context_export_keys_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +cipher_context_export_keys_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (context), + cipher_context_export_keys), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); } static void @@ -248,14 +727,28 @@ camel_cipher_context_class_init (CamelCipherContextClass *class) object_class->dispose = cipher_context_dispose; object_class->finalize = cipher_context_finalize; - class->hash_to_id = cipher_hash_to_id; - class->id_to_hash = cipher_id_to_hash; - class->sign_sync = cipher_sign_sync; - class->verify_sync = cipher_verify_sync; - class->encrypt_sync = cipher_encrypt_sync; - class->decrypt_sync = cipher_decrypt_sync; - class->import_keys_sync = cipher_import_keys_sync; - class->export_keys_sync = cipher_export_keys_sync; + class->hash_to_id = cipher_context_hash_to_id; + class->id_to_hash = cipher_context_id_to_hash; + + class->sign_sync = cipher_context_sign_sync; + class->verify_sync = cipher_context_verify_sync; + class->encrypt_sync = cipher_context_encrypt_sync; + class->decrypt_sync = cipher_context_decrypt_sync; + class->import_keys_sync = cipher_context_import_keys_sync; + class->export_keys_sync = cipher_context_export_keys_sync; + + class->sign = cipher_context_sign; + class->sign_finish = cipher_context_sign_finish; + class->verify = cipher_context_verify; + class->verify_finish = cipher_context_verify_finish; + class->encrypt = cipher_context_encrypt; + class->encrypt_finish = cipher_context_encrypt_finish; + class->decrypt = cipher_context_decrypt; + class->decrypt_finish = cipher_context_decrypt_finish; + class->import_keys = cipher_context_import_keys; + class->import_keys_finish = cipher_context_import_keys_finish; + class->export_keys = cipher_context_export_keys; + class->export_keys_finish = cipher_context_export_keys_finish; g_object_class_install_property ( object_class, @@ -277,81 +770,169 @@ camel_cipher_context_init (CamelCipherContext *context) } /** - * camel_cipher_sign_sync: - * @context: Cipher Context - * @userid: private key to use to sign the stream + * camel_cipher_context_sign_sync: + * @context: a #CamelCipherContext + * @userid: a private key to use to sign the stream * @hash: preferred Message-Integrity-Check hash algorithm - * @ipart: Input part. - * @opart: output part. + * @ipart: input #CamelMimePart + * @opart: output #CamelMimePart * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * - * Converts the (unsigned) part @ipart into a new self-contained mime + * Converts the (unsigned) part @ipart into a new self-contained MIME * part @opart. This may be a multipart/signed part, or a simple part * for enveloped types. * - * Returns: 0 for success or -1 for failure. + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -gint -camel_cipher_sign_sync (CamelCipherContext *context, - const gchar *userid, - CamelCipherHash hash, - CamelMimePart *ipart, - CamelMimePart *opart, - GCancellable *cancellable, - GError **error) +gboolean +camel_cipher_context_sign_sync (CamelCipherContext *context, + const gchar *userid, + CamelCipherHash hash, + CamelMimePart *ipart, + CamelMimePart *opart, + GCancellable *cancellable, + GError **error) { CamelCipherContextClass *class; - gint retval; + gboolean success; - g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1); + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE); class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); - g_return_val_if_fail (class->sign_sync != NULL, -1); + g_return_val_if_fail (class->sign_sync != NULL, FALSE); CIPHER_LOCK (context); - retval = class->sign_sync ( + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + CIPHER_UNLOCK (context); + return FALSE; + } + + camel_operation_push_message (cancellable, _("Signing message")); + + success = class->sign_sync ( context, userid, hash, ipart, opart, cancellable, error); - CAMEL_CHECK_GERROR (context, sign_sync, retval == 0, error); + CAMEL_CHECK_GERROR (context, sign_sync, success, error); + + camel_operation_pop_message (cancellable); CIPHER_UNLOCK (context); - return retval; + return success; +} + +/** + * camel_cipher_context_sign: + * @context: a #CamelCipherContext + * @userid: a private key to use to sign the stream + * @hash: preferred Message-Integrity-Check hash algorithm + * @ipart: input #CamelMimePart + * @opart: output #CamelMimePart + * @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 converts the (unsigned) part @ipart into a new + * self-contained MIME part @opart. This may be a multipart/signed part, + * or a simple part for enveloped types. + * + * When the operation is finished, @callback will be called. You can then + * call camel_cipher_context_sign_finish() to get the result of the operation. + * + * Since: 2.34 + **/ +void +camel_cipher_context_sign (CamelCipherContext *context, + const gchar *userid, + CamelCipherHash hash, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelCipherContextClass *class; + + g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context)); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_if_fail (class->sign != NULL); + + class->sign ( + context, userid, hash, ipart, opart, io_priority, + cancellable, callback, user_data); } /** - * camel_cipher_verify_sync: - * @context: Cipher Context - * @ipart: part to verify + * camel_cipher_context_sign_finish: + * @context: a #CamelCipherContext + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_cipher_context_sign(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_cipher_context_sign_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + CamelCipherContextClass *class; + + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_val_if_fail (class->sign_finish != NULL, FALSE); + + return class->sign_finish (context, result, error); +} + +/** + * camel_cipher_context_verify_sync: + * @context: a #CamelCipherContext + * @ipart: the #CamelMimePart to verify * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * - * Verifies the signature. If @istream is a clearsigned stream, - * you should pass %NULL as the sigstream parameter. Otherwise - * @sigstream is assumed to be the signature stream and is used to - * verify the integirity of the @istream. + * Verifies the signature. * - * Returns: a CamelCipherValidity structure containing information - * about the integrity of the input stream or %NULL on failure to - * execute at all. + * Returns: a #CamelCipherValidity structure containing information + * about the integrity of the input stream, or %NULL on failure to + * execute at all **/ CamelCipherValidity * -camel_cipher_verify_sync (CamelCipherContext *context, - CamelMimePart *ipart, - GCancellable *cancellable, - GError **error) +camel_cipher_context_verify_sync (CamelCipherContext *context, + CamelMimePart *ipart, + GCancellable *cancellable, + GError **error) { CamelCipherContextClass *class; CamelCipherValidity *valid; g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL); + g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), NULL); class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); g_return_val_if_fail (class->verify_sync != NULL, NULL); CIPHER_LOCK (context); + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + CIPHER_UNLOCK (context); + return NULL; + } + valid = class->verify_sync (context, ipart, cancellable, error); CAMEL_CHECK_GERROR (context, verify_sync, valid != NULL, error); @@ -361,162 +942,542 @@ camel_cipher_verify_sync (CamelCipherContext *context, } /** - * camel_cipher_encrypt_sync: - * @context: Cipher Context - * @userid: key id (or email address) to use when signing, or NULL to not sign. - * @recipients: an array of recipient key ids and/or email addresses - * @ipart: cleartext input stream - * @opart: ciphertext output stream + * camel_cipher_context_verify: + * @context: a #CamelCipherContext + * @ipart: the #CamelMimePart to verify + * @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 verifies the signature. + * + * When the operation is finished, @callback will be called. You can + * then call camel_cipher_context_verify_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_cipher_context_verify (CamelCipherContext *context, + CamelMimePart *ipart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelCipherContextClass *class; + + g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context)); + g_return_if_fail (CAMEL_IS_MIME_PART (ipart)); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_if_fail (class->verify != NULL); + + class->verify ( + context, ipart, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_cipher_context_verify_finish: + * @context: a #CamelCipherContext + * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * - * Encrypts (and optionally signs) the cleartext input stream and - * writes the resulting ciphertext to the output stream. + * Finishes the operation started with camel_cipher_context_verify(). * - * Returns: 0 for success or -1 for failure. + * Returns: a #CamelCipherValidity structure containing information + * about the integrity of the input stream, or %NULL on failure to + * execute at all + * + * Since: 2.34 **/ -gint -camel_cipher_encrypt_sync (CamelCipherContext *context, - const gchar *userid, - GPtrArray *recipients, - CamelMimePart *ipart, - CamelMimePart *opart, - GCancellable *cancellable, - GError **error) +CamelCipherValidity * +camel_cipher_context_verify_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + CamelCipherContextClass *class; + + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (context), NULL); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_val_if_fail (class->verify_finish != NULL, NULL); + + return class->verify_finish (context, result, error); +} + +/** + * camel_cipher_context_encrypt_sync: + * @context: a #CamelCipherContext + * @userid: key ID (or email address) to use when signing, or %NULL to not sign + * @recipients: an array of recipient key IDs and/or email addresses + * @ipart: clear-text #CamelMimePart + * @opart: cipher-text #CamelMimePart + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Encrypts (and optionally signs) the clear-text @ipart and writes the + * resulting cipher-text to @opart. + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_cipher_context_encrypt_sync (CamelCipherContext *context, + const gchar *userid, + GPtrArray *recipients, + CamelMimePart *ipart, + CamelMimePart *opart, + GCancellable *cancellable, + GError **error) { CamelCipherContextClass *class; - gint retval; + gboolean success; - g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1); + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE); + g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), FALSE); + g_return_val_if_fail (CAMEL_IS_MIME_PART (opart), FALSE); class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); - g_return_val_if_fail (class->encrypt_sync != NULL, -1); + g_return_val_if_fail (class->encrypt_sync != NULL, FALSE); CIPHER_LOCK (context); - retval = class->encrypt_sync ( + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + CIPHER_UNLOCK (context); + return FALSE; + } + + camel_operation_push_message (cancellable, _("Encrypting message")); + + success = class->encrypt_sync ( context, userid, recipients, ipart, opart, cancellable, error); - CAMEL_CHECK_GERROR (context, encrypt_sync, retval == 0, error); + CAMEL_CHECK_GERROR (context, encrypt_sync, success, error); + + camel_operation_pop_message (cancellable); CIPHER_UNLOCK (context); - return retval; + return success; } /** - * camel_cipher_decrypt_sync: - * @context: - * @ipart: - * @opart: + * camel_cipher_context_encrypt: + * @context: a #CamelCipherContext + * @userid: key id (or email address) to use when signing, or %NULL to not sign + * @recipients: an array of recipient key IDs and/or email addresses + * @ipart: clear-text #CamelMimePart + * @opart: cipher-text #CamelMimePart + * @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 encrypts (and optionally signs) the clear-text @ipart and + * writes the resulting cipher-text to @opart. + * + * When the operation is finished, @callback will be called. You can + * then call camel_cipher_context_encrypt_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_cipher_context_encrypt (CamelCipherContext *context, + const gchar *userid, + GPtrArray *recipients, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelCipherContextClass *class; + + g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context)); + g_return_if_fail (CAMEL_IS_MIME_PART (ipart)); + g_return_if_fail (CAMEL_IS_MIME_PART (opart)); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_if_fail (class->encrypt != NULL); + + class->encrypt ( + context, userid, recipients, ipart, opart, + io_priority, cancellable, callback, user_data); +} + +/** + * camel_cipher_context_encrypt_finish: + * @context: a #CamelCipherContext + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_cipher_context_encrypt(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_cipher_context_encrypt_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + CamelCipherContextClass *class; + + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_val_if_fail (class->encrypt_finish != NULL, FALSE); + + return class->encrypt_finish (context, result, error); +} + +/** + * camel_cipher_context_decrypt_sync: + * @context: a #CamelCipherContext + * @ipart: cipher-text #CamelMimePart + * @opart: clear-text #CamelMimePart * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Decrypts @ipart into @opart. * - * Returns: A validity/encryption status. + * Returns: a validity/encryption status, or %NULL on error + * + * Since: 2.34 **/ CamelCipherValidity * -camel_cipher_decrypt_sync (CamelCipherContext *context, - CamelMimePart *ipart, - CamelMimePart *opart, - GCancellable *cancellable, - GError **error) +camel_cipher_context_decrypt_sync (CamelCipherContext *context, + CamelMimePart *ipart, + CamelMimePart *opart, + GCancellable *cancellable, + GError **error) { CamelCipherContextClass *class; CamelCipherValidity *valid; g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL); + g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), NULL); + g_return_val_if_fail (CAMEL_IS_MIME_PART (opart), NULL); class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); g_return_val_if_fail (class->decrypt_sync != NULL, NULL); CIPHER_LOCK (context); + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + CIPHER_UNLOCK (context); + return NULL; + } + + camel_operation_push_message (cancellable, _("Decrypting message")); + valid = class->decrypt_sync ( context, ipart, opart, cancellable, error); CAMEL_CHECK_GERROR (context, decrypt_sync, valid != NULL, error); + camel_operation_pop_message (cancellable); + CIPHER_UNLOCK (context); return valid; } /** - * camel_cipher_import_keys_sync: - * @context: Cipher Context - * @istream: input stream (containing keys) + * camel_cipher_context_decrypt: + * @context: a #CamelCipherContext + * @ipart: cipher-text #CamelMimePart + * @opart: clear-text #CamelMimePart + * @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 decrypts @ipart into @opart. + * + * When the operation is finished, @callback will be called. You can + * then call camel_cipher_context_decrypt_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_cipher_context_decrypt (CamelCipherContext *context, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelCipherContextClass *class; + + g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context)); + g_return_if_fail (CAMEL_IS_MIME_PART (ipart)); + g_return_if_fail (CAMEL_IS_MIME_PART (opart)); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_if_fail (class->decrypt != NULL); + + class->decrypt ( + context, ipart, opart, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_cipher_context_decrypt_finish: + * @context: a #CamelCipherContext + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_cipher_context_decrypt(). + * + * Returns: a validity/encryption status, or %NULL on error + * + * Since: 2.34 + **/ +CamelCipherValidity * +camel_cipher_context_decrypt_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + CamelCipherContextClass *class; + + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_val_if_fail (class->decrypt_finish != NULL, NULL); + + return class->decrypt_finish (context, result, error); +} + +/** + * camel_cipher_context_import_keys_sync: + * @context: a #CamelCipherContext + * @istream: an input stream containing keys * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Imports a stream of keys/certificates contained within @istream - * into the key/certificate database controlled by @ctx. + * into the key/certificate database controlled by @context. * - * Returns: 0 on success or -1 on fail. + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -gint -camel_cipher_import_keys_sync (CamelCipherContext *context, - CamelStream *istream, - GCancellable *cancellable, - GError **error) +gboolean +camel_cipher_context_import_keys_sync (CamelCipherContext *context, + CamelStream *istream, + GCancellable *cancellable, + GError **error) { CamelCipherContextClass *class; - gint retval; + gboolean success; - g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1); - g_return_val_if_fail (CAMEL_IS_STREAM (istream), -1); + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE); + g_return_val_if_fail (CAMEL_IS_STREAM (istream), FALSE); class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); - g_return_val_if_fail (class->import_keys_sync != NULL, -1); + g_return_val_if_fail (class->import_keys_sync != NULL, FALSE); - retval = class->import_keys_sync ( + success = class->import_keys_sync ( context, istream, cancellable, error); - CAMEL_CHECK_GERROR (context, import_keys_sync, retval == 0, error); + CAMEL_CHECK_GERROR (context, import_keys_sync, success, error); + + return success; +} + +/** + * camel_cipher_context_import_keys: + * @context: a #CamelCipherContext + * @istream: an input stream containing keys + * @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 imports a stream of keys/certificates contained within + * @istream into the key/certificate database controlled by @context. + * + * When the operation is finished, @callback will be called. You can + * then call camel_cipher_context_import_keys_finish() to get the result + * of the operation. + * + * Since: 2.34 + **/ +void +camel_cipher_context_import_keys (CamelCipherContext *context, + CamelStream *istream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelCipherContextClass *class; + + g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context)); + g_return_if_fail (CAMEL_IS_STREAM (istream)); - return retval; + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_if_fail (class->import_keys != NULL); + + class->import_keys ( + context, istream, io_priority, + cancellable, callback, user_data); } /** - * camel_cipher_export_keys_sync: - * @context: Cipher Context - * @keys: an array of key ids - * @ostream: output stream + * camel_cipher_context_import_keys_finish: + * @context: a #CamelCipherContext + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_cipher_context_import_keys(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_cipher_context_import_keys_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + CamelCipherContextClass *class; + + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_val_if_fail (class->import_keys_finish != NULL, FALSE); + + return class->import_keys_finish (context, result, error); +} + +/** + * camel_cipher_context_export_keys_sync: + * @context: a #CamelCipherContext + * @keys: an array of key IDs + * @ostream: an output stream * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Exports the keys/certificates in @keys to the stream @ostream from - * the key/certificate database controlled by @ctx. + * the key/certificate database controlled by @context. * - * Returns: 0 on success or -1 on fail. + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -gint -camel_cipher_export_keys_sync (CamelCipherContext *context, - GPtrArray *keys, - CamelStream *ostream, - GCancellable *cancellable, - GError **error) +gboolean +camel_cipher_context_export_keys_sync (CamelCipherContext *context, + GPtrArray *keys, + CamelStream *ostream, + GCancellable *cancellable, + GError **error) { CamelCipherContextClass *class; - gint retval; + gboolean success; - g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1); - g_return_val_if_fail (CAMEL_IS_STREAM (ostream), -1); - g_return_val_if_fail (keys != NULL, -1); + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE); + g_return_val_if_fail (keys != NULL, FALSE); + g_return_val_if_fail (CAMEL_IS_STREAM (ostream), FALSE); class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); - g_return_val_if_fail (class->export_keys_sync != NULL, -1); + g_return_val_if_fail (class->export_keys_sync != NULL, FALSE); - retval = class->export_keys_sync ( + success = class->export_keys_sync ( context, keys, ostream, cancellable, error); - CAMEL_CHECK_GERROR (context, export_keys_sync, retval == 0, error); + CAMEL_CHECK_GERROR (context, export_keys_sync, success, error); + + return success; +} + +/** + * camel_cipher_context_export_keys: + * @context: a #CamelCipherContext + * @keys: an array of key IDs + * @ostream: an output stream + * @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 exports the keys/certificates in @keys to the stream + * @ostream from the key/certificate database controlled by @context. + * + * When the operation is finished, @callback will be called. You can then + * call camel_cipher_context_export_keys_finish() to get the result of the + * operation. + * + * Since: 2.34 + **/ +void +camel_cipher_context_export_keys (CamelCipherContext *context, + GPtrArray *keys, + CamelStream *ostream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelCipherContextClass *class; + + g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context)); + g_return_if_fail (keys != NULL); + g_return_if_fail (CAMEL_IS_STREAM (ostream)); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_if_fail (class->export_keys != NULL); + + class->export_keys ( + context, keys, ostream, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_cipher_context_export_keys_finish: + * @context: a #CamelCipherContext + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_cipher_context_export_keys(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_cipher_context_export_keys_finish (CamelCipherContext *context, + GAsyncResult *result, + GError **error) +{ + CamelCipherContextClass *class; + + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); + g_return_val_if_fail (class->export_keys_finish != NULL, FALSE); - return retval; + return class->export_keys_finish (context, result, error); } /* a couple of util functions */ CamelCipherHash -camel_cipher_id_to_hash (CamelCipherContext *context, - const gchar *id) +camel_cipher_context_id_to_hash (CamelCipherContext *context, + const gchar *id) { CamelCipherContextClass *class; @@ -532,8 +1493,8 @@ camel_cipher_id_to_hash (CamelCipherContext *context, } const gchar * -camel_cipher_hash_to_id (CamelCipherContext *context, - CamelCipherHash hash) +camel_cipher_context_hash_to_id (CamelCipherContext *context, + CamelCipherHash hash) { CamelCipherContextClass *class; diff --git a/camel/camel-cipher-context.h b/camel/camel-cipher-context.h index e3d231a..71da9d6 100644 --- a/camel/camel-cipher-context.h +++ b/camel/camel-cipher-context.h @@ -134,12 +134,14 @@ struct _CamelCipherContextClass { const gchar *encrypt_protocol; const gchar *key_protocol; + /* Non-Blocking Methods */ CamelCipherHash (*id_to_hash) (CamelCipherContext *context, const gchar *id); const gchar * (*hash_to_id) (CamelCipherContext *context, CamelCipherHash hash); - gint (*sign_sync) (CamelCipherContext *context, + /* Synchronous I/O Methods */ + gboolean (*sign_sync) (CamelCipherContext *context, const gchar *userid, CamelCipherHash hash, CamelMimePart *ipart, @@ -151,7 +153,7 @@ struct _CamelCipherContextClass { CamelMimePart *ipart, GCancellable *cancellable, GError **error); - gint (*encrypt_sync) (CamelCipherContext *context, + gboolean (*encrypt_sync) (CamelCipherContext *context, const gchar *userid, GPtrArray *recipients, CamelMimePart *ipart, @@ -164,26 +166,93 @@ struct _CamelCipherContextClass { CamelMimePart *opart, GCancellable *cancellable, GError **error); - gint (*import_keys_sync) (CamelCipherContext *context, + gboolean (*import_keys_sync) (CamelCipherContext *context, CamelStream *istream, GCancellable *cancellable, GError **error); - gint (*export_keys_sync) (CamelCipherContext *context, + gboolean (*export_keys_sync) (CamelCipherContext *context, GPtrArray *keys, CamelStream *ostream, GCancellable *cancellable, GError **error); + + /* Asynchronous I/O Methods (all have defaults) */ + void (*sign) (CamelCipherContext *context, + const gchar *userid, + CamelCipherHash hash, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*sign_finish) (CamelCipherContext *context, + GAsyncResult *result, + GError **error); + void (*verify) (CamelCipherContext *context, + CamelMimePart *ipart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelCipherValidity * + (*verify_finish) (CamelCipherContext *context, + GAsyncResult *result, + GError **error); + void (*encrypt) (CamelCipherContext *context, + const gchar *user_id, + GPtrArray *recipients, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*encrypt_finish) (CamelCipherContext *context, + GAsyncResult *result, + GError **error); + void (*decrypt) (CamelCipherContext *context, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelCipherValidity * + (*decrypt_finish) (CamelCipherContext *context, + GAsyncResult *result, + GError **error); + void (*import_keys) (CamelCipherContext *context, + CamelStream *istream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*import_keys_finish) (CamelCipherContext *context, + GAsyncResult *result, + GError **error); + void (*export_keys) (CamelCipherContext *context, + GPtrArray *keys, + CamelStream *ostream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*export_keys_finish) (CamelCipherContext *context, + GAsyncResult *result, + GError **error); }; GType camel_cipher_context_get_type (void); CamelCipherContext * camel_cipher_context_new (CamelSession *session); -CamelSession * camel_cipher_context_get_session (CamelCipherContext *context); +CamelSession * camel_cipher_context_get_session + (CamelCipherContext *context); /* cipher context util routines */ -CamelCipherHash camel_cipher_id_to_hash (CamelCipherContext *context, +CamelCipherHash camel_cipher_context_id_to_hash (CamelCipherContext *context, const gchar *id); -const gchar * camel_cipher_hash_to_id (CamelCipherContext *context, +const gchar * camel_cipher_context_hash_to_id (CamelCipherContext *context, CamelCipherHash hash); /* FIXME: @@ -192,41 +261,118 @@ const gchar * camel_cipher_hash_to_id (CamelCipherContext *context, to the cipher, etc etc. */ /* cipher routines */ -gint camel_cipher_sign_sync (CamelCipherContext *context, +gboolean camel_cipher_context_sign_sync (CamelCipherContext *context, const gchar *userid, CamelCipherHash hash, CamelMimePart *ipart, CamelMimePart *opart, GCancellable *cancellable, GError **error); +void camel_cipher_context_sign (CamelCipherContext *context, + const gchar *userid, + CamelCipherHash hash, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_cipher_context_sign_finish + (CamelCipherContext *context, + GAsyncResult *result, + GError **error); +CamelCipherValidity * + camel_cipher_context_verify_sync + (CamelCipherContext *context, + CamelMimePart *ipart, + GCancellable *cancellable, + GError **error); +void camel_cipher_context_verify (CamelCipherContext *context, + CamelMimePart *ipart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); CamelCipherValidity * - camel_cipher_verify_sync (CamelCipherContext *context, + camel_cipher_context_verify_finish + (CamelCipherContext *context, + GAsyncResult *result, + GError **error); +gboolean camel_cipher_context_encrypt_sync + (CamelCipherContext *context, + const gchar *userid, + GPtrArray *recipients, CamelMimePart *ipart, + CamelMimePart *opart, GCancellable *cancellable, GError **error); -gint camel_cipher_encrypt_sync (CamelCipherContext *context, +void camel_cipher_context_encrypt (CamelCipherContext *context, const gchar *userid, GPtrArray *recipients, CamelMimePart *ipart, CamelMimePart *opart, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_cipher_context_encrypt_finish + (CamelCipherContext *context, + GAsyncResult *result, GError **error); CamelCipherValidity * - camel_cipher_decrypt_sync (CamelCipherContext *context, + camel_cipher_context_decrypt_sync + (CamelCipherContext *context, CamelMimePart *ipart, CamelMimePart *opart, GCancellable *cancellable, GError **error); +void camel_cipher_context_decrypt (CamelCipherContext *context, + CamelMimePart *ipart, + CamelMimePart *opart, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelCipherValidity * + camel_cipher_context_decrypt_finish + (CamelCipherContext *context, + GAsyncResult *result, + GError **error); /* key/certificate routines */ -gint camel_cipher_import_keys_sync (CamelCipherContext *context, +gboolean camel_cipher_context_import_keys_sync + (CamelCipherContext *context, CamelStream *istream, GCancellable *cancellable, GError **error); -gint camel_cipher_export_keys_sync (CamelCipherContext *context, +void camel_cipher_context_import_keys + (CamelCipherContext *context, + CamelStream *istream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_cipher_context_import_keys_finish + (CamelCipherContext *context, + GAsyncResult *result, + GError **error); +gboolean camel_cipher_context_export_keys_sync + (CamelCipherContext *context, + GPtrArray *keys, + CamelStream *ostream, + GCancellable *cancellable, + GError **error); +void camel_cipher_context_export_keys + (CamelCipherContext *context, GPtrArray *keys, CamelStream *ostream, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_cipher_context_export_keys_finish + (CamelCipherContext *context, + GAsyncResult *result, GError **error); /* CamelCipherValidity utility functions */ diff --git a/camel/camel-data-wrapper.c b/camel/camel-data-wrapper.c index 4969f78..a9f9a0b 100644 --- a/camel/camel-data-wrapper.c +++ b/camel/camel-data-wrapper.c @@ -40,10 +40,29 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_DATA_WRAPPER, CamelDataWrapperPrivate)) +typedef struct _AsyncContext AsyncContext; + struct _CamelDataWrapperPrivate { GStaticMutex stream_lock; }; +struct _AsyncContext { + /* arguments */ + CamelStream *stream; + + /* results */ + gssize bytes_written; +}; + +static void +async_context_free (AsyncContext *async_context) +{ + if (async_context->stream != NULL) + g_object_unref (async_context->stream); + + g_slice_free (AsyncContext, async_context); +} + G_DEFINE_TYPE (CamelDataWrapper, camel_data_wrapper, CAMEL_TYPE_OBJECT) static void @@ -130,8 +149,17 @@ data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper, } camel_data_wrapper_lock (data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_data_wrapper_unlock ( + data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); + return -1; + } + if (camel_stream_reset (data_wrapper->stream, error) == -1) { - camel_data_wrapper_unlock (data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); + camel_data_wrapper_unlock ( + data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); return -1; } @@ -191,7 +219,7 @@ data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper, return ret; } -static gint +static gboolean data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, @@ -202,7 +230,217 @@ data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper, data_wrapper->stream = g_object_ref (stream); - return 0; + return TRUE; +} + +static void +data_wrapper_write_to_stream_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->bytes_written = + camel_data_wrapper_write_to_stream_sync ( + CAMEL_DATA_WRAPPER (object), + async_context->stream, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->stream = g_object_ref (stream); + + simple = g_simple_async_result_new ( + G_OBJECT (data_wrapper), callback, + user_data, data_wrapper_write_to_stream); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, data_wrapper_write_to_stream_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gssize +data_wrapper_write_to_stream_finish (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (data_wrapper), + data_wrapper_write_to_stream), -1); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return -1; + + return async_context->bytes_written; +} + +static void +data_wrapper_decode_to_stream_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->bytes_written = + camel_data_wrapper_decode_to_stream_sync ( + CAMEL_DATA_WRAPPER (object), + async_context->stream, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->stream = g_object_ref (stream); + + simple = g_simple_async_result_new ( + G_OBJECT (data_wrapper), callback, + user_data, data_wrapper_decode_to_stream); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, data_wrapper_decode_to_stream_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gssize +data_wrapper_decode_to_stream_finish (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (data_wrapper), + data_wrapper_decode_to_stream), -1); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return -1; + + return async_context->bytes_written; +} + +static void +data_wrapper_construct_from_stream_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_data_wrapper_construct_from_stream_sync ( + CAMEL_DATA_WRAPPER (object), async_context->stream, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->stream = g_object_ref (stream); + + simple = g_simple_async_result_new ( + G_OBJECT (data_wrapper), callback, user_data, + data_wrapper_construct_from_stream); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, data_wrapper_construct_from_stream_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +data_wrapper_construct_from_stream_finish (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (data_wrapper), + data_wrapper_construct_from_stream), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); } static void @@ -221,9 +459,17 @@ camel_data_wrapper_class_init (CamelDataWrapperClass *class) 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_stream = data_wrapper_write_to_stream; + class->write_to_stream_finish = data_wrapper_write_to_stream_finish; + class->decode_to_stream = data_wrapper_decode_to_stream; + class->decode_to_stream_finish = data_wrapper_decode_to_stream_finish; + class->construct_from_stream = data_wrapper_construct_from_stream; + class->construct_from_stream_finish = data_wrapper_construct_from_stream_finish; } static void @@ -254,7 +500,7 @@ camel_data_wrapper_new (void) /** * camel_data_wrapper_set_mime_type: - * @data_wrapper: a #CamelDataWrapper object + * @data_wrapper: a #CamelDataWrapper * @mime_type: a MIME type * * This sets the data wrapper's MIME type. @@ -282,7 +528,7 @@ camel_data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper, /** * camel_data_wrapper_get_mime_type: - * @data_wrapper: a #CamelDataWrapper object + * @data_wrapper: a #CamelDataWrapper * * Returns: the MIME type which must be freed by the caller **/ @@ -301,7 +547,7 @@ camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper) /** * camel_data_wrapper_get_mime_type_field: - * @data_wrapper: a #CamelDataWrapper object + * @data_wrapper: a #CamelDataWrapper * * Returns: the parsed form of the data wrapper's MIME type **/ @@ -320,7 +566,7 @@ camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper) /** * camel_data_wrapper_set_mime_type_field: - * @data_wrapper: a #CamelDataWrapper object + * @data_wrapper: a #CamelDataWrapper * @mime_type: a #CamelContentType * * This sets the data wrapper's MIME type. It suffers from the same @@ -343,7 +589,7 @@ camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper, /** * camel_data_wrapper_is_offline: - * @data_wrapper: a #CamelDataWrapper object + * @data_wrapper: a #CamelDataWrapper * * Returns: whether @data_wrapper is "offline" (data stored * remotely) or not. Some optional code paths may choose to not @@ -363,18 +609,77 @@ camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper) } /** + * camel_data_wrapper_lock: + * @data_wrapper: a #CamelDataWrapper + * @lock: lock type to lock + * + * Locks #data_wrapper's #lock. Unlock it with camel_data_wrapper_unlock(). + * + * Since: 2.32 + **/ +void +camel_data_wrapper_lock (CamelDataWrapper *data_wrapper, + CamelDataWrapperLock lock) +{ + g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); + + switch (lock) { + case CAMEL_DATA_WRAPPER_STREAM_LOCK: + g_static_mutex_lock (&data_wrapper->priv->stream_lock); + break; + default: + g_return_if_reached (); + } +} + +/** + * camel_data_wrapper_unlock: + * @data_wrapper: a #CamelDataWrapper + * @lock: lock type to unlock + * + * Unlocks #data_wrapper's #lock, previously locked with + * camel_data_wrapper_lock(). + * + * Since: 2.32 + **/ +void +camel_data_wrapper_unlock (CamelDataWrapper *data_wrapper, + CamelDataWrapperLock lock) +{ + g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); + + switch (lock) { + case CAMEL_DATA_WRAPPER_STREAM_LOCK: + g_static_mutex_unlock (&data_wrapper->priv->stream_lock); + break; + default: + g_return_if_reached (); + } +} + +/** * camel_data_wrapper_write_to_stream_sync: - * @data_wrapper: a #CamelDataWrapper object + * @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 + * 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. + * 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 fail + * Returns: the number of bytes written, or %-1 on error + * + * Since: 2.34 **/ gssize camel_data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper, @@ -400,15 +705,94 @@ camel_data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper, } /** + * 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: 2.34 + **/ +void +camel_data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelDataWrapperClass *class; + + g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); + g_return_if_fail (CAMEL_IS_STREAM (stream)); + + class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); + g_return_if_fail (class->write_to_stream != NULL); + + class->write_to_stream ( + data_wrapper, stream, io_priority, + cancellable, callback, user_data); +} + +/** + * 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: 2.34 + **/ +gssize +camel_data_wrapper_write_to_stream_finish (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error) +{ + CamelDataWrapperClass *class; + + g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), -1); + + class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); + g_return_val_if_fail (class->write_to_stream_finish != NULL, -1); + + return class->write_to_stream_finish (data_wrapper, result, error); +} + +/** * camel_data_wrapper_decode_to_stream_sync: - * @data_wrapper: a #CamelDataWrapper object + * @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. * - * Returns: the number of bytes written, or %-1 on fail + * + * + * 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: 2.34 **/ gssize camel_data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper, @@ -434,24 +818,92 @@ camel_data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper, } /** + * 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: 2.34 + **/ +void +camel_data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelDataWrapperClass *class; + + g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); + g_return_if_fail (CAMEL_IS_STREAM (stream)); + + class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); + g_return_if_fail (class->decode_to_stream != NULL); + + class->decode_to_stream ( + data_wrapper, stream, io_priority, + cancellable, callback, user_data); +} + +/** + * 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: 2.34 + **/ +gssize +camel_data_wrapper_decode_to_stream_finish (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error) +{ + CamelDataWrapperClass *class; + + g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), -1); + + class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); + g_return_val_if_fail (class->decode_to_stream_finish != NULL, -1); + + return class->decode_to_stream_finish (data_wrapper, result, error); +} + +/** * camel_data_wrapper_construct_from_stream_sync: - * @data_wrapper: a #CamelDataWrapper object + * @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 supplied @stream. + * Constructs the content of @data_wrapper from the given @stream. + * + * Returns: %TRUE on success, %FALSE on error * - * Returns: %0 on success or %-1 on fail + * Since: 2.34 **/ -gint +gboolean camel_data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelDataWrapperClass *class; - gint retval; + gboolean success; g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1); g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1); @@ -459,59 +911,78 @@ camel_data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper, class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); g_return_val_if_fail (class->construct_from_stream_sync != NULL, -1); - retval = class->construct_from_stream_sync ( + success = class->construct_from_stream_sync ( data_wrapper, stream, cancellable, error); CAMEL_CHECK_GERROR ( - data_wrapper, construct_from_stream_sync, retval == 0, error); + data_wrapper, construct_from_stream_sync, success, error); - return retval; + return success; } /** - * camel_data_wrapper_lock: + * camel_data_wrapper_construct_from_stream: * @data_wrapper: a #CamelDataWrapper - * @lock: lock type to lock + * @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 * - * Locks #data_wrapper's #lock. Unlock it with camel_data_wrapper_unlock(). + * Asynchronously constructs the content of @data_wrapper from the given + * @stream. * - * Since: 2.32 + * 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: 2.34 **/ void -camel_data_wrapper_lock (CamelDataWrapper *data_wrapper, - CamelDataWrapperLock lock) +camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + CamelDataWrapperClass *class; + g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); + g_return_if_fail (CAMEL_IS_STREAM (stream)); - switch (lock) { - case CAMEL_DATA_WRAPPER_STREAM_LOCK: - g_static_mutex_lock (&data_wrapper->priv->stream_lock); - break; - default: - g_return_if_reached (); - } + class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); + g_return_if_fail (class->construct_from_stream != NULL); + + class->construct_from_stream ( + data_wrapper, stream, io_priority, + cancellable, callback, user_data); } /** - * camel_data_wrapper_unlock: + * camel_data_wrapper_construct_from_stream_finish: * @data_wrapper: a #CamelDataWrapper - * @lock: lock type to unlock + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL * - * Unlocks #data_wrapper's #lock, previously locked with - * camel_data_wrapper_lock(). + * Finishes the operation started with + * camel_data_wrapper_construct_from_stream(). * - * Since: 2.32 + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -void -camel_data_wrapper_unlock (CamelDataWrapper *data_wrapper, - CamelDataWrapperLock lock) +gboolean +camel_data_wrapper_construct_from_stream_finish (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error) { - g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper)); + CamelDataWrapperClass *class; - switch (lock) { - case CAMEL_DATA_WRAPPER_STREAM_LOCK: - g_static_mutex_unlock (&data_wrapper->priv->stream_lock); - break; - default: - g_return_if_reached (); - } + g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper); + g_return_val_if_fail (class->construct_from_stream_finish != NULL, FALSE); + + return class->construct_from_stream_finish (data_wrapper, result, error); } diff --git a/camel/camel-data-wrapper.h b/camel/camel-data-wrapper.h index adde135..d363456 100644 --- a/camel/camel-data-wrapper.h +++ b/camel/camel-data-wrapper.h @@ -83,6 +83,7 @@ struct _CamelDataWrapper { struct _CamelDataWrapperClass { CamelObjectClass parent_class; + /* Non-Blocking Methods */ void (*set_mime_type) (CamelDataWrapper *data_wrapper, const gchar *mime_type); gchar * (*get_mime_type) (CamelDataWrapper *data_wrapper); @@ -92,6 +93,7 @@ struct _CamelDataWrapperClass { CamelContentType *mime_type_field); gboolean (*is_offline) (CamelDataWrapper *data_wrapper); + /* Synchronous I/O Methods */ gssize (*write_to_stream_sync) (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, @@ -100,11 +102,44 @@ struct _CamelDataWrapperClass { CamelStream *stream, GCancellable *cancellable, GError **error); - gint (*construct_from_stream_sync) + gboolean (*construct_from_stream_sync) (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error); + + /* Asyncrhonous I/O Methods (all have defaults) */ + void (*write_to_stream) (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gssize (*write_to_stream_finish) + (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error); + void (*decode_to_stream) (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gssize (*decode_to_stream_finish) + (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error); + void (*construct_from_stream) + (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*construct_from_stream_finish) + (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error); }; GType camel_data_wrapper_get_type (void); @@ -120,25 +155,59 @@ void camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper, CamelContentType *mime_type); gboolean camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper); +void camel_data_wrapper_lock (CamelDataWrapper *data_wrapper, + CamelDataWrapperLock lock); +void camel_data_wrapper_unlock (CamelDataWrapper *data_wrapper, + CamelDataWrapperLock lock); + gssize camel_data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error); +void camel_data_wrapper_write_to_stream + (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gssize camel_data_wrapper_write_to_stream_finish + (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error); gssize camel_data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error); -gint camel_data_wrapper_construct_from_stream_sync +void camel_data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gssize camel_data_wrapper_decode_to_stream_finish + (CamelDataWrapper *data_wrapper, + GAsyncResult *result, + GError **error); +gboolean camel_data_wrapper_construct_from_stream_sync + (CamelDataWrapper *data_wrapper, + CamelStream *stream, + GCancellable *cancellable, + GError **error); +void camel_data_wrapper_construct_from_stream + (CamelDataWrapper *data_wrapper, + CamelStream *stream, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_data_wrapper_construct_from_stream_finish + (CamelDataWrapper *data_wrapper, + GAsyncResult *result, GError **error); -void camel_data_wrapper_lock (CamelDataWrapper *data_wrapper, - CamelDataWrapperLock lock); -void camel_data_wrapper_unlock (CamelDataWrapper *data_wrapper, - CamelDataWrapperLock lock); G_END_DECLS diff --git a/camel/camel-db.h b/camel/camel-db.h index a2d7148..bf047ff 100644 --- a/camel/camel-db.h +++ b/camel/camel-db.h @@ -47,7 +47,7 @@ typedef struct _CamelDBPrivate CamelDBPrivate; * * Since: 2.24 **/ -typedef gint (*CamelDBCollate)(gpointer ,int,gconstpointer ,int,gconstpointer ); +typedef gint (*CamelDBCollate)(gpointer, gint, gconstpointer, gint, gconstpointer ); /** * CamelDB: diff --git a/camel/camel-disco-diary.c b/camel/camel-disco-diary.c index 530d386..9c48a6a 100644 --- a/camel/camel-disco-diary.c +++ b/camel/camel-disco-diary.c @@ -300,7 +300,8 @@ camel_disco_diary_replay (CamelDiscoDiary *diary, g_return_if_fail (size != 0); rewind (diary->file); - camel_operation_start (cancellable, _("Resynchronizing with server")); + camel_operation_push_message ( + cancellable, _("Resynchronizing with server")); while (local_error == NULL) { camel_operation_progress ( @@ -390,8 +391,8 @@ camel_disco_diary_replay (CamelDiscoDiary *diary, } camel_folder_transfer_messages_to_sync ( - source, uids, destination, &ret_uids, - delete_originals, cancellable, &local_error); + source, uids, destination, delete_originals, + &ret_uids, cancellable, &local_error); if (ret_uids) { for (i = 0; i < uids->len; i++) { @@ -410,7 +411,7 @@ camel_disco_diary_replay (CamelDiscoDiary *diary, } lose: - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); /* Close folders */ g_hash_table_foreach ( diff --git a/camel/camel-disco-folder.c b/camel/camel-disco-folder.c index 6fd9009..65e1031 100644 --- a/camel/camel-disco-folder.c +++ b/camel/camel-disco-folder.c @@ -62,7 +62,7 @@ cdf_sync_offline (CamelSession *session, CamelSessionThreadMsg *mm) struct _cdf_sync_msg *m = (struct _cdf_sync_msg *)mm; gint i; - camel_operation_start ( + camel_operation_push_message ( mm->cancellable, _("Downloading new messages for offline mode")); @@ -81,7 +81,7 @@ cdf_sync_offline (CamelSession *session, CamelSessionThreadMsg *mm) NULL, &mm->error); } - camel_operation_end (mm->cancellable); + camel_operation_pop_message (mm->cancellable); } static void @@ -203,7 +203,7 @@ disco_expunge_uids (CamelFolder *folder, static gboolean disco_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -336,8 +336,8 @@ static gboolean disco_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { @@ -385,7 +385,7 @@ disco_prepare_for_offline (CamelDiscoFolder *disco_folder, gint i; gboolean success = TRUE; - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Preparing folder '%s' for offline"), camel_folder_get_full_name (folder)); @@ -395,7 +395,7 @@ disco_prepare_for_offline (CamelDiscoFolder *disco_folder, uids = camel_folder_get_uids (folder); if (!uids) { - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return FALSE; } @@ -411,7 +411,7 @@ disco_prepare_for_offline (CamelDiscoFolder *disco_folder, else camel_folder_free_uids (folder, uids); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return success; } diff --git a/camel/camel-filter-driver.c b/camel/camel-filter-driver.c index 9a4a77c..2c876cd 100644 --- a/camel/camel-filter-driver.c +++ b/camel/camel-filter-driver.c @@ -506,8 +506,8 @@ do_copy (struct _ESExp *f, gint argc, struct _ESExpResult **argv, CamelFilterDri g_ptr_array_add (uids, (gchar *) p->uid); /* FIXME Pass a GCancellable */ camel_folder_transfer_messages_to_sync ( - p->source, uids, outbox, NULL, - FALSE, NULL, &p->error); + p->source, uids, outbox, FALSE, + NULL, NULL, &p->error); g_ptr_array_free (uids, TRUE); } else { if (p->message == NULL) @@ -567,8 +567,8 @@ do_move (struct _ESExp *f, gint argc, struct _ESExpResult **argv, CamelFilterDri g_ptr_array_add (uids, (gchar *) p->uid); /* FIXME Pass a GCancellable */ camel_folder_transfer_messages_to_sync ( - p->source, uids, outbox, NULL, - last, NULL, &p->error); + p->source, uids, outbox, last, + NULL, NULL, &p->error); g_ptr_array_free (uids, TRUE); } else { if (p->message == NULL) @@ -877,8 +877,8 @@ pipe_to_system (struct _ESExp *f, gint argc, struct _ESExpResult **argv, CamelFi g_object_unref (mem); message = camel_mime_message_new (); - if (camel_mime_part_construct_from_parser_sync ( - (CamelMimePart *) message, parser, NULL, NULL) == -1) { + if (!camel_mime_part_construct_from_parser_sync ( + (CamelMimePart *) message, parser, NULL, NULL)) { gint err = camel_mime_parser_errno (parser); g_set_error ( &p->error, G_IO_ERROR, @@ -1309,8 +1309,8 @@ camel_filter_driver_filter_mbox (CamelFilterDriver *driver, message = camel_mime_message_new (); mime_part = CAMEL_MIME_PART (message); - if (camel_mime_part_construct_from_parser_sync ( - mime_part, mp, cancellable, error) == -1) { + if (!camel_mime_part_construct_from_parser_sync ( + mime_part, mp, cancellable, error)) { report_status (driver, CAMEL_FILTER_STATUS_END, 100, _("Failed on message %d"), i); g_object_unref (message); goto fail; @@ -1672,7 +1672,7 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver, g_ptr_array_add (uids, (gchar *) p->uid); camel_folder_transfer_messages_to_sync ( p->source, uids, p->defaultfolder, - NULL, FALSE, cancellable, &p->error); + FALSE, NULL, cancellable, &p->error); g_ptr_array_free (uids, TRUE); } else { if (p->message == NULL) { diff --git a/camel/camel-folder-search.c b/camel/camel-folder-search.c index 399980e..05c1351 100644 --- a/camel/camel-folder-search.c +++ b/camel/camel-folder-search.c @@ -1432,7 +1432,8 @@ match_words_1message (CamelDataWrapper *object, struct _camel_search_words *word byte_array = g_byte_array_new (); stream = camel_stream_mem_new_with_byte_array (byte_array); - /* FIXME: The match should be part of a stream op */ + /* FIXME The match should be part of a stream op */ + /* FIXME Pass a GCancellable and GError here. */ camel_data_wrapper_decode_to_stream_sync ( containee, stream, NULL, NULL); camel_stream_write (stream, "", 1, NULL, NULL); diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c index 489d1c0..1382fd5 100644 --- a/camel/camel-folder-summary.c +++ b/camel/camel-folder-summary.c @@ -4043,6 +4043,7 @@ summary_build_content_info_message (CamelFolderSummary *s, CamelMessageInfo *msg CAMEL_STREAM_FILTER (p->filter_stream), p->filter_index); + /* FIXME Pass a GCancellable and GError here. */ camel_data_wrapper_decode_to_stream_sync ( containee, p->filter_stream, NULL, NULL); camel_stream_flush (p->filter_stream, NULL, NULL); @@ -4452,7 +4453,7 @@ camel_message_info_new (CamelFolderSummary *s) * * Reference an info. **/ -void +gpointer camel_message_info_ref (gpointer o) { CamelMessageInfo *mi = o; @@ -4468,6 +4469,8 @@ camel_message_info_ref (gpointer o) mi->refcount++; GLOBAL_INFO_UNLOCK (info); } + + return o; } /** diff --git a/camel/camel-folder-summary.h b/camel/camel-folder-summary.h index 5dcd835..c4e565f 100644 --- a/camel/camel-folder-summary.h +++ b/camel/camel-folder-summary.h @@ -435,7 +435,7 @@ void camel_tag_list_free (CamelTag **list); /* Summary may be null */ /* Use anonymous pointers to avoid tons of cast crap */ gpointer camel_message_info_new (CamelFolderSummary *summary); -void camel_message_info_ref (gpointer info); +gpointer camel_message_info_ref (gpointer info); CamelMessageInfo *camel_message_info_new_from_header (CamelFolderSummary *summary, struct _camel_header_raw *header); void camel_message_info_free (gpointer info); gpointer camel_message_info_clone (gconstpointer info); diff --git a/camel/camel-folder.c b/camel/camel-folder.c index 2863942..66cda68 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -49,6 +49,8 @@ #define d(x) #define w(x) +typedef struct _AsyncContext AsyncContext; + struct _CamelFolderPrivate { GStaticRecMutex lock; GStaticMutex change_lock; @@ -64,6 +66,20 @@ struct _CamelFolderPrivate { gchar *description; }; +struct _AsyncContext { + /* arguments */ + CamelMimeMessage *message; /* also a result */ + CamelMessageInfo *info; + CamelFolder *destination; + GPtrArray *message_uids; + gchar *message_uid; /* also a result */ + gboolean delete_originals; + gboolean expunge; + + /* results */ + GPtrArray *transferred_uids; +}; + struct _CamelFolderChangeInfoPrivate { GHashTable *uid_stored; /* what we have stored, which array they're in */ GHashTable *uid_source; /* used to create unique lists */ @@ -102,6 +118,37 @@ static guint signals[LAST_SIGNAL]; G_DEFINE_ABSTRACT_TYPE (CamelFolder, camel_folder, CAMEL_TYPE_OBJECT) static void +async_context_free (AsyncContext *async_context) +{ + if (async_context->message != NULL) + g_object_unref (async_context->message); + + /* XXX This is actually an unref. Good god, no wonder we + * have so many crashes involving CamelMessageInfos! */ + if (async_context->info != NULL) + camel_message_info_free (async_context->info); + + if (async_context->destination != NULL) + g_object_unref (async_context->destination); + + if (async_context->message_uids != NULL) { + g_ptr_array_foreach ( + async_context->message_uids, (GFunc) g_free, NULL); + g_ptr_array_free (async_context->message_uids, TRUE); + } + + if (async_context->transferred_uids != NULL) { + g_ptr_array_foreach ( + async_context->transferred_uids, (GFunc) g_free, NULL); + g_ptr_array_free (async_context->transferred_uids, TRUE); + } + + g_free (async_context->message_uid); + + g_slice_free (AsyncContext, async_context); +} + +static void filter_filter (CamelSession *session, CamelSessionThreadMsg *tmsg) { @@ -121,7 +168,7 @@ filter_filter (CamelSession *session, if (m->junk) { /* Translators: The %s is replaced with a folder name where the operation is running. */ - camel_operation_start ( + camel_operation_push_message ( tmsg->cancellable, ngettext ( "Learning new spam message in '%s'", "Learning new spam messages in '%s'", @@ -140,12 +187,12 @@ filter_filter (CamelSession *session, g_object_unref (msg); } } - camel_operation_end (tmsg->cancellable); + camel_operation_pop_message (tmsg->cancellable); } if (m->notjunk) { /* Translators: The %s is replaced with a folder name where the operation is running. */ - camel_operation_start ( + camel_operation_push_message ( tmsg->cancellable, ngettext ( "Learning new ham message in '%s'", "Learning new ham messages in '%s'", @@ -163,7 +210,7 @@ filter_filter (CamelSession *session, g_object_unref (msg); } } - camel_operation_end (tmsg->cancellable); + camel_operation_pop_message (tmsg->cancellable); } if (m->junk || m->notjunk) @@ -171,7 +218,7 @@ filter_filter (CamelSession *session, if (m->driver && m->recents) { /* Translators: The %s is replaced with a folder name where the operation is running. */ - camel_operation_start ( + camel_operation_push_message ( tmsg->cancellable, ngettext ( "Filtering new message in '%s'", "Filtering new messages in '%s'", @@ -218,7 +265,7 @@ filter_filter (CamelSession *session, g_free (source_url); - camel_operation_end (tmsg->cancellable); + camel_operation_pop_message (tmsg->cancellable); } } @@ -755,8 +802,8 @@ static gboolean folder_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { @@ -770,10 +817,10 @@ folder_transfer_messages_to_sync (CamelFolder *source, } if (delete_originals) - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Moving messages")); else - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Copying messages")); if (uids->len > 1) { @@ -798,7 +845,7 @@ folder_transfer_messages_to_sync (CamelFolder *source, camel_folder_thaw (source); } - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); if (local_error != NULL) g_propagate_error (error, local_error); @@ -806,6 +853,465 @@ folder_transfer_messages_to_sync (CamelFolder *source, return TRUE; } +static void +folder_append_message_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_folder_append_message_sync ( + CAMEL_FOLDER (object), async_context->message, + async_context->info, &async_context->message_uid, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +folder_append_message (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->message = g_object_ref (message); + async_context->info = camel_message_info_ref (info); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, + user_data, folder_append_message); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, folder_append_message_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +folder_append_message_finish (CamelFolder *folder, + GAsyncResult *result, + gchar **appended_uid, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), folder_append_message), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (appended_uid != NULL) { + *appended_uid = async_context->message_uid; + async_context->message_uid = NULL; + } + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +folder_expunge_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + GError *error = NULL; + + camel_folder_expunge_sync ( + CAMEL_FOLDER (object), cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +folder_expunge (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, folder_expunge); + + g_simple_async_result_run_in_thread ( + simple, folder_expunge_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +folder_expunge_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), folder_expunge), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +folder_get_message_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->message = camel_folder_get_message_sync ( + CAMEL_FOLDER (object), async_context->message_uid, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +folder_get_message (CamelFolder *folder, + const gchar *message_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->message_uid = g_strdup (message_uid); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, folder_get_message); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, folder_get_message_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static CamelMimeMessage * +folder_get_message_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), folder_get_message), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + return g_object_ref (async_context->message); +} + +static void +folder_refresh_info_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + GError *error = NULL; + + camel_folder_refresh_info_sync ( + CAMEL_FOLDER (object), cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +folder_refresh_info (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, folder_refresh_info); + + g_simple_async_result_run_in_thread ( + simple, folder_refresh_info_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +folder_refresh_info_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), folder_refresh_info), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +folder_synchronize_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_folder_synchronize_sync ( + CAMEL_FOLDER (object), async_context->expunge, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +folder_synchronize (CamelFolder *folder, + gboolean expunge, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->expunge = expunge; + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, folder_synchronize); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, folder_synchronize_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +folder_synchronize_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), folder_synchronize), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +folder_synchronize_message_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_folder_synchronize_message_sync ( + CAMEL_FOLDER (object), async_context->message_uid, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +folder_synchronize_message (CamelFolder *folder, + const gchar *message_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->message_uid = g_strdup (message_uid); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, + user_data, folder_synchronize_message); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, folder_synchronize_message_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +folder_synchronize_message_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), + folder_synchronize_message), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +folder_transfer_messages_to_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_folder_transfer_messages_to_sync ( + CAMEL_FOLDER (object), async_context->message_uids, + async_context->destination, async_context->delete_originals, + &async_context->transferred_uids, cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +folder_transfer_messages_to (CamelFolder *source, + GPtrArray *message_uids, + CamelFolder *destination, + gboolean delete_originals, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + guint ii; + + async_context = g_slice_new0 (AsyncContext); + async_context->message_uids = g_ptr_array_new (); + async_context->destination = g_object_ref (destination); + async_context->delete_originals = delete_originals; + + for (ii = 0; ii < message_uids->len; ii++) + g_ptr_array_add ( + async_context->message_uids, + g_strdup (message_uids->pdata[ii])); + + simple = g_simple_async_result_new ( + G_OBJECT (source), callback, + user_data, folder_transfer_messages_to); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, folder_transfer_messages_to_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +folder_transfer_messages_to_finish (CamelFolder *source, + GAsyncResult *result, + GPtrArray **transferred_uids, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (source), + folder_transfer_messages_to), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (transferred_uids != NULL) { + *transferred_uids = async_context->transferred_uids; + async_context->transferred_uids = NULL; + } + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + /* Signal callback that stops emission when folder is frozen. */ static void folder_changed (CamelFolder *folder, @@ -936,6 +1442,21 @@ camel_folder_class_init (CamelFolderClass *class) class->transfer_messages_to_sync = folder_transfer_messages_to_sync; class->changed = folder_changed; + class->append_message = folder_append_message; + class->append_message_finish = folder_append_message_finish; + class->expunge = folder_expunge; + class->expunge_finish = folder_expunge_finish; + class->get_message = folder_get_message; + class->get_message_finish = folder_get_message_finish; + class->refresh_info = folder_refresh_info; + class->refresh_info_finish = folder_refresh_info_finish; + class->synchronize = folder_synchronize; + class->synchronize_finish = folder_synchronize_finish; + class->synchronize_message = folder_synchronize_message; + class->synchronize_message_finish = folder_synchronize_message_finish; + class->transfer_messages_to = folder_transfer_messages_to; + class->transfer_messages_to_finish = folder_transfer_messages_to_finish; + /** * CamelFolder:description * @@ -1112,114 +1633,42 @@ camel_folder_get_filename (CamelFolder *folder, } /** - * camel_folder_synchronize_sync: + * camel_folder_get_name: * @folder: a #CamelFolder - * @expunge: whether or not to expunge deleted messages - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL * - * Sync changes made to a folder to its backing store, possibly - * expunging deleted messages as well. + * Returns the short name of the folder. The fully qualified name + * can be obtained with camel_folder_get_full_name(). * - * Returns: %TRUE on success, %FALSE on failure + * Returns: the short name of the folder **/ -gboolean -camel_folder_synchronize_sync (CamelFolder *folder, - gboolean expunge, - GCancellable *cancellable, - GError **error) +const gchar * +camel_folder_get_name (CamelFolder *folder) { - CamelFolderClass *class; - gboolean success = TRUE; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - - class = CAMEL_FOLDER_GET_CLASS (folder); - g_return_val_if_fail (class->synchronize_sync != NULL, FALSE); - - camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); - - if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) { - success = class->synchronize_sync ( - folder, expunge, cancellable, error); - CAMEL_CHECK_GERROR (folder, synchronize_sync, success, error); - } - - camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - return success; + return folder->priv->name; } /** - * camel_folder_refresh_info_sync: + * camel_folder_set_name: * @folder: a #CamelFolder - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL + * @name: a name for the folder * - * Updates a folder's summary to be in sync with its backing store. + * Sets the short name of the folder. * - * Returns: %TRUE on success, %FALSE on failure + * Since: 2.32 **/ -gboolean -camel_folder_refresh_info_sync (CamelFolder *folder, - GCancellable *cancellable, - GError **error) +void +camel_folder_set_name (CamelFolder *folder, + const gchar *name) { - CamelFolderClass *class; - gboolean success; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_if_fail (CAMEL_IS_FOLDER (folder)); - class = CAMEL_FOLDER_GET_CLASS (folder); - g_return_val_if_fail (class->refresh_info_sync != NULL, FALSE); + g_free (folder->priv->name); + folder->priv->name = g_strdup (name); - camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); - - success = class->refresh_info_sync (folder, cancellable, error); - CAMEL_CHECK_GERROR (folder, refresh_info_sync, success, error); - - camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); - - return success; -} - -/** - * camel_folder_get_name: - * @folder: a #CamelFolder - * - * Returns the short name of the folder. The fully qualified name - * can be obtained with camel_folder_get_full_name(). - * - * Returns: the short name of the folder - **/ -const gchar * -camel_folder_get_name (CamelFolder *folder) -{ - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - - return folder->priv->name; -} - -/** - * camel_folder_set_name: - * @folder: a #CamelFolder - * @name: a name for the folder - * - * Sets the short name of the folder. - * - * Since: 2.32 - **/ -void -camel_folder_set_name (CamelFolder *folder, - const gchar *name) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - g_free (folder->priv->name); - folder->priv->name = g_strdup (name); - - g_object_notify (G_OBJECT (folder), "name"); -} + g_object_notify (G_OBJECT (folder), "name"); +} /** * camel_folder_get_full_name: @@ -1316,41 +1765,6 @@ camel_folder_get_parent_store (CamelFolder *folder) } /** - * camel_folder_expunge_sync: - * @folder: a #CamelFolder - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Delete messages which have been marked as "DELETED" - * - * Returns: %TRUE on success, %FALSE on failure - **/ -gboolean -camel_folder_expunge_sync (CamelFolder *folder, - GCancellable *cancellable, - GError **error) -{ - CamelFolderClass *class; - gboolean success = TRUE; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - - class = CAMEL_FOLDER_GET_CLASS (folder); - g_return_val_if_fail (class->expunge_sync != NULL, FALSE); - - camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); - - if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) { - success = class->expunge_sync (folder, cancellable, error); - CAMEL_CHECK_GERROR (folder, expunge_sync, success, error); - } - - camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); - - return success; -} - -/** * camel_folder_get_message_count: * @folder: a #CamelFolder * @@ -1404,50 +1818,6 @@ camel_folder_get_deleted_message_count (CamelFolder *folder) } /** - * camel_folder_append_message_sync: - * @folder: a #CamelFolder - * @message: a #CamelMimeMessage object - * @info: a #CamelMessageInfo with additional flags/etc to set on - * new message, or %NULL - * @appended_uid: if non-%NULL, the UID of the appended message will - * be returned here, if it is known. - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Append @message to @folder. Only the flag and tag data from @info - * are used. If @info is %NULL, no flags or tags will be set. - * - * Returns: %TRUE on success, %FALSE on failure - **/ -gboolean -camel_folder_append_message_sync (CamelFolder *folder, - CamelMimeMessage *message, - const CamelMessageInfo *info, - gchar **appended_uid, - GCancellable *cancellable, - GError **error) -{ - CamelFolderClass *class; - gboolean success; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE); - - class = CAMEL_FOLDER_GET_CLASS (folder); - g_return_val_if_fail (class->append_message_sync != NULL, FALSE); - - camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); - - success = class->append_message_sync ( - folder, message, info, appended_uid, cancellable, error); - CAMEL_CHECK_GERROR (folder, append_message_sync, success, error); - - camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); - - return success; -} - -/** * camel_folder_get_permanent_flags: * @folder: a #CamelFolder * @@ -1750,110 +2120,6 @@ camel_folder_has_summary_capability (CamelFolder *folder) /* UIDs stuff */ /** - * camel_folder_get_message_sync: - * @folder: a #CamelFolder - * @uid: the UID - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Get a message from its UID in the folder. - * - * Returns: a #CamelMimeMessage corresponding to @uid - **/ -CamelMimeMessage * -camel_folder_get_message_sync (CamelFolder *folder, - const gchar *uid, - GCancellable *cancellable, - GError **error) -{ - CamelFolderClass *class; - CamelMimeMessage *ret; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - g_return_val_if_fail (uid != NULL, NULL); - - class = CAMEL_FOLDER_GET_CLASS (folder); - g_return_val_if_fail (class->get_message_sync != NULL, NULL); - - camel_operation_start ( - cancellable, _("Retrieving message '%s'"), uid); - - camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); - - ret = class->get_message_sync (folder, uid, cancellable, error); - CAMEL_CHECK_GERROR (folder, get_message_sync, ret != NULL, error); - - camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); - - camel_operation_end (cancellable); - - if (ret && camel_debug_start (":folder")) { - printf ("CamelFolder:get_message ('%s', '%s') =\n", - camel_folder_get_full_name (folder), uid); - camel_mime_message_dump (ret, FALSE); - camel_debug_end (); - } - - return ret; -} - -/** - * camel_folder_synchronize_message_sync: - * @folder: a #CamelFolder - * @uid: the UID - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Ensure that a message identified by UID has been synced in the folder (so - * that camel_folder_get_message on it later will work in offline mode). - * - * Returns: %TRUE on success, %FALSE on failure - * - * Since: 2.26 - **/ -gboolean -camel_folder_synchronize_message_sync (CamelFolder *folder, - const gchar *uid, - GCancellable *cancellable, - GError **error) -{ - CamelFolderClass *class; - gboolean success = FALSE; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - g_return_val_if_fail (uid != NULL, FALSE); - - class = CAMEL_FOLDER_GET_CLASS (folder); - g_return_val_if_fail (class->get_message_sync != NULL, FALSE); - - camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); - - /* Use the sync_message method if the class implements it. */ - if (class->synchronize_message_sync != NULL) { - success = class->synchronize_message_sync ( - folder, uid, cancellable, error); - CAMEL_CHECK_GERROR ( - folder, synchronize_message_sync, success, error); - } else { - CamelMimeMessage *message; - - message = class->get_message_sync ( - folder, uid, cancellable, error); - CAMEL_CHECK_GERROR ( - folder, get_message_sync, message != NULL, error); - - if (message != NULL) { - g_object_unref (message); - success = TRUE; - } - } - - camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); - - return success; -} - -/** * camel_folder_get_uids: * @folder: a #CamelFolder * @@ -2171,62 +2437,6 @@ camel_folder_search_free (CamelFolder *folder, } /** - * camel_folder_transfer_messages_to_sync: - * @source: the source #CamelFolder object - * @uids: message UIDs in @source - * @dest: the destination #CamelFolder object - * @transferred_uids: if non-%NULL, the UIDs of the resulting messages - * in @dest will be stored here, if known. - * @delete_originals: whether or not to delete the original messages - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * This copies or moves messages from one folder to another. If the - * @source and @dest folders have the same parent_store, this may be - * more efficient than using #camel_folder_append_message. - * - * Returns: %TRUE on success, %FALSE on failure - **/ -gboolean -camel_folder_transfer_messages_to_sync (CamelFolder *source, - GPtrArray *uids, - CamelFolder *dest, - GPtrArray **transferred_uids, - gboolean delete_originals, - GCancellable *cancellable, - GError **error) -{ - CamelFolderClass *class; - gboolean success; - - g_return_val_if_fail (CAMEL_IS_FOLDER (source), FALSE); - g_return_val_if_fail (CAMEL_IS_FOLDER (dest), FALSE); - g_return_val_if_fail (uids != NULL, FALSE); - - if (source == dest || uids->len == 0) { - /* source and destination folders are the same, or no work to do, do nothing. */ - return TRUE; - } - - if (source->priv->parent_store == dest->priv->parent_store) { - /* If either folder is a vtrash, we need to use the - * vtrash transfer method. */ - if (CAMEL_IS_VTRASH_FOLDER (dest)) - class = CAMEL_FOLDER_GET_CLASS (dest); - else - class = CAMEL_FOLDER_GET_CLASS (source); - success = class->transfer_messages_to_sync ( - source, uids, dest, transferred_uids, - delete_originals, cancellable, error); - } else - success = folder_transfer_messages_to_sync ( - source, uids, dest, transferred_uids, - delete_originals, cancellable, error); - - return success; -} - -/** * camel_folder_delete: * @folder: a #CamelFolder * @@ -2551,19 +2761,843 @@ camel_folder_free_deep (CamelFolder *folder, } /** - * camel_folder_change_info_new: - * - * Create a new folder change info structure. + * camel_folder_lock: + * @folder: a #CamelFolder + * @lock: lock type to lock * - * Change info structures are not MT-SAFE and must be - * locked for exclusive access externally. + * Locks #folder's #lock. Unlock it with camel_folder_unlock(). * - * Returns: a new #CamelFolderChangeInfo + * Since: 2.32 **/ -CamelFolderChangeInfo * -camel_folder_change_info_new (void) +void +camel_folder_lock (CamelFolder *folder, + CamelFolderLock lock) { - CamelFolderChangeInfo *info; + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + + switch (lock) { + case CAMEL_FOLDER_CHANGE_LOCK: + g_static_mutex_lock (&folder->priv->change_lock); + break; + case CAMEL_FOLDER_REC_LOCK: + if (folder->priv->skip_folder_lock == FALSE) + g_static_rec_mutex_lock (&folder->priv->lock); + break; + default: + g_return_if_reached (); + } +} + +/** + * camel_folder_unlock: + * @folder: a #CamelFolder + * @lock: lock type to unlock + * + * Unlocks #folder's #lock, previously locked with camel_folder_lock(). + * + * Since: 2.32 + **/ +void +camel_folder_unlock (CamelFolder *folder, + CamelFolderLock lock) +{ + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + + switch (lock) { + case CAMEL_FOLDER_CHANGE_LOCK: + g_static_mutex_unlock (&folder->priv->change_lock); + break; + case CAMEL_FOLDER_REC_LOCK: + if (folder->priv->skip_folder_lock == FALSE) + g_static_rec_mutex_unlock (&folder->priv->lock); + break; + default: + g_return_if_reached (); + } +} + +/** + * camel_folder_append_message_sync: + * @folder: a #CamelFolder + * @message: a #CamelMimeMessage + * @info: a #CamelMessageInfo with additional flags/etc to set on the + * new message, or %NULL + * @appended_uid: if non-%NULL, the UID of the appended message will + * be returned here, if it is known + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Appends @message to @folder. Only the flag and tag data from @info + * are used. If @info is %NULL, no flags or tags will be set. + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_append_message_sync (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gchar **appended_uid, + GCancellable *cancellable, + GError **error) +{ + CamelFolderClass *class; + gboolean success; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->append_message_sync != NULL, FALSE); + + camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + return FALSE; + } + + success = class->append_message_sync ( + folder, message, info, appended_uid, cancellable, error); + CAMEL_CHECK_GERROR (folder, append_message_sync, success, error); + + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + + return success; +} + +/** + * camel_folder_append_message: + * @folder a #CamelFolder + * @message: a #CamelMimeMessage + * @info: a #CamelMessageInfo with additional flags/etc to set on the + * new message, or %NULL + * @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 + * + * Appends @message to @folder asynchronously. Only the flag and tag data + * from @info are used. If @info is %NULL, no flags or tags will be set. + * + * When the operation is finished, @callback will be called. You can + * then call camel_folder_append_message_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_folder_append_message (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelFolderClass *class; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_if_fail (class->append_message != NULL); + + class->append_message ( + folder, message, info, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_folder_append_message_finish: + * @folder: a #CamelFolder + * @result: a #GAsyncResult + * @appended_uid: if non-%NULL, the UID of the appended message will + * be returned here, if it is known + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_folder_append_message_finish(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_append_message_finish (CamelFolder *folder, + GAsyncResult *result, + gchar **appended_uid, + GError **error) +{ + CamelFolderClass *class; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->append_message_finish != NULL, FALSE); + + return class->append_message_finish ( + folder, result, appended_uid, error); +} + +/** + * camel_folder_expunge_sync: + * @folder: a #CamelFolder + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Deletes messages which have been marked as "DELETED". + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_expunge_sync (CamelFolder *folder, + GCancellable *cancellable, + GError **error) +{ + CamelFolderClass *class; + gboolean success = TRUE; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->expunge_sync != NULL, FALSE); + + camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + return FALSE; + } + + if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) { + success = class->expunge_sync (folder, cancellable, error); + CAMEL_CHECK_GERROR (folder, expunge_sync, success, error); + } + + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + + return success; +} + +/** + * camel_folder_expunge: + * @folder: a #CamelFolder + * @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 deletes messages which have been marked as "DELETED". + * + * When the operation is finished, @callback will be called. You can then + * call camel_folder_expunge_finish() to get the result of the operation. + * + * Since: 2.34 + **/ +void +camel_folder_expunge (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelFolderClass *class; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_if_fail (class->expunge != NULL); + + class->expunge (folder, io_priority, cancellable, callback, user_data); +} + +/** + * camel_folder_expunge_finish: + * @folder: a #CamelFolder + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_folder_expunge(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_expunge_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + CamelFolderClass *class; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->expunge_finish != NULL, FALSE); + + return class->expunge_finish (folder, result, error); +} + +/** + * camel_folder_get_message_sync: + * @folder: a #CamelFolder + * @message_uid: the message UID + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Gets the message corresponding to @message_uid from @folder. + * + * Returns: a #CamelMimeMessage corresponding to the requested UID + * + * Since: 2.34 + **/ +CamelMimeMessage * +camel_folder_get_message_sync (CamelFolder *folder, + const gchar *message_uid, + GCancellable *cancellable, + GError **error) +{ + CamelFolderClass *class; + CamelMimeMessage *message; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + g_return_val_if_fail (message_uid != NULL, NULL); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->get_message_sync != NULL, NULL); + + camel_operation_push_message ( + cancellable, _("Retrieving message '%s'"), message_uid); + + camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + return NULL; + } + + message = class->get_message_sync ( + folder, message_uid, cancellable, error); + CAMEL_CHECK_GERROR (folder, get_message_sync, message != NULL, error); + + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + + camel_operation_pop_message (cancellable); + + if (message != NULL && camel_debug_start (":folder")) { + printf ("CamelFolder:get_message ('%s', '%s') =\n", + camel_folder_get_full_name (folder), message_uid); + camel_mime_message_dump (message, FALSE); + camel_debug_end (); + } + + return message; +} + +/** + * camel_folder_get_message: + * @folder: a #CamelFolder + * @message_uid: the message UID + * @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 gets the message corresponding to @message_uid from @folder. + * + * When the operation is finished, @callback will be called. You can then + * call camel_folder_get_message_finish() to get the result of the operation. + * + * Since: 2.34 + **/ +void +camel_folder_get_message (CamelFolder *folder, + const gchar *message_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelFolderClass *class; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (message_uid != NULL); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_if_fail (class->get_message != NULL); + + class->get_message ( + folder, message_uid, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_folder_get_message_finish: + * @folder: a #CamelFolder + * @result: a #GAsyncResult + * @error: return location for a #GError or %NULL + * + * Finishes the operation started with camel_folder_get_message(). + * + * Returns: a #CamelMimeMessage corresponding to the requested UID + * + * Since: 2.34 + **/ +CamelMimeMessage * +camel_folder_get_message_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + CamelFolderClass *class; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->get_message_finish != NULL, NULL); + + return class->get_message_finish (folder, result, error); +} + +/** + * camel_folder_refresh_info_sync: + * @folder: a #CamelFolder + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Synchronizes a folder's summary with its backing store. + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_refresh_info_sync (CamelFolder *folder, + GCancellable *cancellable, + GError **error) +{ + CamelFolderClass *class; + gboolean success; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->refresh_info_sync != NULL, FALSE); + + camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + return FALSE; + } + + success = class->refresh_info_sync (folder, cancellable, error); + CAMEL_CHECK_GERROR (folder, refresh_info_sync, success, error); + + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + + return success; +} + +/** + * camel_folder_synchronize_sync: + * @folder: a #CamelFolder + * @expunge: whether to expunge after synchronizing + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Synchronizes any changes that have been made to @folder to its + * backing store, optionally expunging deleted messages as well. + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_synchronize_sync (CamelFolder *folder, + gboolean expunge, + GCancellable *cancellable, + GError **error) +{ + CamelFolderClass *class; + gboolean success = TRUE; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->synchronize_sync != NULL, FALSE); + + camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + return FALSE; + } + + if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) { + success = class->synchronize_sync ( + folder, expunge, cancellable, error); + CAMEL_CHECK_GERROR (folder, synchronize_sync, success, error); + } + + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + + return success; +} + +/** + * camel_folder_synchronize: + * @folder: a #CamelFolder + * @expunge: whether to expunge after synchronizing + * @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 + * + * Synchronizes any changes that have been made to @folder to its backing + * store asynchronously, optionally expunging deleted messages as well. + * + * When the operation is finished, @callback will be called. You can then + * call camel_folder_synchronize_finish() to get the result of the operation. + * + * Since: 2.34 + **/ +void +camel_folder_synchronize (CamelFolder *folder, + gboolean expunge, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelFolderClass *class; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_if_fail (class->synchronize != NULL); + + class->synchronize ( + folder, expunge, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_folder_synchronize_finish: + * @folder: a #CamelFolder + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_folder_synchronize(). + * + * Returns: %TRUE on sucess, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_synchronize_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + CamelFolderClass *class; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->synchronize_finish != NULL, FALSE); + + return class->synchronize_finish (folder, result, error); +} + +/** + * camel_folder_synchronize_message_sync: + * @folder: a #CamelFolder + * @message_uid: a message UID + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Ensure that a message identified by @message_uid has been synchronized in + * @folder so that calling camel_folder_get_message() on it later will work + * in offline mode. + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_synchronize_message_sync (CamelFolder *folder, + const gchar *message_uid, + GCancellable *cancellable, + GError **error) +{ + CamelFolderClass *class; + gboolean success = FALSE; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (message_uid != NULL, FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->get_message_sync != NULL, FALSE); + + camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + return FALSE; + } + + /* Use the sync_message method if the class implements it. */ + if (class->synchronize_message_sync != NULL) { + success = class->synchronize_message_sync ( + folder, message_uid, cancellable, error); + CAMEL_CHECK_GERROR ( + folder, synchronize_message_sync, success, error); + } else { + CamelMimeMessage *message; + + message = class->get_message_sync ( + folder, message_uid, cancellable, error); + CAMEL_CHECK_GERROR ( + folder, get_message_sync, message != NULL, error); + + if (message != NULL) { + g_object_unref (message); + success = TRUE; + } + } + + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + + return success; +} + +/** + * camel_folder_synchronize_message; + * @folder: a #CamelFolder + * @message_uid: a message UID + * @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 ensure that a message identified by @message_uid has been + * synchronized in @folder so that calling camel_folder_get_message() on it + * later will work in offline mode. + * + * When the operation is finished, @callback will be called. You can then + * call camel_folder_synchronize_message_finish() to get the result of the + * operation. + * + * Since: 2.34 + **/ +void +camel_folder_synchronize_message (CamelFolder *folder, + const gchar *message_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelFolderClass *class; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (message_uid != NULL); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_if_fail (class->synchronize_message != NULL); + + class->synchronize_message ( + folder, message_uid, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_folder_synchronize_message_finish: + * @folder: a #CamelFolder + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_folder_synchronize_message(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_synchronize_message_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + CamelFolderClass *class; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->synchronize_message_finish != NULL, FALSE); + + return class->synchronize_message_finish (folder, result, error); +} + +/** + * camel_folder_transfer_messages_to_sync: + * @source: the source #CamelFolder + * @message_uids: message UIDs in @source + * @destination: the destination #CamelFolder + * @delete_originals: whether or not to delete the original messages + * @transferred_uids: if non-%NULL, the UIDs of the resulting messages + * in @destination will be stored here, if known. + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Copies or moves messages from one folder to another. If the + * @source and @destination folders have the same parent_store, this + * may be more efficient than using camel_folder_append_message_sync(). + * + * Returns: %TRUE on success, %FALSE on failure + * + * Since: 2.34 + **/ +gboolean +camel_folder_transfer_messages_to_sync (CamelFolder *source, + GPtrArray *message_uids, + CamelFolder *destination, + gboolean delete_originals, + GPtrArray **transferred_uids, + GCancellable *cancellable, + GError **error) +{ + CamelFolderClass *class; + gboolean success; + + g_return_val_if_fail (CAMEL_IS_FOLDER (source), FALSE); + g_return_val_if_fail (CAMEL_IS_FOLDER (destination), FALSE); + g_return_val_if_fail (message_uids != NULL, FALSE); + + if (source == destination || message_uids->len == 0) + return TRUE; + + if (source->priv->parent_store == destination->priv->parent_store) { + /* If either folder is a vtrash, we need to use the + * vtrash transfer method. */ + if (CAMEL_IS_VTRASH_FOLDER (destination)) + class = CAMEL_FOLDER_GET_CLASS (destination); + else + class = CAMEL_FOLDER_GET_CLASS (source); + success = class->transfer_messages_to_sync ( + source, message_uids, destination, delete_originals, + transferred_uids, cancellable, error); + } else + success = folder_transfer_messages_to_sync ( + source, message_uids, destination, delete_originals, + transferred_uids, cancellable, error); + + return success; +} + +/** + * camel_folder_transfer_messages_to: + * @source: the source #CamelFolder + * @message_uids: message UIDs in @source + * @destination: the destination #CamelFolder + * @delete_originals: whether or not to delete the original messages + * @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 copies or moves messages from one folder to another. + * If the @source or @destination folders have the same parent store, + * this may be more efficient than using camel_folder_append_message(). + * + * When the operation is finished, @callback will be called. You can then + * call camel_folder_transfer_messages_to_finish() to get the result of the + * operation. + * + * Since: 2.34 + **/ +void +camel_folder_transfer_messages_to (CamelFolder *source, + GPtrArray *message_uids, + CamelFolder *destination, + gboolean delete_originals, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelFolderClass *class; + + g_return_if_fail (CAMEL_IS_FOLDER (source)); + g_return_if_fail (CAMEL_IS_FOLDER (destination)); + g_return_if_fail (message_uids != NULL); + + class = CAMEL_FOLDER_GET_CLASS (source); + g_return_if_fail (class->transfer_messages_to != NULL); + + class->transfer_messages_to ( + source, message_uids, destination, delete_originals, + io_priority, cancellable, callback, user_data); +} + +/** + * camel_folder_transfer_messages_to_finish: + * @source: a #CamelFolder + * @result: a #GAsyncResult + * @transferred_uids: if non-%NULL, the UIDs of the resulting messages + * in @destination will be stored here, if known. + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_folder_transfer_messages_to(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_folder_transfer_messages_to_finish (CamelFolder *source, + GAsyncResult *result, + GPtrArray **transferred_uids, + GError **error) +{ + CamelFolderClass *class; + + g_return_val_if_fail (CAMEL_IS_FOLDER (source), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_FOLDER_GET_CLASS (source); + g_return_val_if_fail (class->transfer_messages_to_finish != NULL, FALSE); + + return class->transfer_messages_to_finish ( + source, result, transferred_uids, error); +} + +/** + * camel_folder_change_info_new: + * + * Create a new folder change info structure. + * + * Change info structures are not MT-SAFE and must be + * locked for exclusive access externally. + * + * Returns: a new #CamelFolderChangeInfo + **/ +CamelFolderChangeInfo * +camel_folder_change_info_new (void) +{ + CamelFolderChangeInfo *info; info = g_slice_new (CamelFolderChangeInfo); info->uid_added = g_ptr_array_new (); @@ -2991,59 +4025,3 @@ camel_folder_change_info_free (CamelFolderChangeInfo *info) g_ptr_array_free (info->uid_recent, TRUE); g_slice_free (CamelFolderChangeInfo, info); } - -/** - * camel_folder_lock: - * @folder: a #CamelFolder - * @lock: lock type to lock - * - * Locks #folder's #lock. Unlock it with camel_folder_unlock(). - * - * Since: 2.32 - **/ -void -camel_folder_lock (CamelFolder *folder, - CamelFolderLock lock) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - switch (lock) { - case CAMEL_FOLDER_CHANGE_LOCK: - g_static_mutex_lock (&folder->priv->change_lock); - break; - case CAMEL_FOLDER_REC_LOCK: - if (folder->priv->skip_folder_lock == FALSE) - g_static_rec_mutex_lock (&folder->priv->lock); - break; - default: - g_return_if_reached (); - } -} - -/** - * camel_folder_unlock: - * @folder: a #CamelFolder - * @lock: lock type to unlock - * - * Unlocks #folder's #lock, previously locked with camel_folder_lock(). - * - * Since: 2.32 - **/ -void -camel_folder_unlock (CamelFolder *folder, - CamelFolderLock lock) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - switch (lock) { - case CAMEL_FOLDER_CHANGE_LOCK: - g_static_mutex_unlock (&folder->priv->change_lock); - break; - case CAMEL_FOLDER_REC_LOCK: - if (folder->priv->skip_folder_lock == FALSE) - g_static_rec_mutex_unlock (&folder->priv->lock); - break; - default: - g_return_if_reached (); - } -} diff --git a/camel/camel-folder.h b/camel/camel-folder.h index 652cba7..0fb551b 100644 --- a/camel/camel-folder.h +++ b/camel/camel-folder.h @@ -143,7 +143,7 @@ struct _CamelFolder { struct _CamelFolderClass { CamelObjectClass parent_class; - /* Methods */ + /* Non-Blocking Methods */ gint (*get_message_count) (CamelFolder *folder); guint32 (*get_permanent_flags) (CamelFolder *folder); guint32 (*get_message_flags) (CamelFolder *folder, @@ -212,9 +212,10 @@ struct _CamelFolderClass { const gchar *uid, GError **error); + /* Synchronous I/O Methods */ gboolean (*append_message_sync) (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error); @@ -223,7 +224,7 @@ struct _CamelFolderClass { GError **error); CamelMimeMessage * (*get_message_sync) (CamelFolder *folder, - const gchar *uid, + const gchar *message_uid, GCancellable *cancellable, GError **error); gboolean (*refresh_info_sync) (CamelFolder *folder, @@ -235,16 +236,88 @@ struct _CamelFolderClass { GError **error); gboolean (*synchronize_message_sync) (CamelFolder *folder, - const gchar *uid, + const gchar *message_uid, GCancellable *cancellable, GError **error); gboolean (*transfer_messages_to_sync) (CamelFolder *source, - GPtrArray *uids, + GPtrArray *message_uids, CamelFolder *destination, + gboolean delete_originals, GPtrArray **transferred_uids, + GCancellable *cancellable, + GError **error); + + /* Asynchronous I/O Methods (all have defaults) */ + void (*append_message) (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*append_message_finish) + (CamelFolder *folder, + GAsyncResult *result, + gchar **appended_uid, + GError **error); + void (*expunge) (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*expunge_finish) (CamelFolder *folder, + GAsyncResult *result, + GError **error); + void (*get_message) (CamelFolder *folder, + const gchar *message_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelMimeMessage * + (*get_message_finish) (CamelFolder *folder, + GAsyncResult *result, + GError **error); + void (*refresh_info) (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*refresh_info_finish) (CamelFolder *folder, + GAsyncResult *result, + GError **error); + void (*synchronize) (CamelFolder *folder, + gboolean expunge, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*synchronize_finish) (CamelFolder *folder, + GAsyncResult *result, + GError **error); + void (*synchronize_message) (CamelFolder *folder, + const gchar *message_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*synchronize_message_finish) + (CamelFolder *folder, + GAsyncResult *result, + GError **error); + void (*transfer_messages_to) (CamelFolder *source, + GPtrArray *message_uids, + CamelFolder *destination, gboolean delete_originals, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*transfer_messages_to_finish) + (CamelFolder *source, + GAsyncResult *result, + GPtrArray **transferred_uids, GError **error); /* Signals */ @@ -378,40 +451,118 @@ void camel_folder_free_deep (CamelFolder *folder, gchar * camel_folder_get_filename (CamelFolder *folder, const gchar *uid, GError **error); +void camel_folder_lock (CamelFolder *folder, + CamelFolderLock lock); +void camel_folder_unlock (CamelFolder *folder, + CamelFolderLock lock); + gboolean camel_folder_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error); +void camel_folder_append_message (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_folder_append_message_finish + (CamelFolder *folder, + GAsyncResult *result, + gchar **appended_uid, + GError **error); gboolean camel_folder_expunge_sync (CamelFolder *folder, GCancellable *cancellable, GError **error); +void camel_folder_expunge (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_folder_expunge_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error); CamelMimeMessage * camel_folder_get_message_sync (CamelFolder *folder, - const gchar *uid, + const gchar *message_uid, + GCancellable *cancellable, + GError **error); +void camel_folder_get_message (CamelFolder *folder, + const gchar *message_uid, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelMimeMessage * + camel_folder_get_message_finish (CamelFolder *folder, + GAsyncResult *result, GError **error); gboolean camel_folder_refresh_info_sync (CamelFolder *folder, GCancellable *cancellable, GError **error); +void camel_folder_refresh_info (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_folder_refresh_info_finish + (CamelFolder *folder, + GAsyncResult *result, + GError **error); gboolean camel_folder_synchronize_sync (CamelFolder *folder, gboolean expunge, GCancellable *cancellable, GError **error); +void camel_folder_synchronize (CamelFolder *folder, + gboolean expunge, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_folder_synchronize_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error); gboolean camel_folder_synchronize_message_sync (CamelFolder *folder, - const gchar *uid, + const gchar *message_uid, + GCancellable *cancellable, + GError **error); +void camel_folder_synchronize_message + (CamelFolder *folder, + const gchar *message_uid, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_folder_synchronize_message_finish + (CamelFolder *folder, + GAsyncResult *result, GError **error); gboolean camel_folder_transfer_messages_to_sync (CamelFolder *source, - GPtrArray *uids, - CamelFolder *dest, + GPtrArray *message_uids, + CamelFolder *destination, + gboolean delete_originals, GPtrArray **transferred_uids, + GCancellable *cancellable, + GError **error); +void camel_folder_transfer_messages_to + (CamelFolder *source, + GPtrArray *message_uids, + CamelFolder *destination, gboolean delete_originals, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_folder_transfer_messages_to_finish + (CamelFolder *source, + GAsyncResult *result, + GPtrArray **transferred_uids, GError **error); /* update functions for change info */ @@ -452,11 +603,6 @@ void camel_folder_change_info_recent_uid (CamelFolderChangeInfo *info, const gchar *uid); -void camel_folder_lock (CamelFolder *folder, - CamelFolderLock lock); -void camel_folder_unlock (CamelFolder *folder, - CamelFolderLock lock); - G_END_DECLS #endif /* CAMEL_FOLDER_H */ diff --git a/camel/camel-gpg-context.c b/camel/camel-gpg-context.c index a63257f..f027917 100644 --- a/camel/camel-gpg-context.c +++ b/camel/camel-gpg-context.c @@ -1506,7 +1506,7 @@ gpg_id_to_hash (CamelCipherContext *context, return CAMEL_CIPHER_HASH_DEFAULT; } -static gint +static gboolean gpg_sign_sync (CamelCipherContext *context, const gchar *userid, CamelCipherHash hash, @@ -1520,9 +1520,9 @@ gpg_sign_sync (CamelCipherContext *context, CamelStream *ostream = camel_stream_mem_new (), *istream; CamelDataWrapper *dw; CamelContentType *ct; - gint res = -1; CamelMimePart *sigpart; CamelMultipartSigned *mps; + gboolean success = FALSE; /* Note: see rfc2015 or rfc3156, section 5 */ @@ -1588,7 +1588,7 @@ gpg_sign_sync (CamelCipherContext *context, goto fail; } - res = 0; + success = TRUE; dw = camel_data_wrapper_new (); camel_stream_reset (ostream, NULL); @@ -1608,7 +1608,7 @@ gpg_sign_sync (CamelCipherContext *context, mps = camel_multipart_signed_new (); ct = camel_content_type_new("multipart", "signed"); - camel_content_type_set_param(ct, "micalg", camel_cipher_hash_to_id (context, hash == CAMEL_CIPHER_HASH_DEFAULT ? gpg->hash : hash)); + camel_content_type_set_param(ct, "micalg", camel_cipher_context_hash_to_id (context, hash == CAMEL_CIPHER_HASH_DEFAULT ? gpg->hash : hash)); camel_content_type_set_param(ct, "protocol", class->sign_protocol); camel_data_wrapper_set_mime_type_field ((CamelDataWrapper *)mps, ct); camel_content_type_unref (ct); @@ -1626,7 +1626,7 @@ fail: if (gpg) gpg_ctx_free (gpg); - return res; + return success; } static CamelCipherValidity * @@ -1689,8 +1689,9 @@ gpg_verify_sync (CamelCipherContext *context, CamelDataWrapper *content; content = camel_medium_get_content ((CamelMedium *) ipart); istream = camel_stream_mem_new (); - camel_data_wrapper_decode_to_stream_sync ( - content, istream, NULL, NULL); + if (!camel_data_wrapper_decode_to_stream_sync ( + content, istream, cancellable, error)) + goto exception; camel_stream_reset (istream, NULL); sigpart = NULL; } else { @@ -1831,7 +1832,7 @@ gpg_verify_sync (CamelCipherContext *context, return NULL; } -static gint +static gboolean gpg_encrypt_sync (CamelCipherContext *context, const gchar *userid, GPtrArray *recipients, @@ -1843,12 +1844,13 @@ gpg_encrypt_sync (CamelCipherContext *context, CamelCipherContextClass *class; CamelGpgContext *ctx = (CamelGpgContext *) context; struct _GpgCtx *gpg; - gint i, res = -1; CamelStream *istream, *ostream, *vstream; CamelMimePart *encpart, *verpart; CamelDataWrapper *dw; CamelContentType *ct; CamelMultipartEncrypted *mpe; + gboolean success = FALSE; + gint i; class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); @@ -1895,7 +1897,7 @@ gpg_encrypt_sync (CamelCipherContext *context, goto fail; } - res = 0; + success = TRUE; dw = camel_data_wrapper_new (); camel_data_wrapper_construct_from_stream_sync ( @@ -1946,7 +1948,7 @@ fail1: g_object_unref (istream); g_object_unref (ostream); - return res; + return success; } static CamelCipherValidity * @@ -1956,14 +1958,14 @@ gpg_decrypt_sync (CamelCipherContext *context, GCancellable *cancellable, GError **error) { - struct _GpgCtx *gpg; + struct _GpgCtx *gpg = NULL; CamelCipherValidity *valid = NULL; CamelStream *ostream, *istream; CamelDataWrapper *content; CamelMimePart *encrypted; CamelMultipart *mp; CamelContentType *ct; - gint rv; + gboolean success; if (!ipart) { g_set_error ( @@ -2005,8 +2007,9 @@ gpg_decrypt_sync (CamelCipherContext *context, } istream = camel_stream_mem_new (); - camel_data_wrapper_decode_to_stream_sync ( - content, istream, NULL, NULL); + if (!camel_data_wrapper_decode_to_stream_sync ( + content, istream, cancellable, error)) + goto fail; camel_stream_reset (istream, NULL); ostream = camel_stream_mem_new (); @@ -2044,7 +2047,7 @@ gpg_decrypt_sync (CamelCipherContext *context, CamelStream *null = camel_stream_null_new (); /* Multipart encrypted - parse a full mime part */ - rv = camel_data_wrapper_construct_from_stream_sync ( + success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (opart), ostream, NULL, error); @@ -2054,8 +2057,8 @@ gpg_decrypt_sync (CamelCipherContext *context, /* nothing had been decoded from the stream, it doesn't contain any header, like Content-Type or such, thus write it as a message body */ - rv = camel_data_wrapper_construct_from_stream_sync ( - dw, ostream, NULL, error); + success = camel_data_wrapper_construct_from_stream_sync ( + dw, ostream, cancellable, error); } g_object_unref (null); @@ -2063,7 +2066,7 @@ gpg_decrypt_sync (CamelCipherContext *context, /* Inline signed - raw data (may not be a mime part) */ CamelDataWrapper *dw; dw = camel_data_wrapper_new (); - rv = camel_data_wrapper_construct_from_stream_sync ( + success = camel_data_wrapper_construct_from_stream_sync ( dw, ostream, NULL, error); camel_data_wrapper_set_mime_type(dw, "application/octet-stream"); camel_medium_set_content ((CamelMedium *)opart, dw); @@ -2072,7 +2075,7 @@ gpg_decrypt_sync (CamelCipherContext *context, camel_mime_part_set_content_type(opart, "application/octet-stream"); } - if (rv != -1) { + if (success) { valid = camel_cipher_validity_new (); valid->encrypt.description = g_strdup(_("Encrypted content")); valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED; @@ -2103,14 +2106,14 @@ gpg_decrypt_sync (CamelCipherContext *context, return valid; } -static gint +static gboolean gpg_import_keys_sync (CamelCipherContext *context, CamelStream *istream, GCancellable *cancellable, GError **error) { struct _GpgCtx *gpg; - gint res = -1; + gboolean success = FALSE; gpg = gpg_ctx_new (context); gpg_ctx_set_mode (gpg, GPG_CTX_MODE_IMPORT); @@ -2137,14 +2140,14 @@ gpg_import_keys_sync (CamelCipherContext *context, goto fail; } - res = 0; + success = TRUE; fail: gpg_ctx_free (gpg); - return res; + return success; } -static gint +static gboolean gpg_export_keys_sync (CamelCipherContext *context, GPtrArray *keys, CamelStream *ostream, @@ -2152,8 +2155,8 @@ gpg_export_keys_sync (CamelCipherContext *context, GError **error) { struct _GpgCtx *gpg; + gboolean success = FALSE; gint i; - gint res = -1; gpg = gpg_ctx_new (context); gpg_ctx_set_mode (gpg, GPG_CTX_MODE_EXPORT); @@ -2185,11 +2188,11 @@ gpg_export_keys_sync (CamelCipherContext *context, goto fail; } - res = 0; + success = TRUE; fail: gpg_ctx_free (gpg); - return res; + return success; } static void diff --git a/camel/camel-mime-message.c b/camel/camel-mime-message.c index ba97e3a..217b85c 100644 --- a/camel/camel-mime-message.c +++ b/camel/camel-mime-message.c @@ -288,7 +288,7 @@ mime_message_remove_header (CamelMedium *medium, CAMEL_MEDIUM_CLASS (camel_mime_message_parent_class)->remove_header (medium, name); } -static gint +static gboolean mime_message_construct_from_parser_sync (CamelMimePart *dw, CamelMimeParser *mp, GCancellable *cancellable, @@ -298,16 +298,16 @@ mime_message_construct_from_parser_sync (CamelMimePart *dw, gchar *buf; gsize len; gint state; - gint ret; gint err; + gboolean success; /* let the mime-part construct the guts ... */ mime_part_class = CAMEL_MIME_PART_CLASS (camel_mime_message_parent_class); - ret = mime_part_class->construct_from_parser_sync ( + success = mime_part_class->construct_from_parser_sync ( dw, mp, cancellable, error); - if (ret == -1) - return -1; + if (!success) + return FALSE; /* ... then clean up the follow-on state */ state = camel_mime_parser_step (mp, &buf, &len); @@ -321,7 +321,7 @@ mime_message_construct_from_parser_sync (CamelMimePart *dw, default: g_error ("Bad parser state: Expecing MESSAGE_END or EOF or EOM, got: %u", camel_mime_parser_state (mp)); camel_mime_parser_unstep (mp); - return -1; + return FALSE; } err = camel_mime_parser_errno (mp); @@ -331,10 +331,10 @@ mime_message_construct_from_parser_sync (CamelMimePart *dw, error, G_IO_ERROR, g_io_error_from_errno (errno), "%s", g_strerror (errno)); - ret = -1; + success = FALSE; } - return ret; + return success; } static void @@ -845,7 +845,10 @@ camel_mime_message_has_8bit_parts (CamelMimeMessage *msg) /* finds the best charset and transfer encoding for a given part */ static CamelTransferEncoding -find_best_encoding (CamelMimePart *part, CamelBestencRequired required, CamelBestencEncoding enctype, gchar **charsetp) +find_best_encoding (CamelMimePart *part, + CamelBestencRequired required, + CamelBestencEncoding enctype, + gchar **charsetp) { CamelMimeFilter *charenc = NULL; CamelTransferEncoding encoding; @@ -1034,7 +1037,9 @@ best_encoding (CamelMimeMessage *msg, CamelMimePart *part, gpointer datap) * parts will be encoded as binary and 8bit textual parts will be encoded as 8bit. **/ void -camel_mime_message_set_best_encoding (CamelMimeMessage *msg, CamelBestencRequired required, CamelBestencEncoding enctype) +camel_mime_message_set_best_encoding (CamelMimeMessage *msg, + CamelBestencRequired required, + CamelBestencEncoding enctype) { struct _enc_data data; diff --git a/camel/camel-mime-message.h b/camel/camel-mime-message.h index f4cac90..3f6ae1f 100644 --- a/camel/camel-mime-message.h +++ b/camel/camel-mime-message.h @@ -93,55 +93,63 @@ struct _CamelMimeMessageClass { CamelMimePartClass parent_class; }; -GType camel_mime_message_get_type (void); - -/* public methods */ -CamelMimeMessage *camel_mime_message_new (void); -void camel_mime_message_set_date (CamelMimeMessage *message, - time_t date, - gint offset); -time_t camel_mime_message_get_date (CamelMimeMessage *message, - gint *offset); -time_t camel_mime_message_get_date_received (CamelMimeMessage *message, - gint *offset); -void camel_mime_message_set_message_id (CamelMimeMessage *message, - const gchar *message_id); -const gchar *camel_mime_message_get_message_id (CamelMimeMessage *message); -void camel_mime_message_set_reply_to (CamelMimeMessage *message, - CamelInternetAddress *reply_to); -CamelInternetAddress * camel_mime_message_get_reply_to (CamelMimeMessage *message); - -void camel_mime_message_set_subject (CamelMimeMessage *message, - const gchar *subject); -const gchar *camel_mime_message_get_subject (CamelMimeMessage *message); -void camel_mime_message_set_from (CamelMimeMessage *message, - CamelInternetAddress *from); -CamelInternetAddress * camel_mime_message_get_from (CamelMimeMessage *message); - -CamelInternetAddress * camel_mime_message_get_recipients (CamelMimeMessage *message, - const gchar *type); -void camel_mime_message_set_recipients (CamelMimeMessage *message, - const gchar *type, - CamelInternetAddress *recipients); - -void camel_mime_message_set_source (CamelMimeMessage *message, - const gchar *identity); -const gchar *camel_mime_message_get_source (CamelMimeMessage *message); +GType camel_mime_message_get_type (void); +CamelMimeMessage * + camel_mime_message_new (void); +void camel_mime_message_set_date (CamelMimeMessage *message, + time_t date, + gint offset); +time_t camel_mime_message_get_date (CamelMimeMessage *message, + gint *offset); +time_t camel_mime_message_get_date_received + (CamelMimeMessage *message, + gint *offset); +void camel_mime_message_set_message_id + (CamelMimeMessage *message, + const gchar *message_id); +const gchar * camel_mime_message_get_message_id + (CamelMimeMessage *message); +void camel_mime_message_set_reply_to (CamelMimeMessage *message, + CamelInternetAddress *reply_to); +CamelInternetAddress * + camel_mime_message_get_reply_to (CamelMimeMessage *message); +void camel_mime_message_set_subject (CamelMimeMessage *message, + const gchar *subject); +const gchar * camel_mime_message_get_subject (CamelMimeMessage *message); +void camel_mime_message_set_from (CamelMimeMessage *message, + CamelInternetAddress *from); +CamelInternetAddress * + camel_mime_message_get_from (CamelMimeMessage *message); +CamelInternetAddress * + camel_mime_message_get_recipients + (CamelMimeMessage *message, + const gchar *type); +void camel_mime_message_set_recipients + (CamelMimeMessage *message, + const gchar *type, + CamelInternetAddress *recipients); +void camel_mime_message_set_source (CamelMimeMessage *message, + const gchar *identity); +const gchar * camel_mime_message_get_source (CamelMimeMessage *message); /* utility functions */ -gboolean camel_mime_message_has_8bit_parts (CamelMimeMessage *message); -void camel_mime_message_set_best_encoding (CamelMimeMessage *message, - CamelBestencRequired required, - CamelBestencEncoding enctype); -void camel_mime_message_encode_8bit_parts (CamelMimeMessage *message); - -CamelMimePart *camel_mime_message_get_part_by_content_id (CamelMimeMessage *message, const gchar *content_id); - -gchar *camel_mime_message_build_mbox_from (CamelMimeMessage *message); - -gboolean camel_mime_message_has_attachment (CamelMimeMessage *message); - -void camel_mime_message_dump (CamelMimeMessage *msg, gint body); +gboolean camel_mime_message_has_8bit_parts + (CamelMimeMessage *message); +void camel_mime_message_set_best_encoding + (CamelMimeMessage *message, + CamelBestencRequired required, + CamelBestencEncoding enctype); +void camel_mime_message_encode_8bit_parts + (CamelMimeMessage *message); +CamelMimePart * camel_mime_message_get_part_by_content_id + (CamelMimeMessage *message, + const gchar *content_id); +gchar * camel_mime_message_build_mbox_from + (CamelMimeMessage *message); +gboolean camel_mime_message_has_attachment + (CamelMimeMessage *message); +void camel_mime_message_dump (CamelMimeMessage *message, + gint body); G_END_DECLS diff --git a/camel/camel-mime-part-utils.c b/camel/camel-mime-part-utils.c index e9c7268..b9aad19 100644 --- a/camel/camel-mime-part-utils.c +++ b/camel/camel-mime-part-utils.c @@ -64,7 +64,7 @@ simple_data_wrapper_construct_from_parser (CamelDataWrapper *dw, GByteArray *buffer; CamelStream *mem; gsize len; - gint retval; + gboolean success; d(printf ("simple_data_wrapper_construct_from_parser()\n")); @@ -78,11 +78,11 @@ simple_data_wrapper_construct_from_parser (CamelDataWrapper *dw, d(printf("message part kept in memory!\n")); mem = camel_stream_mem_new_with_byte_array (buffer); - retval = camel_data_wrapper_construct_from_stream_sync ( + success = camel_data_wrapper_construct_from_stream_sync ( dw, mem, cancellable, error); g_object_unref (mem); - return (retval == 0); + return success; } /** @@ -123,8 +123,8 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw, case CAMEL_MIME_PARSER_STATE_MESSAGE: d(printf("Creating message part\n")); content = (CamelDataWrapper *) camel_mime_message_new (); - success = (camel_mime_part_construct_from_parser_sync ( - (CamelMimePart *)content, mp, cancellable, error) == 0); + success = camel_mime_part_construct_from_parser_sync ( + (CamelMimePart *)content, mp, cancellable, error); break; case CAMEL_MIME_PARSER_STATE_MULTIPART: d(printf("Creating multi-part\n")); @@ -160,6 +160,12 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw, /** * camel_mime_message_build_preview: * + * + * + * This function blocks like crazy. + * + * + * * Since: 2.28 **/ gboolean @@ -186,6 +192,8 @@ camel_mime_message_build_preview (CamelMimePart *msg, /* !camel_content_type_is (dw->mime_type, "text", "html") && */ !camel_content_type_is (dw->mime_type, "text", "calendar")) { CamelStream *mstream, *bstream; + + /* FIXME Pass a GCancellable and GError here. */ mstream = camel_stream_mem_new (); if (camel_data_wrapper_decode_to_stream_sync (dw, mstream, NULL, NULL) > 0) { gchar *line = NULL; diff --git a/camel/camel-mime-part.c b/camel/camel-mime-part.c index e4d7025..8b5bc99 100644 --- a/camel/camel-mime-part.c +++ b/camel/camel-mime-part.c @@ -53,9 +53,9 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_MIME_PART, CamelMimePartPrivate)) -struct _CamelMimePartPrivate { +typedef struct _AsyncContext AsyncContext; - /* TODO: these should be in a camelcontentinfo */ +struct _CamelMimePartPrivate { gchar *description; CamelContentDisposition *disposition; gchar *content_id; @@ -65,6 +65,11 @@ struct _CamelMimePartPrivate { CamelTransferEncoding encoding; }; +struct _AsyncContext { + /* arguments */ + CamelMimeParser *parser; +}; + enum { PROP_0, PROP_CONTENT_ID, @@ -92,6 +97,15 @@ static GHashTable *header_formatted_table; G_DEFINE_TYPE (CamelMimePart, camel_mime_part, CAMEL_TYPE_MEDIUM) +static void +async_context_free (AsyncContext *async_context) +{ + if (async_context->parser != NULL) + g_object_unref (async_context->parser); + + g_slice_free (AsyncContext, async_context); +} + static gssize write_header (CamelStream *stream, const gchar *name, @@ -671,31 +685,32 @@ mime_part_write_to_stream_sync (CamelDataWrapper *dw, return total; } -static gint +static gboolean mime_part_construct_from_stream_sync (CamelDataWrapper *dw, - CamelStream *s, + CamelStream *stream, GCancellable *cancellable, GError **error) { - CamelMimeParser *mp; - gint ret; + CamelMimeParser *parser; + gboolean success; d(printf("mime_part::construct_from_stream()\n")); - mp = camel_mime_parser_new (); - if (camel_mime_parser_init_with_stream (mp, s, error) == -1) { - ret = -1; + parser = camel_mime_parser_new (); + if (camel_mime_parser_init_with_stream (parser, stream, error) == -1) { + success = FALSE; } else { - ret = camel_mime_part_construct_from_parser_sync ( - CAMEL_MIME_PART (dw), mp, cancellable, error); + success = camel_mime_part_construct_from_parser_sync ( + CAMEL_MIME_PART (dw), parser, cancellable, error); } - g_object_unref (mp); - return ret; + g_object_unref (parser); + + return success; } -static gint +static gboolean mime_part_construct_from_parser_sync (CamelMimePart *mime_part, - CamelMimeParser *mp, + CamelMimeParser *parser, GCancellable *cancellable, GError **error) { @@ -705,10 +720,9 @@ mime_part_construct_from_parser_sync (CamelMimePart *mime_part, gchar *buf; gsize len; gint err; - gboolean success; - gboolean retval = 0; + gboolean success = TRUE; - switch (camel_mime_parser_step (mp, &buf, &len)) { + switch (camel_mime_parser_step (parser, &buf, &len)) { case CAMEL_MIME_PARSER_STATE_MESSAGE: /* set the default type of a message always */ if (dw->mime_type) @@ -717,7 +731,7 @@ mime_part_construct_from_parser_sync (CamelMimePart *mime_part, case CAMEL_MIME_PARSER_STATE_HEADER: case CAMEL_MIME_PARSER_STATE_MULTIPART: /* we have the headers, build them into 'us' */ - headers = camel_mime_parser_headers_raw (mp); + headers = camel_mime_parser_headers_raw (parser); /* if content-type exists, process it first, set for fallback charset in headers */ content = camel_header_raw_find(&headers, "content-type", NULL); @@ -734,24 +748,89 @@ mime_part_construct_from_parser_sync (CamelMimePart *mime_part, } success = camel_mime_part_construct_content_from_parser ( - mime_part, mp, cancellable, error); - retval = success ? 0 : -1; + mime_part, parser, cancellable, error); break; default: - g_warning("Invalid state encountered???: %u", camel_mime_parser_state(mp)); + g_warning("Invalid state encountered???: %u", camel_mime_parser_state(parser)); } - err = camel_mime_parser_errno (mp); + err = camel_mime_parser_errno (parser); if (err != 0) { errno = err; g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), "%s", g_strerror (errno)); - retval = -1; + success = FALSE; + } + + return success; +} + +static void +mime_part_construct_from_parser_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_mime_part_construct_from_parser_sync ( + CAMEL_MIME_PART (object), async_context->parser, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); } +} + +static void +mime_part_construct_from_parser (CamelMimePart *mime_part, + CamelMimeParser *parser, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->parser = g_object_ref (parser); + + simple = g_simple_async_result_new ( + G_OBJECT (mime_part), callback, user_data, + mime_part_construct_from_parser); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, mime_part_construct_from_parser_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +mime_part_construct_from_parser_finish (CamelMimePart *mime_part, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; - return retval; + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (mime_part), + mime_part_construct_from_parser), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); } static void @@ -782,6 +861,8 @@ camel_mime_part_class_init (CamelMimePartClass *class) data_wrapper_class->construct_from_stream_sync = mime_part_construct_from_stream_sync; class->construct_from_parser_sync = mime_part_construct_from_parser_sync; + class->construct_from_parser = mime_part_construct_from_parser; + class->construct_from_parser_finish = mime_part_construct_from_parser_finish; g_object_class_install_property ( object_class, @@ -842,245 +923,264 @@ camel_mime_part_init (CamelMimePart *mime_part) data_wrapper->mime_type = camel_content_type_new ("text", "plain"); } -/* **** Content-Description */ +/** + * camel_mime_part_new: + * + * Create a new MIME part. + * + * Returns: a new #CamelMimePart + **/ +CamelMimePart * +camel_mime_part_new (void) +{ + return g_object_new (CAMEL_TYPE_MIME_PART, NULL); +} /** - * camel_mime_part_set_description: - * @mime_part: a #CamelMimePart object - * @description: description of the MIME part + * camel_mime_part_set_content: + * @mime_part: a #CamelMimePart + * @data: data to put into the part + * @length: length of @data + * @type: Content-Type of the data * - * Set a description on the MIME part. + * Utility function used to set the content of a mime part object to + * be the provided data. If @length is 0, this routine can be used as + * a way to remove old content (in which case @data and @type are + * ignored and may be %NULL). **/ void -camel_mime_part_set_description (CamelMimePart *mime_part, - const gchar *description) +camel_mime_part_set_content (CamelMimePart *mime_part, + const gchar *data, + gint length, + const gchar *type) /* why on earth is the type last? */ { - CamelMedium *medium; - gchar *text; + CamelMedium *medium = CAMEL_MEDIUM (mime_part); - g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); - g_return_if_fail (description != NULL); + if (length) { + CamelDataWrapper *dw; + CamelStream *stream; - medium = CAMEL_MEDIUM (mime_part); + dw = camel_data_wrapper_new (); + camel_data_wrapper_set_mime_type (dw, type); + stream = camel_stream_mem_new_with_buffer (data, length); + camel_data_wrapper_construct_from_stream_sync ( + dw, stream, NULL, NULL); + g_object_unref (stream); + camel_medium_set_content (medium, dw); + g_object_unref (dw); + } else + camel_medium_set_content (medium, NULL); +} - text = camel_header_encode_string ((guchar *) description); - camel_medium_set_header (medium, "Content-Description", text); - g_free (text); +/** + * camel_mime_part_get_content_disposition: + * @mime_part: a #CamelMimePart + * + * Get the disposition of the MIME part as a structure. + * Returned pointer is owned by #mime_part. + * + * Returns: the disposition structure + * + * Since: 2.30 + **/ +const CamelContentDisposition * +camel_mime_part_get_content_disposition (CamelMimePart *mime_part) +{ + g_return_val_if_fail (mime_part != NULL, NULL); - g_object_notify (G_OBJECT (mime_part), "description"); + return mime_part->priv->disposition; } /** - * camel_mime_part_get_description: - * @mime_part: a #CamelMimePart object + * camel_mime_part_get_content_id: + * @mime_part: a #CamelMimePart * - * Get the description of the MIME part. + * Get the content-id field of a MIME part. * - * Returns: the description + * Returns: the content-id field of the MIME part **/ const gchar * -camel_mime_part_get_description (CamelMimePart *mime_part) +camel_mime_part_get_content_id (CamelMimePart *mime_part) { g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); - return mime_part->priv->description; + return mime_part->priv->content_id; } -/* **** Content-Disposition */ - /** - * camel_mime_part_set_disposition: - * @mime_part: a #CamelMimePart object - * @disposition: disposition of the MIME part + * camel_mime_part_set_content_id: + * @mime_part: a #CamelMimePart + * @contentid: content id * - * Set a disposition on the MIME part. + * Set the content-id field on a MIME part. **/ void -camel_mime_part_set_disposition (CamelMimePart *mime_part, - const gchar *disposition) +camel_mime_part_set_content_id (CamelMimePart *mime_part, + const gchar *contentid) { CamelMedium *medium; - gchar *text; + gchar *cid, *id; g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); medium = CAMEL_MEDIUM (mime_part); - /* we poke in a new disposition (so we dont lose 'filename', etc) */ - if (mime_part->priv->disposition == NULL) - mime_part_set_disposition (mime_part, disposition); + if (contentid) + id = g_strstrip (g_strdup (contentid)); + else + id = camel_header_msgid_generate (); - if (mime_part->priv->disposition != NULL) { - g_free (mime_part->priv->disposition->disposition); - mime_part->priv->disposition->disposition = g_strdup (disposition); - } + cid = g_strdup_printf ("<%s>", id); + camel_medium_set_header (medium, "Content-ID", cid); + g_free (cid); - text = camel_content_disposition_format (mime_part->priv->disposition); - camel_medium_set_header (medium, "Content-Disposition", text); - g_free (text); + g_free (id); - g_object_notify (G_OBJECT (mime_part), "disposition"); + g_object_notify (G_OBJECT (mime_part), "content-id"); } /** - * camel_mime_part_get_disposition: - * @mime_part: a #CamelMimePart object + * camel_mime_part_get_content_location: + * @mime_part: a #CamelMimePart * - * Get the disposition of the MIME part. + * Get the content-location field of a MIME part. * - * Returns: the disposition + * Returns: the content-location field of a MIME part **/ const gchar * -camel_mime_part_get_disposition (CamelMimePart *mime_part) +camel_mime_part_get_content_location (CamelMimePart *mime_part) { g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); - if (mime_part->priv->disposition) - return mime_part->priv->disposition->disposition; - else - return NULL; + return mime_part->priv->content_location; } /** - * camel_mime_part_get_content_disposition: - * @mime_part: a #CamelMimePart object + * camel_mime_part_set_content_location: + * @mime_part: a #CamelMimePart + * @location: the content-location value of the MIME part * - * Get the disposition of the MIME part as a structure. - * Returned pointer is owned by #mime_part. + * Set the content-location field of the MIME part. + **/ +void +camel_mime_part_set_content_location (CamelMimePart *mime_part, + const gchar *location) +{ + CamelMedium *medium; + + g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); + + medium = CAMEL_MEDIUM (mime_part); + + /* FIXME: this should perform content-location folding */ + camel_medium_set_header (medium, "Content-Location", location); + + g_object_notify (G_OBJECT (mime_part), "content-location"); +} + +/** + * camel_mime_part_get_content_md5: + * @mime_part: a #CamelMimePart * - * Returns: the disposition structure + * Get the content-md5 field of the MIME part. * - * Since: 2.30 + * Returns: the content-md5 field of the MIME part **/ -const CamelContentDisposition * -camel_mime_part_get_content_disposition (CamelMimePart *mime_part) +const gchar * +camel_mime_part_get_content_md5 (CamelMimePart *mime_part) { - g_return_val_if_fail (mime_part != NULL, NULL); + g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); - return mime_part->priv->disposition; + return mime_part->priv->content_md5; } -/* **** Content-Disposition: filename="xxx" */ - /** - * camel_mime_part_set_filename: - * @mime_part: a #CamelMimePart object - * @filename: filename given to the MIME part + * camel_mime_part_set_content_md5: + * @mime_part: a #CamelMimePart + * @md5sum: the md5sum of the MIME part * - * Set the filename on a MIME part. + * Set the content-md5 field of the MIME part. **/ void -camel_mime_part_set_filename (CamelMimePart *mime_part, const gchar *filename) +camel_mime_part_set_content_md5 (CamelMimePart *mime_part, + const gchar *content_md5) { - CamelDataWrapper *dw; CamelMedium *medium; - gchar *str; - - medium = CAMEL_MEDIUM (mime_part); - - if (mime_part->priv->disposition == NULL) - mime_part->priv->disposition = - camel_content_disposition_decode("attachment"); - camel_header_set_param ( - &mime_part->priv->disposition->params, "filename", filename); - str = camel_content_disposition_format (mime_part->priv->disposition); + g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); - camel_medium_set_header (medium, "Content-Disposition", str); - g_free (str); + medium = CAMEL_MEDIUM (mime_part); - dw = (CamelDataWrapper *) mime_part; - if (!dw->mime_type) - dw->mime_type = camel_content_type_new ("application", "octet-stream"); - camel_content_type_set_param (dw->mime_type, "name", filename); - str = camel_content_type_format (dw->mime_type); - camel_medium_set_header (medium, "Content-Type", str); - g_free (str); + camel_medium_set_header (medium, "Content-MD5", content_md5); } /** - * camel_mime_part_get_filename: - * @mime_part: a #CamelMimePart object + * camel_mime_part_get_content_languages: + * @mime_part: a #CamelMimePart * - * Get the filename of a MIME part. + * Get the Content-Languages set on the MIME part. * - * Returns: the filename of the MIME part + * Returns: a #GList of languages **/ -const gchar * -camel_mime_part_get_filename (CamelMimePart *mime_part) +const GList * +camel_mime_part_get_content_languages (CamelMimePart *mime_part) { - if (mime_part->priv->disposition) { - const gchar *name = camel_header_param ( - mime_part->priv->disposition->params, "filename"); - if (name) - return name; - } + g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); - return camel_content_type_param (((CamelDataWrapper *) mime_part)->mime_type, "name"); + return mime_part->priv->content_languages; } -/* **** Content-ID: */ - /** - * camel_mime_part_set_content_id: - * @mime_part: a #CamelMimePart object - * @contentid: content id + * camel_mime_part_set_content_languages: + * @mime_part: a #CamelMimePart + * @content_languages: list of languages * - * Set the content-id field on a MIME part. + * Set the Content-Languages field of a MIME part. **/ void -camel_mime_part_set_content_id (CamelMimePart *mime_part, - const gchar *contentid) +camel_mime_part_set_content_languages (CamelMimePart *mime_part, + GList *content_languages) { - CamelMedium *medium; - gchar *cid, *id; - g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); - medium = CAMEL_MEDIUM (mime_part); - - if (contentid) - id = g_strstrip (g_strdup (contentid)); - else - id = camel_header_msgid_generate (); - - cid = g_strdup_printf ("<%s>", id); - camel_medium_set_header (medium, "Content-ID", cid); - g_free (cid); + if (mime_part->priv->content_languages) + camel_string_list_free (mime_part->priv->content_languages); - g_free (id); + mime_part->priv->content_languages = content_languages; - g_object_notify (G_OBJECT (mime_part), "content-id"); + /* FIXME: translate to a header and set it */ } /** - * camel_mime_part_get_content_id: - * @mime_part: a #CamelMimePart object + * camel_mime_part_get_content_type: + * @mime_part: a #CamelMimePart * - * Get the content-id field of a MIME part. + * Get the Content-Type of a MIME part. * - * Returns: the content-id field of the MIME part + * Returns: the parsed #CamelContentType of the MIME part **/ -const gchar * -camel_mime_part_get_content_id (CamelMimePart *mime_part) +CamelContentType * +camel_mime_part_get_content_type (CamelMimePart *mime_part) { + CamelDataWrapper *data_wrapper; + g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); - return mime_part->priv->content_id; -} + data_wrapper = CAMEL_DATA_WRAPPER (mime_part); -/* **** Content-MD5: */ + return camel_data_wrapper_get_mime_type_field (data_wrapper); +} /** - * camel_mime_part_set_content_md5: - * @mime_part: a #CamelMimePart object - * @md5sum: the md5sum of the MIME part + * camel_mime_part_set_content_type: + * @mime_part: a #CamelMimePart + * @content_type: content-type string * - * Set the content-md5 field of the MIME part. + * Set the content-type on a MIME part. **/ void -camel_mime_part_set_content_md5 (CamelMimePart *mime_part, - const gchar *content_md5) +camel_mime_part_set_content_type (CamelMimePart *mime_part, + const gchar *content_type) { CamelMedium *medium; @@ -1088,93 +1188,107 @@ camel_mime_part_set_content_md5 (CamelMimePart *mime_part, medium = CAMEL_MEDIUM (mime_part); - camel_medium_set_header (medium, "Content-MD5", content_md5); + camel_medium_set_header (medium, "Content-Type", content_type); } /** - * camel_mime_part_get_content_md5: - * @mime_part: a #CamelMimePart object + * camel_mime_part_get_description: + * @mime_part: a #CamelMimePart * - * Get the content-md5 field of the MIME part. + * Get the description of the MIME part. * - * Returns: the content-md5 field of the MIME part + * Returns: the description **/ const gchar * -camel_mime_part_get_content_md5 (CamelMimePart *mime_part) +camel_mime_part_get_description (CamelMimePart *mime_part) { g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); - return mime_part->priv->content_md5; + return mime_part->priv->description; } -/* **** Content-Location: */ - /** - * camel_mime_part_set_content_location: - * @mime_part: a #CamelMimePart object - * @location: the content-location value of the MIME part + * camel_mime_part_set_description: + * @mime_part: a #CamelMimePart + * @description: description of the MIME part * - * Set the content-location field of the MIME part. + * Set a description on the MIME part. **/ void -camel_mime_part_set_content_location (CamelMimePart *mime_part, - const gchar *location) +camel_mime_part_set_description (CamelMimePart *mime_part, + const gchar *description) { CamelMedium *medium; + gchar *text; g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); + g_return_if_fail (description != NULL); medium = CAMEL_MEDIUM (mime_part); - /* FIXME: this should perform content-location folding */ - camel_medium_set_header (medium, "Content-Location", location); + text = camel_header_encode_string ((guchar *) description); + camel_medium_set_header (medium, "Content-Description", text); + g_free (text); - g_object_notify (G_OBJECT (mime_part), "content-location"); + g_object_notify (G_OBJECT (mime_part), "description"); } /** - * camel_mime_part_get_content_location: - * @mime_part: a #CamelMimePart object + * camel_mime_part_get_disposition: + * @mime_part: a #CamelMimePart * - * Get the content-location field of a MIME part. + * Get the disposition of the MIME part. * - * Returns: the content-location field of a MIME part + * Returns: the disposition **/ const gchar * -camel_mime_part_get_content_location (CamelMimePart *mime_part) +camel_mime_part_get_disposition (CamelMimePart *mime_part) { g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); - return mime_part->priv->content_location; + if (mime_part->priv->disposition) + return mime_part->priv->disposition->disposition; + else + return NULL; } -/* **** Content-Transfer-Encoding: */ - /** - * camel_mime_part_set_encoding: - * @mime_part: a #CamelMimePart object - * @encoding: a #CamelTransferEncoding + * camel_mime_part_set_disposition: + * @mime_part: a #CamelMimePart + * @disposition: disposition of the MIME part * - * Set the Content-Transfer-Encoding to use on a MIME part. + * Set a disposition on the MIME part. **/ void -camel_mime_part_set_encoding (CamelMimePart *mime_part, - CamelTransferEncoding encoding) +camel_mime_part_set_disposition (CamelMimePart *mime_part, + const gchar *disposition) { CamelMedium *medium; - const gchar *text; + gchar *text; g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); medium = CAMEL_MEDIUM (mime_part); - text = camel_transfer_encoding_to_string (encoding); - camel_medium_set_header (medium, "Content-Transfer-Encoding", text); + /* we poke in a new disposition (so we dont lose 'filename', etc) */ + if (mime_part->priv->disposition == NULL) + mime_part_set_disposition (mime_part, disposition); + + if (mime_part->priv->disposition != NULL) { + g_free (mime_part->priv->disposition->disposition); + mime_part->priv->disposition->disposition = g_strdup (disposition); + } + + text = camel_content_disposition_format (mime_part->priv->disposition); + camel_medium_set_header (medium, "Content-Disposition", text); + g_free (text); + + g_object_notify (G_OBJECT (mime_part), "disposition"); } /** * camel_mime_part_get_encoding: - * @mime_part: a #CamelMimePart object + * @mime_part: a #CamelMimePart * * Get the Content-Transfer-Encoding of a MIME part. * @@ -1190,193 +1304,185 @@ camel_mime_part_get_encoding (CamelMimePart *mime_part) return mime_part->priv->encoding; } -/* FIXME: do something with this stuff ... */ - /** - * camel_mime_part_set_content_languages: - * @mime_part: a #CamelMimePart object - * @content_languages: list of languages + * camel_mime_part_set_encoding: + * @mime_part: a #CamelMimePart + * @encoding: a #CamelTransferEncoding * - * Set the Content-Languages field of a MIME part. + * Set the Content-Transfer-Encoding to use on a MIME part. **/ void -camel_mime_part_set_content_languages (CamelMimePart *mime_part, - GList *content_languages) +camel_mime_part_set_encoding (CamelMimePart *mime_part, + CamelTransferEncoding encoding) { - g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); + CamelMedium *medium; + const gchar *text; - if (mime_part->priv->content_languages) - camel_string_list_free (mime_part->priv->content_languages); + g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); - mime_part->priv->content_languages = content_languages; + medium = CAMEL_MEDIUM (mime_part); - /* FIXME: translate to a header and set it */ + text = camel_transfer_encoding_to_string (encoding); + camel_medium_set_header (medium, "Content-Transfer-Encoding", text); } /** - * camel_mime_part_get_content_languages: - * @mime_part: a #CamelMimePart object + * camel_mime_part_get_filename: + * @mime_part: a #CamelMimePart * - * Get the Content-Languages set on the MIME part. + * Get the filename of a MIME part. * - * Returns: a #GList of languages + * Returns: the filename of the MIME part **/ -const GList * -camel_mime_part_get_content_languages (CamelMimePart *mime_part) +const gchar * +camel_mime_part_get_filename (CamelMimePart *mime_part) { - g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); + if (mime_part->priv->disposition) { + const gchar *name = camel_header_param ( + mime_part->priv->disposition->params, "filename"); + if (name) + return name; + } - return mime_part->priv->content_languages; + return camel_content_type_param ( + ((CamelDataWrapper *) mime_part)->mime_type, "name"); } -/* **** */ - -/* **** Content-Type: */ - /** - * camel_mime_part_set_content_type: - * @mime_part: a #CamelMimePart object - * @content_type: content-type string + * camel_mime_part_set_filename: + * @mime_part: a #CamelMimePart + * @filename: filename given to the MIME part * - * Set the content-type on a MIME part. + * Set the filename on a MIME part. **/ void -camel_mime_part_set_content_type (CamelMimePart *mime_part, - const gchar *content_type) +camel_mime_part_set_filename (CamelMimePart *mime_part, + const gchar *filename) { + CamelDataWrapper *dw; CamelMedium *medium; - - g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); + gchar *str; medium = CAMEL_MEDIUM (mime_part); - camel_medium_set_header (medium, "Content-Type", content_type); -} + if (mime_part->priv->disposition == NULL) + mime_part->priv->disposition = + camel_content_disposition_decode("attachment"); -/** - * camel_mime_part_get_content_type: - * @mime_part: a #CamelMimePart object - * - * Get the Content-Type of a MIME part. - * - * Returns: the parsed #CamelContentType of the MIME part - **/ -CamelContentType * -camel_mime_part_get_content_type (CamelMimePart *mime_part) -{ - g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); + camel_header_set_param ( + &mime_part->priv->disposition->params, "filename", filename); + str = camel_content_disposition_format (mime_part->priv->disposition); + + camel_medium_set_header (medium, "Content-Disposition", str); + g_free (str); - return camel_data_wrapper_get_mime_type_field ((CamelDataWrapper *) mime_part); + dw = (CamelDataWrapper *) mime_part; + if (!dw->mime_type) + dw->mime_type = camel_content_type_new ("application", "octet-stream"); + camel_content_type_set_param (dw->mime_type, "name", filename); + str = camel_content_type_format (dw->mime_type); + camel_medium_set_header (medium, "Content-Type", str); + g_free (str); } /** * camel_mime_part_construct_from_parser_sync: - * @mime_part: a #CamelMimePart object - * @parser: a #CamelMimeParser object + * @mime_part: a #CamelMimePart + * @parser: a #CamelMimeParser * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Constructs a MIME part from a parser. * - * Returns: %0 on success or %-1 on fail + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -gint +gboolean camel_mime_part_construct_from_parser_sync (CamelMimePart *mime_part, - CamelMimeParser *mp, + CamelMimeParser *parser, GCancellable *cancellable, GError **error) { CamelMimePartClass *class; - gint retval; + gboolean success; g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), -1); - g_return_val_if_fail (CAMEL_IS_MIME_PARSER (mp), -1); + g_return_val_if_fail (CAMEL_IS_MIME_PARSER (parser), -1); class = CAMEL_MIME_PART_GET_CLASS (mime_part); g_return_val_if_fail (class->construct_from_parser_sync != NULL, -1); - retval = class->construct_from_parser_sync ( - mime_part, mp, cancellable, error); + success = class->construct_from_parser_sync ( + mime_part, parser, cancellable, error); CAMEL_CHECK_GERROR ( - mime_part, construct_from_parser_sync, retval == 0, error); + mime_part, construct_from_parser_sync, success, error); - return retval; + return success; } /** - * camel_mime_part_new: + * camel_mime_part_construct_from_parser: + * @mime_part: a #CamelMimePart + * @parser: a #CamelMimeParser + * @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 * - * Create a new MIME part. + * Asynchronously constructs a MIME part from a parser. * - * Returns: a new #CamelMimePart object - **/ -CamelMimePart * -camel_mime_part_new (void) -{ - return g_object_new (CAMEL_TYPE_MIME_PART, NULL); -} - -/** - * camel_mime_part_set_content: - * @mime_part: a #CamelMimePart object - * @data: data to put into the part - * @length: length of @data - * @type: Content-Type of the data + * When the operation is finished, @callback will be called. You can then + * call camel_mime_part_construct_from_parser_finish() to get the result of + * the operation. * - * Utility function used to set the content of a mime part object to - * be the provided data. If @length is 0, this routine can be used as - * a way to remove old content (in which case @data and @type are - * ignored and may be %NULL). + * Since: 2.34 **/ void -camel_mime_part_set_content (CamelMimePart *mime_part, - const gchar *data, gint length, - const gchar *type) /* why on earth is the type last? */ +camel_mime_part_construct_from_parser (CamelMimePart *mime_part, + CamelMimeParser *parser, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - CamelMedium *medium = CAMEL_MEDIUM (mime_part); + CamelMimePartClass *class; - if (length) { - CamelDataWrapper *dw; - CamelStream *stream; + g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); + g_return_if_fail (CAMEL_IS_MIME_PARSER (parser)); - dw = camel_data_wrapper_new (); - camel_data_wrapper_set_mime_type (dw, type); - stream = camel_stream_mem_new_with_buffer (data, length); - camel_data_wrapper_construct_from_stream_sync ( - dw, stream, NULL, NULL); - g_object_unref (stream); - camel_medium_set_content (medium, dw); - g_object_unref (dw); - } else - camel_medium_set_content (medium, NULL); + class = CAMEL_MIME_PART_GET_CLASS (mime_part); + g_return_if_fail (class->construct_from_parser != NULL); + + class->construct_from_parser ( + mime_part, parser, io_priority, + cancellable, callback, user_data); } /** - * camel_mime_part_get_content_size: - * @mime_part: a #CamelMimePart object + * camel_mime_part_construct_from_parser_finish: + * @mime_part: a #CamelMimePart + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL * - * Get the decoded size of the MIME part's content. + * Finishes the operation started with camel_mime_part_construct_from_parser(). * - * Returns: the size of the MIME part's content in bytes. + * Returns: %TRUE on success, %FALSE on error * - * Since: 2.22 + * Since: 2.34 **/ -gsize -camel_mime_part_get_content_size (CamelMimePart *mime_part) +gboolean +camel_mime_part_construct_from_parser_finish (CamelMimePart *mime_part, + GAsyncResult *result, + GError **error) { - CamelStream *null; - CamelDataWrapper *dw; - gsize size; - - g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), 0); - - dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); + CamelMimePartClass *class; - null = camel_stream_null_new (); - camel_data_wrapper_decode_to_stream_sync (dw, null, NULL, NULL); - size = CAMEL_STREAM_NULL (null)->written; + g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); - g_object_unref (null); + class = CAMEL_MIME_PART_GET_CLASS (mime_part); + g_return_val_if_fail (class->construct_from_parser_finish != NULL, FALSE); - return size; + return class->construct_from_parser_finish (mime_part, result, error); } diff --git a/camel/camel-mime-part.h b/camel/camel-mime-part.h index 748a31b..89b0dc1 100644 --- a/camel/camel-mime-part.h +++ b/camel/camel-mime-part.h @@ -69,10 +69,25 @@ struct _CamelMimePart { struct _CamelMimePartClass { CamelMediumClass parent_class; - gint (*construct_from_parser_sync) (CamelMimePart *mime_part, + /* Synchronous I/O Methods */ + gboolean (*construct_from_parser_sync) + (CamelMimePart *mime_part, CamelMimeParser *parser, GCancellable *cancellable, GError **error); + + /* Asynchronous I/O Methods (all have defaults) */ + void (*construct_from_parser) + (CamelMimePart *mime_part, + CamelMimeParser *parser, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*construct_from_parser_finish) + (CamelMimePart *mime_part, + GAsyncResult *result, + GError **error); }; GType camel_mime_part_get_type (void); @@ -119,13 +134,23 @@ void camel_mime_part_set_content (CamelMimePart *mime_part, const gchar *data, gint length, const gchar *type); -gsize camel_mime_part_get_content_size - (CamelMimePart *mime_part); -gint camel_mime_part_construct_from_parser_sync + +gboolean camel_mime_part_construct_from_parser_sync (CamelMimePart *mime_part, CamelMimeParser *parser, GCancellable *cancellable, GError **error); +void camel_mime_part_construct_from_parser + (CamelMimePart *mime_part, + CamelMimeParser *parser, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_mime_part_construct_from_parser_finish + (CamelMimePart *mime_part, + GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/camel/camel-multipart-signed.c b/camel/camel-multipart-signed.c index 21968fb..1affe87 100644 --- a/camel/camel-multipart-signed.c +++ b/camel/camel-multipart-signed.c @@ -359,7 +359,7 @@ file_error: return -1; } -static gint +static gboolean multipart_signed_construct_from_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, @@ -370,11 +370,11 @@ multipart_signed_construct_from_stream_sync (CamelDataWrapper *data_wrapper, if (camel_stream_write_to_stream ( stream, mem, cancellable, error) == -1) - return -1; + return FALSE; multipart_signed_set_stream (mps, mem); - return 0; + return TRUE; } static void diff --git a/camel/camel-net-utils.c b/camel/camel-net-utils.c index 6769285..13d3b97 100644 --- a/camel/camel-net-utils.c +++ b/camel/camel-net-utils.c @@ -691,7 +691,7 @@ camel_getaddrinfo (const gchar *name, if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; - camel_operation_start_transient ( + camel_operation_push_message ( cancellable, _("Resolving: %s"), name); /* force ipv4 addresses only */ @@ -729,7 +729,7 @@ camel_getaddrinfo (const gchar *name, cs_freeinfo (msg); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return res; } @@ -841,7 +841,7 @@ camel_getnameinfo (const struct sockaddr *sa, if (g_cancellable_set_error_if_cancelled (cancellable, error)) return -1; - camel_operation_start_transient ( + camel_operation_push_message ( cancellable, _("Resolving address")); msg = g_malloc0 (sizeof (*msg)); @@ -879,7 +879,7 @@ camel_getnameinfo (const struct sockaddr *sa, cs_freeinfo (msg); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return result; } diff --git a/camel/camel-offline-folder.c b/camel/camel-offline-folder.c index 73338f6..7e755d2 100644 --- a/camel/camel-offline-folder.c +++ b/camel/camel-offline-folder.c @@ -37,10 +37,17 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_OFFLINE_FOLDER, CamelOfflineFolderPrivate)) +typedef struct _AsyncContext AsyncContext; + struct _CamelOfflineFolderPrivate { gboolean offline_sync; }; +struct _AsyncContext { + /* arguments */ + gchar *expression; +}; + struct _offline_downsync_msg { CamelSessionThreadMsg msg; @@ -58,12 +65,20 @@ enum { G_DEFINE_TYPE (CamelOfflineFolder, camel_offline_folder, CAMEL_TYPE_FOLDER) static void +async_context_free (AsyncContext *async_context) +{ + g_free (async_context->expression); + + g_slice_free (AsyncContext, async_context); +} + +static void offline_downsync_sync (CamelSession *session, CamelSessionThreadMsg *mm) { struct _offline_downsync_msg *m = (struct _offline_downsync_msg *) mm; gint i; - camel_operation_start ( + camel_operation_push_message ( mm->cancellable, _("Downloading new messages for offline mode")); @@ -84,7 +99,7 @@ offline_downsync_sync (CamelSession *session, CamelSessionThreadMsg *mm) "(match-all)", NULL, &mm->error); } - camel_operation_end (mm->cancellable); + camel_operation_pop_message (mm->cancellable); } static void @@ -174,7 +189,7 @@ offline_folder_downsync_sync (CamelOfflineFolder *offline, GPtrArray *uids, *uncached_uids = NULL; gint i; - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Syncing messages in folder '%s' to disk"), camel_folder_get_full_name (folder)); @@ -207,12 +222,77 @@ done: if (uncached_uids) camel_folder_free_uids (folder, uncached_uids); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return TRUE; } static void +offline_folder_downsync_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_offline_folder_downsync_sync ( + CAMEL_OFFLINE_FOLDER (object), async_context->expression, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +offline_folder_downsync (CamelOfflineFolder *folder, + const gchar *expression, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->expression = g_strdup (expression); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, + user_data, offline_folder_downsync); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, offline_folder_downsync_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +offline_folder_downsync_finish (CamelOfflineFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), offline_folder_downsync), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void camel_offline_folder_class_init (CamelOfflineFolderClass *class) { GObjectClass *object_class; @@ -224,6 +304,8 @@ camel_offline_folder_class_init (CamelOfflineFolderClass *class) object_class->get_property = offline_folder_get_property; class->downsync_sync = offline_folder_downsync_sync; + class->downsync = offline_folder_downsync; + class->downsync_finish = offline_folder_downsync_finish; g_object_class_install_property ( object_class, @@ -249,51 +331,53 @@ camel_offline_folder_init (CamelOfflineFolder *folder) /** * camel_offline_folder_get_offline_sync: - * @offline_folder: a #CamelOfflineFolder + * @folder: a #CamelOfflineFolder * * Since: 2.32 **/ gboolean -camel_offline_folder_get_offline_sync (CamelOfflineFolder *offline_folder) +camel_offline_folder_get_offline_sync (CamelOfflineFolder *folder) { - g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline_folder), FALSE); + g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE); - return offline_folder->priv->offline_sync; + return folder->priv->offline_sync; } /** * camel_offline_folder_set_offline_sync: - * @offline_folder: a #CamelOfflineFolder + * @folder: a #CamelOfflineFolder * @offline_sync: whether to synchronize for offline use * * Since: 2.32 **/ void -camel_offline_folder_set_offline_sync (CamelOfflineFolder *offline_folder, +camel_offline_folder_set_offline_sync (CamelOfflineFolder *folder, gboolean offline_sync) { - g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline_folder)); + g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder)); - offline_folder->priv->offline_sync = offline_sync; + folder->priv->offline_sync = offline_sync; - g_object_notify (G_OBJECT (offline_folder), "offline-sync"); + g_object_notify (G_OBJECT (folder), "offline-sync"); } /** * camel_offline_folder_downsync_sync: - * @offline: a #CamelOfflineFolder object + * @folder: a #CamelOfflineFolder * @expression: search expression describing which set of messages * to downsync (%NULL for all) * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * - * Syncs messages in @offline described by the search @expression to + * Synchronizes messages in @folder described by the search @expression to * the local machine for offline availability. * - * Returns: %TRUE on success, %FALSE on failure + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ gboolean -camel_offline_folder_downsync_sync (CamelOfflineFolder *offline, +camel_offline_folder_downsync_sync (CamelOfflineFolder *folder, const gchar *expression, GCancellable *cancellable, GError **error) @@ -301,14 +385,81 @@ camel_offline_folder_downsync_sync (CamelOfflineFolder *offline, CamelOfflineFolderClass *class; gboolean success; - g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline), FALSE); + g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE); - class = CAMEL_OFFLINE_FOLDER_GET_CLASS (offline); + class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder); g_return_val_if_fail (class->downsync_sync != NULL, FALSE); success = class->downsync_sync ( - offline, expression, cancellable, error); - CAMEL_CHECK_GERROR (offline, downsync_sync, success, error); + folder, expression, cancellable, error); + CAMEL_CHECK_GERROR (folder, downsync_sync, success, error); return success; } + +/** + * camel_offline_folder_downsync: + * @folder: a #CamelOfflineFolder + * @expression: search expression describing which set of messages + * to downsync (%NULL for all) + * @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 + * + * Synchronizes messages in @folder described by the search @expression to + * the local machine asynchronously for offline availability. + * + * When the operation is finished, @callback will be called. You can then + * call camel_offline_folder_downsync_finish() to get the result of the + * operation. + * + * Since: 2.34 + **/ +void +camel_offline_folder_downsync (CamelOfflineFolder *folder, + const gchar *expression, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelOfflineFolderClass *class; + + g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder)); + + class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder); + g_return_if_fail (class->downsync != NULL); + + class->downsync ( + folder, expression, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_offline_folder_downsync_finish: + * @folder: a #CamelOfflineFolder + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_offline_folder_downsync(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_offline_folder_downsync_finish (CamelOfflineFolder *folder, + GAsyncResult *result, + GError **error) +{ + CamelOfflineFolderClass *class; + + g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder); + g_return_val_if_fail (class->downsync_finish != NULL, FALSE); + + return class->downsync_finish (folder, result, error); +} diff --git a/camel/camel-offline-folder.h b/camel/camel-offline-folder.h index d3ca48c..977e769 100644 --- a/camel/camel-offline-folder.h +++ b/camel/camel-offline-folder.h @@ -62,22 +62,45 @@ struct _CamelOfflineFolder { struct _CamelOfflineFolderClass { CamelFolderClass parent_class; + /* Synchronous I/O Methods */ gboolean (*downsync_sync) (CamelOfflineFolder *folder, const gchar *expression, GCancellable *cancellable, GError **error); + + /* Asynchronous I/O Methods (all have defaults) */ + void (*downsync) (CamelOfflineFolder *folder, + const gchar *expression, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*downsync_finish) (CamelOfflineFolder *folder, + GAsyncResult *result, + GError **error); }; GType camel_offline_folder_get_type (void); gboolean camel_offline_folder_get_offline_sync - (CamelOfflineFolder *offline); + (CamelOfflineFolder *folder); void camel_offline_folder_set_offline_sync - (CamelOfflineFolder *offline, + (CamelOfflineFolder *folder, gboolean offline_sync); + gboolean camel_offline_folder_downsync_sync - (CamelOfflineFolder *offline, + (CamelOfflineFolder *folder, + const gchar *expression, + GCancellable *cancellable, + GError **error); +void camel_offline_folder_downsync (CamelOfflineFolder *folder, const gchar *expression, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_offline_folder_downsync_finish + (CamelOfflineFolder *folder, + GAsyncResult *result, GError **error); G_END_DECLS diff --git a/camel/camel-operation.c b/camel/camel-operation.c index 82c6989..f00c92b 100644 --- a/camel/camel-operation.c +++ b/camel/camel-operation.c @@ -38,20 +38,13 @@ typedef struct _StatusNode StatusNode; struct _StatusNode { - gboolean transient; - gchar *msg; - gint pc; /* last percentage reported */ - guint stamp; /* last time stamp reported */ + CamelOperation *operation; + guint source_id; /* for timeout or idle */ + gchar *message; + gint percent; }; struct _CamelOperationPrivate { - guint status_idle_id; - - /* For the next 'status' signal. */ - gchar *status_msg; - gint status_pc; - - guint status_update; GQueue status_stack; @@ -66,9 +59,6 @@ enum { LAST_SIGNAL }; -/* Delay before a transient operation has any effect on the status */ -#define CAMEL_OPERATION_TRANSIENT_DELAY (5) - static GStaticRecMutex operation_lock = G_STATIC_REC_MUTEX_INIT; #define LOCK() g_static_rec_mutex_lock (&operation_lock) #define UNLOCK() g_static_rec_mutex_unlock (&operation_lock) @@ -79,85 +69,56 @@ static guint signals[LAST_SIGNAL]; G_DEFINE_TYPE (CamelOperation, camel_operation, G_TYPE_CANCELLABLE) -static StatusNode * -status_node_new (CamelOperation *operation) -{ - StatusNode *node; - - node = g_slice_new0 (StatusNode); - g_queue_push_head (&operation->priv->status_stack, node); - - return node; -} - static void status_node_free (StatusNode *node) { - g_free (node->msg); - g_slice_free (StatusNode, node); -} + g_free (node->message); -static guint -stamp (void) -{ - GTimeVal tv; + if (node->source_id > 0) + g_source_remove (node->source_id); - g_get_current_time (&tv); - /* update 4 times/second */ - return (tv.tv_sec * 4) + tv.tv_usec / (1000000/4); + g_slice_free (StatusNode, node); } static gboolean -operation_idle_cb (CamelOperation *operation) +operation_emit_status_cb (StatusNode *node) { - gchar *msg; - gint pc; + StatusNode *head_node; + gchar *message = NULL; + gint percent = 0; /* Keep the operation alive until we emit the signal, * otherwise it might be finalized between unlocking * the mutex and emitting the signal. */ - g_object_ref (operation); + g_object_ref (node->operation); LOCK (); - msg = operation->priv->status_msg; - operation->priv->status_msg = NULL; + node->source_id = 0; - pc = operation->priv->status_pc; + head_node = g_queue_peek_head (&node->operation->priv->status_stack); - operation->priv->status_idle_id = 0; + if (node == head_node) { + message = g_strdup (node->message); + percent = node->percent; + } UNLOCK (); - if (msg != NULL) { - g_signal_emit (operation, signals[STATUS], 0, msg, pc); - g_free (msg); + if (message != NULL) { + g_signal_emit ( + node->operation, + signals[STATUS], 0, + message, percent); + g_free (message); } - g_object_unref (operation); + g_object_unref (node->operation); return FALSE; } static void -operation_queue_status_update (CamelOperation *operation, - StatusNode *node) -{ - LOCK (); - - if (operation->priv->status_idle_id == 0) - operation->priv->status_idle_id = g_idle_add ( - (GSourceFunc) operation_idle_cb, operation); - - g_free (operation->priv->status_msg); - operation->priv->status_msg = g_strdup (node->msg); - - operation->priv->status_pc = node->pc; - - UNLOCK (); -} - -static void operation_flush_msgport (CamelOperation *operation) { CamelOperationPrivate *priv = operation->priv; @@ -183,16 +144,13 @@ operation_finalize (GObject *object) g_queue_remove (&operation_list, object); - if (priv->status_idle_id > 0) - g_source_remove (priv->status_idle_id); - operation_flush_msgport (CAMEL_OPERATION (object)); camel_msgport_destroy (priv->cancel_port); while ((node = g_queue_pop_head (&priv->status_stack)) != NULL) { g_warning ( "CamelOperation status stack non-empty: %s", - node->msg); + node->message); status_node_free (node); } @@ -398,24 +356,24 @@ camel_operation_cancel_prfd (CamelOperation *operation) #endif /* CAMEL_HAVE_NSS */ /** - * camel_operation_start: + * camel_operation_push_message: * @cancellable: a #GCancellable or %NULL - * @what: action being performed (printf-style format string) - * @Varargs: varargs + * @format: a standard printf() format string + * @Varargs: the parameters to insert into the format string * - * Report the start of an operation. All start operations should have - * similar end operations. + * Call this function to describe an operation being performed. + * Call camel_operation_progress() to report progress on the operation. + * Call camel_operation_pop_message() when the operation is complete. * * This function only works if @cancellable is a #CamelOperation cast as a * #GCancellable. If @cancellable is a plain #GCancellable or %NULL, the * function does nothing and returns silently. **/ void -camel_operation_start (GCancellable *cancellable, - const gchar *what, ...) +camel_operation_push_message (GCancellable *cancellable, + const gchar *format, ...) { CamelOperation *operation; - const guint signal_id = signals[STATUS]; StatusNode *node; va_list ap; @@ -427,48 +385,45 @@ camel_operation_start (GCancellable *cancellable, g_return_if_fail (CAMEL_IS_OPERATION (cancellable)); - if (!g_signal_has_handler_pending (cancellable, signal_id, 0, TRUE)) - return; - LOCK (); operation = CAMEL_OPERATION (cancellable); - operation->priv->status_update = 0; + va_start (ap, format); - va_start (ap, what); + node = g_slice_new0 (StatusNode); + node->message = g_strdup_vprintf (format, ap); + node->operation = operation; /* not referenced */ - node = status_node_new (operation); - node->msg = g_strdup_vprintf (what, ap); + if (g_queue_is_empty (&operation->priv->status_stack)) + node->source_id = g_idle_add ( + (GSourceFunc) operation_emit_status_cb, node); + else + node->source_id = g_timeout_add_seconds ( + 4, (GSourceFunc) operation_emit_status_cb, node); - va_end (ap); + g_queue_push_head (&operation->priv->status_stack, node); - operation_queue_status_update (operation, node); + va_end (ap); UNLOCK (); } /** - * camel_operation_start_transient: - * @cancellable: a #GCancellable or %NULL - * @what: printf-style format string describing the action being performed - * @Varargs: varargs + * camel_operation_pop_message: + * @cancellable: a #GCancellable * - * Start a transient event. We only update this to the display if it - * takes very long to process, and if we do, we then go back to the - * previous state when finished. + * Pops the most recently pushed message. * * This function only works if @cancellable is a #CamelOperation cast as a * #GCancellable. If @cancellable is a plain #GCancellable or %NULL, the * function does nothing and returns silently. **/ void -camel_operation_start_transient (GCancellable *cancellable, - const gchar *what, ...) +camel_operation_pop_message (GCancellable *cancellable) { CamelOperation *operation; StatusNode *node; - va_list ap; if (cancellable == NULL) return; @@ -481,17 +436,16 @@ camel_operation_start_transient (GCancellable *cancellable, LOCK (); operation = CAMEL_OPERATION (cancellable); + node = g_queue_pop_head (&operation->priv->status_stack); - operation->priv->status_update = 0; + if (node != NULL) + status_node_free (node); - va_start (ap, what); + node = g_queue_peek_head (&operation->priv->status_stack); - node = status_node_new (operation); - node->msg = g_strdup_vprintf (what, ap); - node->stamp = stamp (); - node->transient = TRUE; - - va_end (ap); + if (node != NULL && node->source_id == 0) + node->source_id = g_idle_add ( + (GSourceFunc) operation_emit_status_cb, node); UNLOCK (); } @@ -499,9 +453,9 @@ camel_operation_start_transient (GCancellable *cancellable, /** * camel_operation_progress: * @cancellable: a #GCancellable or %NULL - * @pc: percent complete, 0 to 100. + * @percent: percent complete, 0 to 100. * - * Report progress on the current operation. @pc reports the current + * Report progress on the current operation. @percent reports the current * percentage of completion, which should be in the range of 0 to 100. * * This function only works if @cancellable is a #CamelOperation cast as a @@ -510,12 +464,9 @@ camel_operation_start_transient (GCancellable *cancellable, **/ void camel_operation_progress (GCancellable *cancellable, - gint pc) + gint percent) { CamelOperation *operation; - const guint signal_id = signals[STATUS]; - CamelOperationPrivate *priv; - guint now; StatusNode *node; if (cancellable == NULL) @@ -526,83 +477,21 @@ camel_operation_progress (GCancellable *cancellable, g_return_if_fail (CAMEL_IS_OPERATION (cancellable)); - if (!g_signal_has_handler_pending (cancellable, signal_id, 0, TRUE)) - return; - LOCK (); operation = CAMEL_OPERATION (cancellable); - priv = operation->priv; + node = g_queue_peek_head (&operation->priv->status_stack); - if (g_queue_is_empty (&priv->status_stack)) { - UNLOCK (); - return; - } + if (node != NULL) { + node->percent = percent; - node = g_queue_peek_head (&priv->status_stack); - node->pc = pc; - - /* Transient messages dont start updating till 4 seconds after - they started, then they update every second */ - now = stamp (); - if (priv->status_update == now) { - operation = NULL; - } else if (node->transient) { - if (node->stamp + CAMEL_OPERATION_TRANSIENT_DELAY > now) { - operation = NULL; - } else { - priv->status_update = now; - } - } else { - node->stamp = priv->status_update = now; + /* Rate limit progress updates. */ + if (node->source_id == 0) + node->source_id = g_timeout_add ( + 250, (GSourceFunc) + operation_emit_status_cb, node); } - if (operation != NULL) - operation_queue_status_update (operation, node); - UNLOCK (); } -/** - * camel_operation_end: - * @cancellable: a #GCancellable - * - * Report the end of an operation. - * - * This function only works if @cancellable is a #CamelOperation cast as a - * #GCancellable. If @cancellable is a plain #GCancellable or %NULL, the - * function does nothing and returns silently. - **/ -void -camel_operation_end (GCancellable *cancellable) -{ - CamelOperation *operation; - const guint signal_id = signals[STATUS]; - GQueue *status_stack; - StatusNode *node; - - if (cancellable == NULL) - return; - - if (G_OBJECT_TYPE (cancellable) == G_TYPE_CANCELLABLE) - return; - - g_return_if_fail (CAMEL_IS_OPERATION (cancellable)); - - if (!g_signal_has_handler_pending (cancellable, signal_id, 0, TRUE)) - return; - - LOCK (); - - operation = CAMEL_OPERATION (cancellable); - - status_stack = &operation->priv->status_stack; - - if ((node = g_queue_pop_head (status_stack)) != NULL) { - node->pc = 100; - operation_queue_status_update (operation, node); - status_node_free (node); - } - - UNLOCK (); -} diff --git a/camel/camel-operation.h b/camel/camel-operation.h index 6b6b549..7cdec8e 100644 --- a/camel/camel-operation.h +++ b/camel/camel-operation.h @@ -84,15 +84,12 @@ struct PRFileDesc * * a GCancellable pointer and just return silently if the pointer is * NULL or the pointed to object actually is a plain GCancellable. */ -void camel_operation_start (GCancellable *cancellable, - const gchar *what, - ...) G_GNUC_PRINTF (2, 3); -void camel_operation_start_transient (GCancellable *cancellable, - const gchar *what, +void camel_operation_push_message (GCancellable *cancellable, + const gchar *format, ...) G_GNUC_PRINTF (2, 3); +void camel_operation_pop_message (GCancellable *cancellable); void camel_operation_progress (GCancellable *cancellable, - gint pc); -void camel_operation_end (GCancellable *cancellable); + gint percent); G_END_DECLS diff --git a/camel/camel-sasl.c b/camel/camel-sasl.c index 4966602..de82c55 100644 --- a/camel/camel-sasl.c +++ b/camel/camel-sasl.c @@ -44,6 +44,8 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_SASL, CamelSaslPrivate)) +typedef struct _AsyncContext AsyncContext; + struct _CamelSaslPrivate { CamelService *service; gboolean authenticated; @@ -51,6 +53,16 @@ struct _CamelSaslPrivate { gchar *mechanism; }; +struct _AsyncContext { + /* arguments */ + GByteArray *token; + gchar *base64_token; + + /* results */ + GByteArray *response; + gchar *base64_response; +}; + enum { PROP_0, PROP_AUTHENTICATED, @@ -62,6 +74,21 @@ enum { G_DEFINE_ABSTRACT_TYPE (CamelSasl, camel_sasl, CAMEL_TYPE_OBJECT) static void +async_context_free (AsyncContext *async_context) +{ + if (async_context->token != NULL) + g_byte_array_free (async_context->token, TRUE); + + if (async_context->response != NULL) + g_byte_array_free (async_context->response, TRUE); + + g_free (async_context->base64_token); + g_free (async_context->base64_response); + + g_slice_free (AsyncContext, async_context); +} + +static void sasl_set_mechanism (CamelSasl *sasl, const gchar *mechanism) { @@ -192,6 +219,79 @@ sasl_finalize (GObject *object) } static void +sasl_challenge_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->response = camel_sasl_challenge_sync ( + CAMEL_SASL (object), async_context->token, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +sasl_challenge (CamelSasl *sasl, + GByteArray *token, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->token = g_byte_array_new (); + + g_byte_array_append (async_context->token, token->data, token->len); + + simple = g_simple_async_result_new ( + G_OBJECT (sasl), callback, user_data, sasl_challenge); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, sasl_challenge_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static GByteArray * +sasl_challenge_finish (CamelSasl *sasl, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + GByteArray *response; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (sasl), sasl_challenge), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + response = async_context->response; + async_context->response = NULL; + + return response; +} + +static void camel_sasl_class_init (CamelSaslClass *class) { GObjectClass *object_class; @@ -204,6 +304,9 @@ camel_sasl_class_init (CamelSaslClass *class) object_class->dispose = sasl_dispose; object_class->finalize = sasl_finalize; + class->challenge = sasl_challenge; + class->challenge_finish = sasl_challenge_finish; + g_object_class_install_property ( object_class, PROP_AUTHENTICATED, @@ -303,7 +406,7 @@ camel_sasl_new (const gchar *service_name, /** * camel_sasl_get_authenticated: - * @sasl: a #CamelSasl object + * @sasl: a #CamelSasl * * Returns: whether or not @sasl has successfully authenticated the * user. This will be %TRUE after it returns the last needed response. @@ -380,16 +483,18 @@ camel_sasl_get_service_name (CamelSasl *sasl) /** * camel_sasl_challenge_sync: - * @sasl: a #CamelSasl object + * @sasl: a #CamelSasl * @token: a token, or %NULL * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * If @token is %NULL, generate the initial SASL message to send to - * the server. (This will be %NULL if the client doesn't initiate the - * exchange.) Otherwise, @token is a challenge from the server, and + * the server. (This will be %NULL if the client doesn't initiate the + * exchange.) Otherwise, @token is a challenge from the server, and * the return value is the response. * + * Free the returned #GByteArray with g_byte_array_free(). + * * Returns: the SASL response or %NULL. If an error occurred, @error will * also be set. **/ @@ -416,16 +521,86 @@ camel_sasl_challenge_sync (CamelSasl *sasl, } /** + * camel_sasl_challenge: + * @sasl: a #CamelSasl + * @token: a token, or %NULL + * @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 + * + * If @token is %NULL, asynchronously generate the initial SASL message + * to send to the server. (This will be %NULL if the client doesn't + * initiate the exchange.) Otherwise, @token is a challenge from the + * server, and the asynchronous result is the response. + * + * When the operation is finished, @callback will be called. You can then + * call camel_sasl_challenge_finish() to get the result of the operation. + * + * Since: 2.34 + **/ +void +camel_sasl_challenge (CamelSasl *sasl, + GByteArray *token, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelSaslClass *class; + + g_return_if_fail (CAMEL_IS_SASL (sasl)); + + class = CAMEL_SASL_GET_CLASS (sasl); + g_return_if_fail (class->challenge != NULL); + + class->challenge ( + sasl, token, io_priority, cancellable, callback, user_data); +} + +/** + * camel_sasl_challenge_finish: + * @sasl: a #CamelSasl + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_sasl_challenge(). Free the + * returned #GByteArray with g_byte_array_free(). + * + * Returns: the SASL response or %NULL. If an error occurred, @error will + * also be set. + * + * Since: 2.34 + **/ +GByteArray * +camel_sasl_challenge_finish (CamelSasl *sasl, + GAsyncResult *result, + GError **error) +{ + CamelSaslClass *class; + + g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + class = CAMEL_SASL_GET_CLASS (sasl); + g_return_val_if_fail (class->challenge_finish != NULL, NULL); + + return class->challenge_finish (sasl, result, error); +} + +/** * camel_sasl_challenge_base64_sync: - * @sasl: a #CamelSasl object + * @sasl: a #CamelSasl * @token: a base64-encoded token * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * - * As with #camel_sasl_challenge, but the challenge @token and the + * As with camel_sasl_challenge_sync(), but the challenge @token and the * response are both base64-encoded. * - * Returns: the base64 encoded challenge string + * Returns: the base64-encoded response + * + * Since: 2.34 **/ gchar * camel_sasl_challenge_base64_sync (CamelSasl *sasl, @@ -433,12 +608,13 @@ camel_sasl_challenge_base64_sync (CamelSasl *sasl, GCancellable *cancellable, GError **error) { - GByteArray *token_binary, *ret_binary; - gchar *ret; + GByteArray *token_binary; + GByteArray *response_binary; + gchar *response; g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL); - if (token && *token) { + if (token != NULL && *token != '\0') { guchar *data; gsize length = 0; @@ -449,20 +625,131 @@ camel_sasl_challenge_base64_sync (CamelSasl *sasl, } else token_binary = NULL; - ret_binary = camel_sasl_challenge_sync ( + response_binary = camel_sasl_challenge_sync ( sasl, token_binary, cancellable, error); if (token_binary) g_byte_array_free (token_binary, TRUE); - if (!ret_binary) + if (response_binary == NULL) return NULL; - if (ret_binary->len > 0) - ret = g_base64_encode (ret_binary->data, ret_binary->len); + if (response_binary->len > 0) + response = g_base64_encode ( + response_binary->data, response_binary->len); else - ret = g_strdup (""); - g_byte_array_free (ret_binary, TRUE); + response = g_strdup (""); + + g_byte_array_free (response_binary, TRUE); + + return response; +} + +/* Helper for camel_sasl_challenge_base64() */ +static void +sasl_challenge_base64_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->base64_response = camel_sasl_challenge_base64_sync ( + CAMEL_SASL (object), async_context->base64_token, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +/** + * camel_sasl_challenge_base64: + * @sasl: a #CamelSasl + * @token: a base64-encoded token + * @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 + * + * As with camel_sasl_challenge(), but the challenge @token and the + * response are both base64-encoded. + * + * When the operation is finished, @callback will be called. You can + * then call camel_store_challenge_base64_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_sasl_challenge_base64 (CamelSasl *sasl, + const gchar *token, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_if_fail (CAMEL_IS_SASL (sasl)); - return ret; + async_context = g_slice_new0 (AsyncContext); + async_context->base64_token = g_strdup (token); + + simple = g_simple_async_result_new ( + G_OBJECT (sasl), callback, user_data, + camel_sasl_challenge_base64); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, sasl_challenge_base64_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +/** + * camel_sasl_challenge_base64_finish: + * @sasl: a #CamelSasl + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_sasl_challenge_base64(). + * + * Returns: the base64-encoded response + * + * Since: 2.34 + **/ +gchar * +camel_sasl_challenge_base64_finish (CamelSasl *sasl, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + gchar *response; + + g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (sasl), camel_sasl_challenge_base64), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + response = async_context->base64_response; + async_context->base64_response = NULL; + + return response; } /** diff --git a/camel/camel-sasl.h b/camel/camel-sasl.h index 57dc1c8..3bb3a84 100644 --- a/camel/camel-sasl.h +++ b/camel/camel-sasl.h @@ -63,10 +63,22 @@ struct _CamelSasl { struct _CamelSaslClass { CamelObjectClass parent_class; + /* Synchronous I/O Methods */ GByteArray * (*challenge_sync) (CamelSasl *sasl, GByteArray *token, GCancellable *cancellable, GError **error); + + /* Asynchronous I/O Methods (all have defaults) */ + void (*challenge) (CamelSasl *sasl, + GByteArray *token, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + GByteArray * (*challenge_finish) (CamelSasl *sasl, + GAsyncResult *result, + GError **error); }; GType camel_sasl_get_type (void); @@ -79,15 +91,35 @@ void camel_sasl_set_authenticated (CamelSasl *sasl, const gchar * camel_sasl_get_mechanism (CamelSasl *sasl); CamelService * camel_sasl_get_service (CamelSasl *sasl); const gchar * camel_sasl_get_service_name (CamelSasl *sasl); + GByteArray * camel_sasl_challenge_sync (CamelSasl *sasl, GByteArray *token, GCancellable *cancellable, GError **error); +void camel_sasl_challenge (CamelSasl *sasl, + GByteArray *token, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GByteArray * camel_sasl_challenge_finish (CamelSasl *sasl, + GAsyncResult *result, + GError **error); gchar * camel_sasl_challenge_base64_sync (CamelSasl *sasl, const gchar *token, GCancellable *cancellable, GError **error); +void camel_sasl_challenge_base64 (CamelSasl *sasl, + const gchar *token, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gchar * camel_sasl_challenge_base64_finish + (CamelSasl *sasl, + GAsyncResult *result, + GError **error); GList * camel_sasl_authtype_list (gboolean include_plain); CamelServiceAuthType * diff --git a/camel/camel-smime-context.c b/camel/camel-smime-context.c index 58e81d2..309eef1 100644 --- a/camel/camel-smime-context.c +++ b/camel/camel-smime-context.c @@ -759,7 +759,7 @@ get_hash_from_oid (SECOidTag oidTag) return CAMEL_CIPHER_HASH_DEFAULT; } -static gint +static gboolean smime_context_sign_sync (CamelCipherContext *context, const gchar *userid, CamelCipherHash hash, @@ -769,7 +769,6 @@ smime_context_sign_sync (CamelCipherContext *context, GError **error) { CamelCipherContextClass *class; - gint res = -1; NSSCMSMessage *cmsg; CamelStream *ostream, *istream; GByteArray *buffer; @@ -777,6 +776,7 @@ smime_context_sign_sync (CamelCipherContext *context, NSSCMSEncoderContext *enc; CamelDataWrapper *dw; CamelContentType *ct; + gboolean success = FALSE; class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context); @@ -846,7 +846,7 @@ smime_context_sign_sync (CamelCipherContext *context, goto fail; } - res = 0; + success = TRUE; dw = camel_data_wrapper_new (); camel_stream_reset (ostream, NULL); @@ -872,7 +872,7 @@ smime_context_sign_sync (CamelCipherContext *context, mps = camel_multipart_signed_new (); ct = camel_content_type_new ("multipart", "signed"); - camel_content_type_set_param (ct, "micalg", camel_cipher_hash_to_id (context, get_hash_from_oid (sechash))); + camel_content_type_set_param (ct, "micalg", camel_cipher_context_hash_to_id (context, get_hash_from_oid (sechash))); camel_content_type_set_param (ct, "protocol", class->sign_protocol); camel_data_wrapper_set_mime_type_field ((CamelDataWrapper *)mps, ct); camel_content_type_unref (ct); @@ -904,7 +904,7 @@ fail: g_object_unref (ostream); g_object_unref (istream); - return res; + return success; } static CamelCipherValidity * @@ -998,7 +998,7 @@ fail: return valid; } -static gint +static gboolean smime_context_encrypt_sync (CamelCipherContext *context, const gchar *userid, GPtrArray *recipients, @@ -1029,7 +1029,7 @@ smime_context_encrypt_sync (CamelCipherContext *context, poolp = PORT_NewArena (1024); if (poolp == NULL) { set_nss_error (error, g_strerror (ENOMEM)); - return -1; + return FALSE; } /* Lookup all recipients certs, for later working */ @@ -1164,7 +1164,7 @@ smime_context_encrypt_sync (CamelCipherContext *context, camel_mime_part_set_description (opart, "S/MIME Encrypted Message"); camel_mime_part_set_encoding (opart, CAMEL_TRANSFER_ENCODING_BASE64); - return 0; + return TRUE; fail: if (ostream) @@ -1181,7 +1181,7 @@ fail: PORT_FreeArena (poolp, PR_FALSE); - return -1; + return FALSE; } static CamelCipherValidity * @@ -1207,9 +1207,12 @@ smime_context_decrypt_sync (CamelCipherContext *context, /* FIXME: stream this to the decoder incrementally */ buffer = g_byte_array_new (); istream = camel_stream_mem_new_with_byte_array (buffer); - camel_data_wrapper_decode_to_stream_sync ( + if (!camel_data_wrapper_decode_to_stream_sync ( camel_medium_get_content (CAMEL_MEDIUM (ipart)), - istream, NULL, NULL); + istream, cancellable, error)) { + g_object_unref (istream); + goto fail; + } camel_stream_reset (istream, NULL); dec = NSS_CMSDecoder_Start (NULL, @@ -1352,6 +1355,7 @@ camel_smime_context_describe_part (CamelSMIMEContext *context, CamelMimePart *pa /* FIXME: stream this to the decoder incrementally */ buffer = g_byte_array_new (); istream = camel_stream_mem_new_with_byte_array (buffer); + /* FIXME Pass a GCancellable and GError here. */ camel_data_wrapper_decode_to_stream_sync ( camel_medium_get_content ((CamelMedium *)part), istream, NULL, NULL); diff --git a/camel/camel-store.c b/camel/camel-store.c index fa4997f..f109e57 100644 --- a/camel/camel-store.c +++ b/camel/camel-store.c @@ -48,10 +48,24 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_STORE, CamelStorePrivate)) +typedef struct _AsyncContext AsyncContext; + struct _CamelStorePrivate { GStaticRecMutex folder_lock; /* for locking folder operations */ }; +struct _AsyncContext { + /* arguments */ + gchar *folder_name_1; + gchar *folder_name_2; + gboolean expunge; + guint32 flags; + + /* results */ + CamelFolder *folder; + CamelFolderInfo *folder_info; +}; + enum { FOLDER_CREATED, FOLDER_DELETED, @@ -66,6 +80,20 @@ static guint signals[LAST_SIGNAL]; G_DEFINE_ABSTRACT_TYPE (CamelStore, camel_store, CAMEL_TYPE_SERVICE) +static void +async_context_free (AsyncContext *async_context) +{ + g_free (async_context->folder_name_1); + g_free (async_context->folder_name_2); + + if (async_context->folder != NULL) + g_object_unref (async_context->folder); + + camel_folder_info_free (async_context->folder_info); + + g_slice_free (AsyncContext, async_context); +} + /** * ignore_no_such_table_exception: * Clears the exception 'ex' when it's the 'no such table' exception. @@ -302,1211 +330,2711 @@ store_noop_sync (CamelStore *store, } static void -camel_store_class_init (CamelStoreClass *class) +store_get_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) { - GObjectClass *object_class; - CamelServiceClass *service_class; + AsyncContext *async_context; + GError *error = NULL; - g_type_class_add_private (class, sizeof (CamelStorePrivate)); + async_context = g_simple_async_result_get_op_res_gpointer (simple); - object_class = G_OBJECT_CLASS (class); - object_class->finalize = store_finalize; - object_class->constructed = store_constructed; + async_context->folder = camel_store_get_folder_sync ( + CAMEL_STORE (object), async_context->folder_name_1, + async_context->flags, cancellable, &error); - service_class = CAMEL_SERVICE_CLASS (class); - service_class->construct = store_construct; + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} - class->hash_folder_name = g_str_hash; - class->compare_folder_name = g_str_equal; - class->can_refresh_folder = store_can_refresh_folder; - class->get_inbox_folder_sync = store_get_inbox_folder_sync; - class->get_junk_folder_sync = store_get_junk_folder_sync; - class->get_trash_folder_sync = store_get_trash_folder_sync; - class->synchronize_sync = store_synchronize_sync; - class->noop_sync = store_noop_sync; +static void +store_get_folder (CamelStore *store, + const gchar *folder_name, + guint32 flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; - signals[FOLDER_CREATED] = g_signal_new ( - "folder-created", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CamelStoreClass, folder_created), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); + async_context = g_slice_new0 (AsyncContext); + async_context->folder_name_1 = g_strdup (folder_name); + async_context->flags = flags; - signals[FOLDER_DELETED] = g_signal_new ( - "folder-deleted", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CamelStoreClass, folder_deleted), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, user_data, store_get_folder); - signals[FOLDER_OPENED] = g_signal_new ( - "folder-opened", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CamelStoreClass, folder_opened), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - CAMEL_TYPE_FOLDER); + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); - signals[FOLDER_RENAMED] = g_signal_new ( - "folder-renamed", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CamelStoreClass, folder_renamed), - NULL, NULL, - camel_marshal_VOID__STRING_POINTER, - G_TYPE_NONE, 2, - G_TYPE_STRING, - G_TYPE_POINTER); + g_simple_async_result_run_in_thread ( + simple, store_get_folder_thread, io_priority, cancellable); - signals[FOLDER_SUBSCRIBED] = g_signal_new ( - "folder-subscribed", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CamelStoreClass, folder_subscribed), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); + g_object_unref (simple); +} - signals[FOLDER_UNSUBSCRIBED] = g_signal_new ( - "folder-unsubscribed", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CamelStoreClass, folder_unsubscribed), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); +static CamelFolder * +store_get_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_get_folder), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + return g_object_ref (async_context->folder); } static void -camel_store_init (CamelStore *store) +store_get_folder_info_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) { - store->priv = CAMEL_STORE_GET_PRIVATE (store); + AsyncContext *async_context; + GError *error = NULL; - /* set vtrash and vjunk on by default */ - store->flags = CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK; - store->mode = CAMEL_STORE_READ | CAMEL_STORE_WRITE; + async_context = g_simple_async_result_get_op_res_gpointer (simple); - g_static_rec_mutex_init (&store->priv->folder_lock); + async_context->folder_info = camel_store_get_folder_info_sync ( + CAMEL_STORE (object), async_context->folder_name_1, + async_context->flags, cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } } -GQuark -camel_store_error_quark (void) +static void +store_get_folder_info (CamelStore *store, + const gchar *top, + guint32 flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - static GQuark quark = 0; + GSimpleAsyncResult *simple; + AsyncContext *async_context; - if (G_UNLIKELY (quark == 0)) { - const gchar *string = "camel-store-error-quark"; - quark = g_quark_from_static_string (string); - } + async_context = g_slice_new0 (AsyncContext); + async_context->folder_name_1 = g_strdup (top); + async_context->flags = flags; - return quark; + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, + user_data, store_get_folder_info); + + g_simple_async_result_run_in_thread ( + simple, store_get_folder_info_thread, + io_priority, cancellable); + + g_object_unref (simple); } -/** - * camel_store_get_folder_sync: - * @store: a #CamelStore object - * @folder_name: name of the folder to get - * @flags: folder flags (create, save body index, etc) - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Get a specific folder object from the store by name. - * - * Returns: the folder corresponding to the path @folder_name or %NULL. - **/ -CamelFolder * -camel_store_get_folder_sync (CamelStore *store, - const gchar *folder_name, - guint32 flags, - GCancellable *cancellable, - GError **error) +static CamelFolderInfo * +store_get_folder_info_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - CamelStoreClass *class; - CamelFolder *folder = NULL; + GSimpleAsyncResult *simple; + AsyncContext *async_context; + CamelFolderInfo *folder_info; - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); - g_return_val_if_fail (folder_name != NULL, NULL); + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_get_folder_info), NULL); - class = CAMEL_STORE_GET_CLASS (store); + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); - /* O_EXCL doesn't make sense if we aren't requesting to also create the folder if it doesn't exist */ - if (!(flags & CAMEL_STORE_FOLDER_CREATE)) - flags &= ~CAMEL_STORE_FOLDER_EXCL; + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; - if (store->folders) { - /* Try cache first. */ - folder = camel_object_bag_reserve (store->folders, folder_name); - if (folder && (flags & CAMEL_STORE_FOLDER_EXCL)) { - g_set_error ( - error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, - _("Cannot create folder '%s': folder exists"), - folder_name); - camel_object_bag_abort (store->folders, folder_name); - g_object_unref (folder); - return NULL; - } - } + folder_info = async_context->folder_info; + async_context->folder_info = NULL; - if (!folder) { + return folder_info; +} - if (flags & CAMEL_STORE_IS_MIGRATING) { - if ((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0) { - if (store->folders) - camel_object_bag_abort (store->folders, folder_name); - return NULL; - } +static void +store_get_inbox_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; - if ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0) { - if (store->folders) - camel_object_bag_abort (store->folders, folder_name); - return NULL; - } - } + async_context = g_simple_async_result_get_op_res_gpointer (simple); - if ((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0) { - folder = class->get_trash_folder_sync (store, cancellable, error); - CAMEL_CHECK_GERROR (store, get_trash_folder_sync, folder != NULL, error); - } else if ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0) { - folder = class->get_junk_folder_sync (store, cancellable, error); - CAMEL_CHECK_GERROR (store, get_junk_folder_sync, folder != NULL, error); - } else { - folder = class->get_folder_sync ( - store, folder_name, flags, cancellable, error); - CAMEL_CHECK_GERROR (store, get_folder_sync, folder != NULL, error); + async_context->folder = camel_store_get_inbox_folder_sync ( + CAMEL_STORE (object), cancellable, &error); - if (folder) { - CamelVeeFolder *vfolder; + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} - if ((store->flags & CAMEL_STORE_VTRASH) - && (vfolder = camel_object_bag_get (store->folders, CAMEL_VTRASH_NAME))) { - camel_vee_folder_add_folder (vfolder, folder); - g_object_unref (vfolder); - } +static void +store_get_inbox_folder (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; - if ((store->flags & CAMEL_STORE_VJUNK) - && (vfolder = camel_object_bag_get (store->folders, CAMEL_VJUNK_NAME))) { - camel_vee_folder_add_folder (vfolder, folder); - g_object_unref (vfolder); - } - } - } + async_context = g_slice_new0 (AsyncContext); - if (store->folders) { - if (folder) - camel_object_bag_add (store->folders, folder_name, folder); - else - camel_object_bag_abort (store->folders, folder_name); - } + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, + user_data, store_get_inbox_folder); - if (folder) - g_signal_emit (store, signals[FOLDER_OPENED], 0, folder); - } + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); - return folder; + g_simple_async_result_run_in_thread ( + simple, store_get_inbox_folder_thread, + io_priority, cancellable); + + g_object_unref (simple); } -/** - * camel_store_create_folder_sync: - * @store: a #CamelStore object - * @parent_name: name of the new folder's parent, or %NULL - * @folder_name: name of the folder to create - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Creates a new folder as a child of an existing folder. - * @parent_name can be %NULL to create a new top-level folder. - * - * Returns: info about the created folder, which the caller must - * free with #camel_store_free_folder_info, or %NULL. - **/ -CamelFolderInfo * -camel_store_create_folder_sync (CamelStore *store, - const gchar *parent_name, - const gchar *folder_name, - GCancellable *cancellable, - GError **error) +static CamelFolder * +store_get_inbox_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - CamelStoreClass *class; - CamelFolderInfo *fi; + GSimpleAsyncResult *simple; + AsyncContext *async_context; - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); - g_return_val_if_fail (folder_name != NULL, NULL); + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_get_inbox_folder), NULL); - class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->create_folder_sync != NULL, NULL); + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); - if ((parent_name == NULL || parent_name[0] == 0) - && (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0) - || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0))) { - g_set_error ( - error, CAMEL_STORE_ERROR, - CAMEL_STORE_ERROR_INVALID, - _("Cannot create folder: %s: folder exists"), - folder_name); + if (g_simple_async_result_propagate_error (simple, error)) return NULL; - } - camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + return g_object_ref (async_context->folder); +} - fi = class->create_folder_sync ( - store, parent_name, folder_name, cancellable, error); - CAMEL_CHECK_GERROR (store, create_folder_sync, fi != NULL, error); +static void +store_get_junk_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; - camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + async_context = g_simple_async_result_get_op_res_gpointer (simple); - return fi; + async_context->folder = camel_store_get_junk_folder_sync ( + CAMEL_STORE (object), cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } } -/* deletes folder/removes it from the folder cache, if it's there */ static void -cs_delete_cached_folder (CamelStore *store, - const gchar *folder_name) +store_get_junk_folder (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - CamelFolder *folder; + GSimpleAsyncResult *simple; + AsyncContext *async_context; - if (store->folders - && (folder = camel_object_bag_get (store->folders, folder_name))) { - CamelVeeFolder *vfolder; + async_context = g_slice_new0 (AsyncContext); - if ((store->flags & CAMEL_STORE_VTRASH) - && (vfolder = camel_object_bag_get(store->folders, CAMEL_VTRASH_NAME))) { - camel_vee_folder_remove_folder (vfolder, folder); - g_object_unref (vfolder); - } + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, + user_data, store_get_junk_folder); - if ((store->flags & CAMEL_STORE_VJUNK) - && (vfolder = camel_object_bag_get(store->folders, CAMEL_VJUNK_NAME))) { - camel_vee_folder_remove_folder(vfolder, folder); - g_object_unref (vfolder); - } + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); - camel_folder_delete (folder); + g_simple_async_result_run_in_thread ( + simple, store_get_junk_folder_thread, + io_priority, cancellable); - camel_object_bag_remove (store->folders, folder); - g_object_unref (folder); - } + g_object_unref (simple); } -/** - * camel_store_delete_folder_sync: - * @store: a #CamelStore object - * @folder_name: name of the folder to delete - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Deletes the named folder. The folder must be empty. - * - * Returns: %TRUE on success, %FALSE on failure - **/ -gboolean -camel_store_delete_folder_sync (CamelStore *store, - const gchar *folder_name, - GCancellable *cancellable, - GError **error) +static CamelFolder * +store_get_junk_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - CamelStoreClass *class; - gboolean success; - GError *local_error = NULL; + GSimpleAsyncResult *simple; + AsyncContext *async_context; - g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); - g_return_val_if_fail (folder_name != NULL, FALSE); + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_get_folder), NULL); - class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->delete_folder_sync != NULL, FALSE); + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); - /* TODO: should probably be a parameter/bit on the storeinfo */ - if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0) - || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0)) { - g_set_error ( - error, CAMEL_STORE_ERROR, - CAMEL_STORE_ERROR_NO_FOLDER, - _("Cannot delete folder: %s: Invalid operation"), - folder_name); - return FALSE; + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + return g_object_ref (async_context->folder); +} + +static void +store_get_trash_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->folder = camel_store_get_trash_folder_sync ( + CAMEL_STORE (object), cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); } +} - camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); +static void +store_get_trash_folder (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; - success = class->delete_folder_sync ( - store, folder_name, cancellable, &local_error); - CAMEL_CHECK_GERROR (store, delete_folder_sync, success, &local_error); + async_context = g_slice_new0 (AsyncContext); - /* ignore 'no such table' errors */ - if (local_error != NULL && - g_ascii_strncasecmp (local_error->message, "no such table", 13) == 0) - g_clear_error (&local_error); + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, + user_data, store_get_trash_folder); - if (local_error == NULL) - cs_delete_cached_folder(store, folder_name); - else - g_propagate_error (error, local_error); + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); - camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + g_simple_async_result_run_in_thread ( + simple, store_get_trash_folder_thread, + io_priority, cancellable); - return success; + g_object_unref (simple); } -/** - * camel_store_rename_folder_sync: - * @store: a #CamelStore object - * @old_namein: the current name of the folder - * @new_name: the new name of the folder - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Rename a named folder to a new name. - * - * Returns: %TRUE on success, %FALSE on failure - **/ -gboolean -camel_store_rename_folder_sync (CamelStore *store, - const gchar *old_namein, - const gchar *new_name, - GCancellable *cancellable, - GError **error) +static CamelFolder * +store_get_trash_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - CamelStoreClass *class; - CamelFolder *folder; - gint i, oldlen, namelen; - GPtrArray *folders = NULL; - gchar *old_name; - gboolean success; + GSimpleAsyncResult *simple; + AsyncContext *async_context; - g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); - g_return_val_if_fail (old_namein != NULL, FALSE); - g_return_val_if_fail (new_name != NULL, FALSE); + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_get_trash_folder), NULL); - class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->rename_folder_sync != NULL, FALSE); + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); - if (strcmp (old_namein, new_name) == 0) - return TRUE; + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; - if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (old_namein, CAMEL_VTRASH_NAME) == 0) - || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (old_namein, CAMEL_VJUNK_NAME) == 0)) { - g_set_error ( - error, CAMEL_STORE_ERROR, - CAMEL_STORE_ERROR_NO_FOLDER, - _("Cannot rename folder: %s: Invalid operation"), - old_namein); - return FALSE; + return g_object_ref (async_context->folder); +} + +static void +store_create_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + async_context->folder_info = camel_store_create_folder_sync ( + CAMEL_STORE (object), async_context->folder_name_1, + async_context->folder_name_2, cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); } +} - /* need to save this, since old_namein might be folder->full_name, which could go away */ - old_name = g_strdup (old_namein); - oldlen = strlen (old_name); +static void +store_create_folder (CamelStore *store, + const gchar *parent_name, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; - camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + async_context = g_slice_new0 (AsyncContext); + async_context->folder_name_1 = g_strdup (parent_name); + async_context->folder_name_2 = g_strdup (folder_name); - /* If the folder is open (or any subfolders of the open folder) - We need to rename them atomically with renaming the actual folder path */ - if (store->folders) { - folders = camel_object_bag_list (store->folders); - for (i=0;ilen;i++) { - const gchar *full_name; + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, user_data, store_create_folder); - folder = folders->pdata[i]; - full_name = camel_folder_get_full_name (folder); + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); - namelen = strlen (full_name); - if ((namelen == oldlen && - strcmp (full_name, old_name) == 0) - || ((namelen > oldlen) - && strncmp (full_name, old_name, oldlen) == 0 - && full_name[oldlen] == '/')) { - camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); - } else { - g_ptr_array_remove_index_fast (folders, i); - i--; - g_object_unref (folder); - } - } - } + g_simple_async_result_run_in_thread ( + simple, store_create_folder_thread, io_priority, cancellable); - /* Now try the real rename (will emit renamed signal) */ - success = class->rename_folder_sync ( - store, old_name, new_name, cancellable, error); - CAMEL_CHECK_GERROR (store, rename_folder_sync, success, error); + g_object_unref (simple); +} - /* If it worked, update all open folders/unlock them */ - if (folders) { - if (success) { - guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE; - CamelFolderInfo *folder_info; +static CamelFolderInfo * +store_create_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + CamelFolderInfo *folder_info; - for (i=0;ilen;i++) { - const gchar *full_name; - gchar *new; + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_create_folder_finish), NULL); - folder = folders->pdata[i]; - full_name = camel_folder_get_full_name (folder); + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); - new = g_strdup_printf("%s%s", new_name, full_name + strlen(old_name)); - camel_object_bag_rekey (store->folders, folder, new); - camel_folder_rename (folder, new); - g_free (new); + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; - camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); - g_object_unref (folder); - } + folder_info = async_context->folder_info; + async_context->folder_info = NULL; - /* Emit renamed signal */ - if (store->flags & CAMEL_STORE_SUBSCRIPTIONS) - flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED; + return folder_info; +} - folder_info = class->get_folder_info_sync ( - store, new_name, flags, cancellable, error); - CAMEL_CHECK_GERROR (store, get_folder_info, folder_info != NULL, error); +static void +store_delete_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; - if (folder_info != NULL) { - camel_store_folder_renamed (store, old_name, folder_info); - class->free_folder_info (store, folder_info); - } - } else { - /* Failed, just unlock our folders for re-use */ - for (i=0;ilen;i++) { - folder = folders->pdata[i]; - camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); - g_object_unref (folder); - } - } + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_store_delete_folder_sync ( + CAMEL_STORE (object), async_context->folder_name_1, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); } +} - camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); +static void +store_delete_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; - g_ptr_array_free (folders, TRUE); - g_free (old_name); + async_context = g_slice_new0 (AsyncContext); + async_context->folder_name_1 = g_strdup (folder_name); - return success; + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, user_data, store_delete_folder); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, store_delete_folder_thread, io_priority, cancellable); + + g_object_unref (simple); } -/** - * camel_store_folder_created: - * @store: a #CamelStore - * @info: information about the created folder - * - * Emits the #CamelStore::folder-created signal. - * - * This function is only intended for Camel providers. - * - * Since: 2.32 - **/ -void -camel_store_folder_created (CamelStore *store, - CamelFolderInfo *info) +static gboolean +store_delete_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - g_return_if_fail (CAMEL_STORE (store)); - g_return_if_fail (info != NULL); + GSimpleAsyncResult *simple; - g_signal_emit (store, signals[FOLDER_CREATED], 0, info); + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_delete_folder), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); } -/** - * camel_store_folder_deleted: - * @store: a #CamelStore - * @info: information about the deleted folder - * - * Emits the #CamelStore::folder-deleted signal. - * - * This function is only intended for Camel providers. - * - * Since: 2.32 - **/ -void -camel_store_folder_deleted (CamelStore *store, - CamelFolderInfo *info) +static void +store_rename_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) { - g_return_if_fail (CAMEL_STORE (store)); - g_return_if_fail (info != NULL); + AsyncContext *async_context; + GError *error = NULL; - g_signal_emit (store, signals[FOLDER_DELETED], 0, info); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_store_rename_folder_sync ( + CAMEL_STORE (object), async_context->folder_name_1, + async_context->folder_name_2, cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } } -/** - * camel_store_folder_renamed: - * @store: a #CamelStore - * @old_name: the old name of the folder - * @info: information about the renamed folder - * - * Emits the #CamelStore::folder-renamed signal. - * - * This function is only intended for Camel providers. - * - * Since: 2.32 - **/ -void -camel_store_folder_renamed (CamelStore *store, - const gchar *old_name, - CamelFolderInfo *info) +static void +store_rename_folder (CamelStore *store, + const gchar *old_name, + const gchar *new_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - g_return_if_fail (CAMEL_STORE (store)); - g_return_if_fail (old_name != NULL); - g_return_if_fail (info != NULL); + GSimpleAsyncResult *simple; + AsyncContext *async_context; - g_signal_emit (store, signals[FOLDER_RENAMED], 0, old_name, info); + async_context = g_slice_new0 (AsyncContext); + async_context->folder_name_1 = g_strdup (old_name); + async_context->folder_name_2 = g_strdup (new_name); + + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, user_data, store_rename_folder); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, store_rename_folder_thread, io_priority, cancellable); + + g_object_unref (simple); } -/** - * camel_store_folder_subscribed: - * @store: a #CamelStore - * @info: information about the subscribed folder - * - * Emits the #CamelStore::folder-subscribed signal. - * - * This function is only intended for Camel providers. - * - * Since: 2.32 - **/ -void -camel_store_folder_subscribed (CamelStore *store, - CamelFolderInfo *info) +static gboolean +store_rename_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - g_return_if_fail (CAMEL_STORE (store)); - g_return_if_fail (info != NULL); + GSimpleAsyncResult *simple; - g_signal_emit (store, signals[FOLDER_SUBSCRIBED], 0, info); + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_rename_folder), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); } -/** - * camel_store_folder_unsubscribed: - * @store: a #CamelStore - * @info: information about the unsubscribed folder - * - * Emits the #CamelStore::folder-unsubscribed signal. - * - * This function is only intended for Camel providers. - * - * Since: 2.32 - **/ -void -camel_store_folder_unsubscribed (CamelStore *store, - CamelFolderInfo *info) +static void +store_subscribe_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) { - g_return_if_fail (CAMEL_STORE (store)); - g_return_if_fail (info != NULL); + AsyncContext *async_context; + GError *error = NULL; - g_signal_emit (store, signals[FOLDER_UNSUBSCRIBED], 0, info); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_store_subscribe_folder_sync ( + CAMEL_STORE (object), async_context->folder_name_1, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } } -/** - * camel_store_get_inbox_folder_sync: - * @store: a #CamelStore object - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Returns: the folder in the store into which new mail is delivered, - * or %NULL if no such folder exists. - **/ -CamelFolder * -camel_store_get_inbox_folder_sync (CamelStore *store, - GCancellable *cancellable, - GError **error) +static void +store_subscribe_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - CamelStoreClass *class; - CamelFolder *folder; + GSimpleAsyncResult *simple; + AsyncContext *async_context; - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); - - class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->get_inbox_folder_sync != NULL, NULL); + async_context = g_slice_new0 (AsyncContext); + async_context->folder_name_1 = g_strdup (folder_name); - camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, + user_data, store_subscribe_folder); - folder = class->get_inbox_folder_sync (store, cancellable, error); - CAMEL_CHECK_GERROR ( - store, get_inbox_folder_sync, folder != NULL, error); + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); - camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + g_simple_async_result_run_in_thread ( + simple, store_subscribe_folder_thread, + io_priority, cancellable); - return folder; + g_object_unref (simple); } -/** - * camel_store_get_junk_folder_sync: - * @store: a #CamelStore object - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Returns: the folder in the store into which junk is delivered, or - * %NULL if no such folder exists. - **/ -CamelFolder * -camel_store_get_junk_folder_sync (CamelStore *store, - GCancellable *cancellable, - GError **error) +static gboolean +store_subscribe_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + GSimpleAsyncResult *simple; - if ((store->flags & CAMEL_STORE_VJUNK) == 0) { - CamelStoreClass *class; - CamelFolder *folder; + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_subscribe_folder), FALSE); - class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->get_junk_folder_sync != NULL, NULL); + simple = G_SIMPLE_ASYNC_RESULT (result); - folder = class->get_junk_folder_sync (store, cancellable, error); - CAMEL_CHECK_GERROR ( - store, get_junk_folder_sync, folder != NULL, error); + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} - return folder; - } +static void +store_unsubscribe_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; - return camel_store_get_folder_sync ( - store, CAMEL_VJUNK_NAME, 0, cancellable, error); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_store_unsubscribe_folder_sync ( + CAMEL_STORE (object), async_context->folder_name_1, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } } -/** - * camel_store_get_trash_folder_sync: - * @store: a #CamelStore object - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Returns: the folder in the store into which trash is delivered, or - * %NULL if no such folder exists. - **/ -CamelFolder * -camel_store_get_trash_folder_sync (CamelStore *store, - GCancellable *cancellable, - GError **error) +static void +store_unsubscribe_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + GSimpleAsyncResult *simple; + AsyncContext *async_context; - if ((store->flags & CAMEL_STORE_VTRASH) == 0) { - CamelStoreClass *class; - CamelFolder *folder; + async_context = g_slice_new0 (AsyncContext); + async_context->folder_name_1 = g_strdup (folder_name); - class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->get_trash_folder_sync != NULL, NULL); + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, + user_data, store_unsubscribe_folder); - folder = class->get_trash_folder_sync ( - store, cancellable, error); - CAMEL_CHECK_GERROR ( - store, get_trash_folder_sync, folder != NULL, error); + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); - return folder; - } + g_simple_async_result_run_in_thread ( + simple, store_unsubscribe_folder_thread, + io_priority, cancellable); - return camel_store_get_folder_sync ( - store, CAMEL_VTRASH_NAME, 0, cancellable, error); + g_object_unref (simple); } -/** - * camel_store_synchronize_sync: - * @store: a #CamelStore object - * @expunge: %TRUE if an expunge should be done after sync or %FALSE otherwise - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Syncs any changes that have been made to the store object and its - * folders with the real store. - * - * Returns: %TRUE on success, %FALSE on failure - **/ -gboolean -camel_store_synchronize_sync (CamelStore *store, - gboolean expunge, - GCancellable *cancellable, - GError **error) +static gboolean +store_unsubscribe_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - CamelStoreClass *class; - gboolean success; - - g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + GSimpleAsyncResult *simple; - class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->synchronize_sync != NULL, FALSE); + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_unsubscribe_folder), FALSE); - success = class->synchronize_sync (store, expunge, cancellable, error); - CAMEL_CHECK_GERROR (store, synchronize_sync, success, error); + simple = G_SIMPLE_ASYNC_RESULT (result); - return success; + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); } static void -add_special_info (CamelStore *store, - CamelFolderInfo *info, - const gchar *name, - const gchar *translated, - gboolean unread_count, - guint32 flags) +store_synchronize_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) { - CamelFolderInfo *fi, *vinfo, *parent; - gchar *uri, *path; - CamelURL *url; + AsyncContext *async_context; + GError *error = NULL; - g_return_if_fail (info != NULL); + async_context = g_simple_async_result_get_op_res_gpointer (simple); - parent = NULL; - for (fi = info; fi; fi = fi->next) { - if (!strcmp (fi->full_name, name)) - break; - parent = fi; - } + camel_store_synchronize_sync ( + CAMEL_STORE (object), async_context->expunge, + cancellable, &error); - /* create our vTrash/vJunk URL */ - url = camel_url_new (info->uri, NULL); - if (((CamelService *) store)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) { - camel_url_set_fragment (url, name); - } else { - path = g_strdup_printf ("/%s", name); - camel_url_set_path (url, path); - g_free (path); + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); } +} - uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - camel_url_free (url); +static void +store_synchronize (CamelStore *store, + gboolean expunge, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; - if (fi) { - /* We're going to replace the physical Trash/Junk folder with our vTrash/vJunk folder */ - vinfo = fi; - g_free (vinfo->full_name); - g_free (vinfo->name); - g_free (vinfo->uri); - } else { - /* There wasn't a Trash/Junk folder so create a new folder entry */ - vinfo = camel_folder_info_new (); + async_context = g_slice_new0 (AsyncContext); + async_context->expunge = expunge; - g_assert (parent != NULL); + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, user_data, store_synchronize); - vinfo->flags |= CAMEL_FOLDER_NOINFERIORS | CAMEL_FOLDER_SUBSCRIBED; + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); - /* link it into the right spot */ - vinfo->next = parent->next; - parent->next = vinfo; - } + g_simple_async_result_run_in_thread ( + simple, store_synchronize_thread, io_priority, cancellable); - /* Fill in the new fields */ - vinfo->flags |= flags; - vinfo->full_name = g_strdup (name); - vinfo->name = g_strdup (translated); - vinfo->uri = uri; - if (!unread_count) - vinfo->unread = -1; + g_object_unref (simple); +} + +static gboolean +store_synchronize_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_synchronize), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); } static void -dump_fi (CamelFolderInfo *fi, gint depth) +store_noop_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) { - gchar *s; + GError *error = NULL; - s = g_alloca (depth+1); - memset (s, ' ', depth); - s[depth] = 0; + camel_store_noop_sync (CAMEL_STORE (object), cancellable, &error); - while (fi) { - printf("%suri: %s\n", s, fi->uri); - printf("%sfull_name: %s\n", s, fi->full_name); - printf("%sflags: %08x\n", s, fi->flags); - dump_fi (fi->child, depth+2); - fi = fi->next; + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); } } -/** - * camel_store_get_folder_info_sync: - * @store: a #CamelStore object - * @top: the name of the folder to start from - * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * This fetches information about the folder structure of @store, - * starting with @top, and returns a tree of CamelFolderInfo - * structures. If @flags includes %CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, - * only subscribed folders will be listed. If the store doesn't support - * subscriptions, then it will list all folders. If @flags includes - * %CAMEL_STORE_FOLDER_INFO_RECURSIVE, the returned tree will include - * all levels of hierarchy below @top. If not, it will only include - * the immediate subfolders of @top. If @flags includes - * %CAMEL_STORE_FOLDER_INFO_FAST, the unread_message_count fields of - * some or all of the structures may be set to %-1, if the store cannot - * determine that information quickly. If @flags includes - * %CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, don't include special virtual +static void +store_noop (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, user_data, store_noop); + + g_simple_async_result_run_in_thread ( + simple, store_noop_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +store_noop_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), store_noop), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +camel_store_class_init (CamelStoreClass *class) +{ + GObjectClass *object_class; + CamelServiceClass *service_class; + + g_type_class_add_private (class, sizeof (CamelStorePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = store_finalize; + object_class->constructed = store_constructed; + + service_class = CAMEL_SERVICE_CLASS (class); + service_class->construct = store_construct; + + class->hash_folder_name = g_str_hash; + class->compare_folder_name = g_str_equal; + class->can_refresh_folder = store_can_refresh_folder; + + class->get_inbox_folder_sync = store_get_inbox_folder_sync; + class->get_junk_folder_sync = store_get_junk_folder_sync; + class->get_trash_folder_sync = store_get_trash_folder_sync; + class->synchronize_sync = store_synchronize_sync; + class->noop_sync = store_noop_sync; + + class->get_folder = store_get_folder; + class->get_folder_finish = store_get_folder_finish; + class->get_folder_info = store_get_folder_info; + class->get_folder_info_finish = store_get_folder_info_finish; + class->get_inbox_folder = store_get_inbox_folder; + class->get_inbox_folder_finish = store_get_inbox_folder_finish; + class->get_junk_folder = store_get_junk_folder; + class->get_junk_folder_finish = store_get_junk_folder_finish; + class->get_trash_folder = store_get_trash_folder; + class->get_trash_folder_finish = store_get_trash_folder_finish; + class->create_folder = store_create_folder; + class->create_folder_finish = store_create_folder_finish; + class->delete_folder = store_delete_folder; + class->delete_folder_finish = store_delete_folder_finish; + class->rename_folder = store_rename_folder; + class->rename_folder_finish = store_rename_folder_finish; + class->subscribe_folder = store_subscribe_folder; + class->subscribe_folder_finish = store_subscribe_folder_finish; + class->unsubscribe_folder = store_unsubscribe_folder; + class->unsubscribe_folder_finish = store_unsubscribe_folder_finish; + class->synchronize = store_synchronize; + class->synchronize_finish = store_synchronize_finish; + class->noop = store_noop; + class->noop_finish = store_noop_finish; + + signals[FOLDER_CREATED] = g_signal_new ( + "folder-created", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CamelStoreClass, folder_created), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[FOLDER_DELETED] = g_signal_new ( + "folder-deleted", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CamelStoreClass, folder_deleted), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[FOLDER_OPENED] = g_signal_new ( + "folder-opened", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CamelStoreClass, folder_opened), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CAMEL_TYPE_FOLDER); + + signals[FOLDER_RENAMED] = g_signal_new ( + "folder-renamed", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CamelStoreClass, folder_renamed), + NULL, NULL, + camel_marshal_VOID__STRING_POINTER, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_POINTER); + + signals[FOLDER_SUBSCRIBED] = g_signal_new ( + "folder-subscribed", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CamelStoreClass, folder_subscribed), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[FOLDER_UNSUBSCRIBED] = g_signal_new ( + "folder-unsubscribed", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (CamelStoreClass, folder_unsubscribed), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); +} + +static void +camel_store_init (CamelStore *store) +{ + store->priv = CAMEL_STORE_GET_PRIVATE (store); + + /* set vtrash and vjunk on by default */ + store->flags = CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK; + store->mode = CAMEL_STORE_READ | CAMEL_STORE_WRITE; + + g_static_rec_mutex_init (&store->priv->folder_lock); +} + +GQuark +camel_store_error_quark (void) +{ + static GQuark quark = 0; + + if (G_UNLIKELY (quark == 0)) { + const gchar *string = "camel-store-error-quark"; + quark = g_quark_from_static_string (string); + } + + return quark; +} + +/* deletes folder/removes it from the folder cache, if it's there */ +static void +cs_delete_cached_folder (CamelStore *store, + const gchar *folder_name) +{ + CamelFolder *folder; + + if (store->folders + && (folder = camel_object_bag_get (store->folders, folder_name))) { + CamelVeeFolder *vfolder; + + if ((store->flags & CAMEL_STORE_VTRASH) + && (vfolder = camel_object_bag_get(store->folders, CAMEL_VTRASH_NAME))) { + camel_vee_folder_remove_folder (vfolder, folder); + g_object_unref (vfolder); + } + + if ((store->flags & CAMEL_STORE_VJUNK) + && (vfolder = camel_object_bag_get(store->folders, CAMEL_VJUNK_NAME))) { + camel_vee_folder_remove_folder(vfolder, folder); + g_object_unref (vfolder); + } + + camel_folder_delete (folder); + + camel_object_bag_remove (store->folders, folder); + g_object_unref (folder); + } +} + +/** + * camel_store_folder_created: + * @store: a #CamelStore + * @info: information about the created folder + * + * Emits the #CamelStore::folder-created signal. + * + * This function is only intended for Camel providers. + * + * Since: 2.32 + **/ +void +camel_store_folder_created (CamelStore *store, + CamelFolderInfo *info) +{ + g_return_if_fail (CAMEL_STORE (store)); + g_return_if_fail (info != NULL); + + g_signal_emit (store, signals[FOLDER_CREATED], 0, info); +} + +/** + * camel_store_folder_deleted: + * @store: a #CamelStore + * @info: information about the deleted folder + * + * Emits the #CamelStore::folder-deleted signal. + * + * This function is only intended for Camel providers. + * + * Since: 2.32 + **/ +void +camel_store_folder_deleted (CamelStore *store, + CamelFolderInfo *info) +{ + g_return_if_fail (CAMEL_STORE (store)); + g_return_if_fail (info != NULL); + + g_signal_emit (store, signals[FOLDER_DELETED], 0, info); +} + +/** + * camel_store_folder_renamed: + * @store: a #CamelStore + * @old_name: the old name of the folder + * @info: information about the renamed folder + * + * Emits the #CamelStore::folder-renamed signal. + * + * This function is only intended for Camel providers. + * + * Since: 2.32 + **/ +void +camel_store_folder_renamed (CamelStore *store, + const gchar *old_name, + CamelFolderInfo *info) +{ + g_return_if_fail (CAMEL_STORE (store)); + g_return_if_fail (old_name != NULL); + g_return_if_fail (info != NULL); + + g_signal_emit (store, signals[FOLDER_RENAMED], 0, old_name, info); +} + +/** + * camel_store_folder_subscribed: + * @store: a #CamelStore + * @info: information about the subscribed folder + * + * Emits the #CamelStore::folder-subscribed signal. + * + * This function is only intended for Camel providers. + * + * Since: 2.32 + **/ +void +camel_store_folder_subscribed (CamelStore *store, + CamelFolderInfo *info) +{ + g_return_if_fail (CAMEL_STORE (store)); + g_return_if_fail (info != NULL); + + g_signal_emit (store, signals[FOLDER_SUBSCRIBED], 0, info); +} + +/** + * camel_store_folder_unsubscribed: + * @store: a #CamelStore + * @info: information about the unsubscribed folder + * + * Emits the #CamelStore::folder-unsubscribed signal. + * + * This function is only intended for Camel providers. + * + * Since: 2.32 + **/ +void +camel_store_folder_unsubscribed (CamelStore *store, + CamelFolderInfo *info) +{ + g_return_if_fail (CAMEL_STORE (store)); + g_return_if_fail (info != NULL); + + g_signal_emit (store, signals[FOLDER_UNSUBSCRIBED], 0, info); +} + +static void +add_special_info (CamelStore *store, + CamelFolderInfo *info, + const gchar *name, + const gchar *translated, + gboolean unread_count, + guint32 flags) +{ + CamelFolderInfo *fi, *vinfo, *parent; + gchar *uri, *path; + CamelURL *url; + + g_return_if_fail (info != NULL); + + parent = NULL; + for (fi = info; fi; fi = fi->next) { + if (!strcmp (fi->full_name, name)) + break; + parent = fi; + } + + /* create our vTrash/vJunk URL */ + url = camel_url_new (info->uri, NULL); + if (((CamelService *) store)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) { + camel_url_set_fragment (url, name); + } else { + path = g_strdup_printf ("/%s", name); + camel_url_set_path (url, path); + g_free (path); + } + + uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); + camel_url_free (url); + + if (fi) { + /* We're going to replace the physical Trash/Junk folder with our vTrash/vJunk folder */ + vinfo = fi; + g_free (vinfo->full_name); + g_free (vinfo->name); + g_free (vinfo->uri); + } else { + /* There wasn't a Trash/Junk folder so create a new folder entry */ + vinfo = camel_folder_info_new (); + + g_assert (parent != NULL); + + vinfo->flags |= CAMEL_FOLDER_NOINFERIORS | CAMEL_FOLDER_SUBSCRIBED; + + /* link it into the right spot */ + vinfo->next = parent->next; + parent->next = vinfo; + } + + /* Fill in the new fields */ + vinfo->flags |= flags; + vinfo->full_name = g_strdup (name); + vinfo->name = g_strdup (translated); + vinfo->uri = uri; + if (!unread_count) + vinfo->unread = -1; +} + +static void +dump_fi (CamelFolderInfo *fi, gint depth) +{ + gchar *s; + + s = g_alloca (depth+1); + memset (s, ' ', depth); + s[depth] = 0; + + while (fi) { + printf("%suri: %s\n", s, fi->uri); + printf("%sfull_name: %s\n", s, fi->full_name); + printf("%sflags: %08x\n", s, fi->flags); + dump_fi (fi->child, depth+2); + fi = fi->next; + } +} + +/** + * camel_store_free_folder_info: + * @store: a #CamelStore + * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info + * + * Frees the data returned by #camel_store_get_folder_info. If @fi is %NULL, + * nothing is done, the routine simply returns. + **/ +void +camel_store_free_folder_info (CamelStore *store, + CamelFolderInfo *fi) +{ + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + if (fi == NULL) + return; + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->free_folder_info != NULL); + + class->free_folder_info (store, fi); +} + +/** + * camel_store_free_folder_info_full: + * @store: a #CamelStore + * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info + * + * An implementation for #CamelStore::free_folder_info. Frees all + * of the data. + **/ +void +camel_store_free_folder_info_full (CamelStore *store, + CamelFolderInfo *fi) +{ + camel_folder_info_free (fi); +} + +/** + * camel_store_free_folder_info_nop: + * @store: a #CamelStore + * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info + * + * An implementation for #CamelStore::free_folder_info. Does nothing. + **/ +void +camel_store_free_folder_info_nop (CamelStore *store, + CamelFolderInfo *fi) +{ + ; +} + +/** + * camel_folder_info_free: + * @fi: a #CamelFolderInfo + * + * Frees @fi. + **/ +void +camel_folder_info_free (CamelFolderInfo *fi) +{ + if (fi != NULL) { + camel_folder_info_free (fi->next); + camel_folder_info_free (fi->child); + g_free (fi->name); + g_free (fi->full_name); + g_free (fi->uri); + g_slice_free (CamelFolderInfo, fi); + } +} + +/** + * camel_folder_info_new: + * + * Returns: a new empty CamelFolderInfo instance + * + * Since: 2.22 + **/ +CamelFolderInfo * +camel_folder_info_new (void) +{ + return g_slice_new0 (CamelFolderInfo); +} + +static gint +folder_info_cmp (gconstpointer ap, + gconstpointer bp) +{ + const CamelFolderInfo *a = ((CamelFolderInfo **)ap)[0]; + const CamelFolderInfo *b = ((CamelFolderInfo **)bp)[0]; + + return strcmp (a->full_name, b->full_name); +} + +/** + * camel_folder_info_build: + * @folders: an array of #CamelFolderInfo + * @namespace: an ignorable prefix on the folder names + * @separator: the hieararchy separator character + * @short_names: %TRUE if the (short) name of a folder is the part after + * the last @separator in the full name. %FALSE if it is the full name. + * + * This takes an array of folders and attaches them together according + * to the hierarchy described by their full_names and @separator. If + * @namespace is non-%NULL, then it will be ignored as a full_name + * prefix, for purposes of comparison. If necessary, + * #camel_folder_info_build will create additional #CamelFolderInfo with + * %NULL urls to fill in gaps in the tree. The value of @short_names + * is used in constructing the names of these intermediate folders. + * + * NOTE: This is deprected, do not use this. + * FIXME: remove this/move it to imap, which is the only user of it now. + * + * Returns: the top level of the tree of linked folder info. + **/ +CamelFolderInfo * +camel_folder_info_build (GPtrArray *folders, + const gchar *namespace, + gchar separator, + gboolean short_names) +{ + CamelFolderInfo *fi, *pfi, *top = NULL, *tail = NULL; + GHashTable *hash; + gchar *p, *pname; + gint i, nlen; + + if (!namespace) + namespace = ""; + nlen = strlen (namespace); + + qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_info_cmp); + + /* Hash the folders. */ + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + for (i = 0; i < folders->len; i++) { + fi = folders->pdata[i]; + g_hash_table_insert (hash, g_strdup (fi->full_name), fi); + } + + /* Now find parents. */ + for (i = 0; i < folders->len; i++) { + fi = folders->pdata[i]; + if (!strncmp (namespace, fi->full_name, nlen) + && (p = strrchr (fi->full_name+nlen, separator))) { + pname = g_strndup (fi->full_name, p - fi->full_name); + pfi = g_hash_table_lookup (hash, pname); + if (pfi) { + g_free (pname); + } else { + /* we are missing a folder in the heirarchy so + create a fake folder node */ + const gchar *path; + CamelURL *url; + gchar *sep; + + pfi = camel_folder_info_new (); + if (short_names) { + pfi->name = strrchr (pname, separator); + if (pfi->name) + pfi->name = g_strdup (pfi->name + 1); + else + pfi->name = g_strdup (pname); + } else + pfi->name = g_strdup (pname); + + url = camel_url_new (fi->uri, NULL); + if (url->fragment) + path = url->fragment; + else + path = url->path + 1; + + sep = strrchr (path, separator); + if (sep) + *sep = '\0'; + else { + d(g_warning ("huh, no \"%c\" in \"%s\"?", separator, fi->uri)); + } + + pfi->full_name = g_strdup (path); + + /* since this is a "fake" folder node, it is not selectable */ + camel_url_set_param (url, "noselect", "yes"); + pfi->uri = camel_url_to_string (url, 0); + camel_url_free (url); + + g_hash_table_insert (hash, pname, pfi); + g_ptr_array_add (folders, pfi); + } + tail = (CamelFolderInfo *)&pfi->child; + while (tail->next) + tail = tail->next; + tail->next = fi; + fi->parent = pfi; + } else if (!top) + top = fi; + } + g_hash_table_destroy (hash); + + /* Link together the top-level folders */ + tail = top; + for (i = 0; i < folders->len; i++) { + fi = folders->pdata[i]; + + if (fi->child) + fi->flags &= ~CAMEL_FOLDER_NOCHILDREN; + + if (fi->parent || fi == top) + continue; + if (tail == NULL) { + tail = fi; + top = fi; + } else { + tail->next = fi; + tail = fi; + } + } + + return top; +} + +static CamelFolderInfo * +folder_info_clone_rec (CamelFolderInfo *fi, + CamelFolderInfo *parent) +{ + CamelFolderInfo *info; + + info = camel_folder_info_new (); + info->parent = parent; + info->uri = g_strdup (fi->uri); + info->name = g_strdup (fi->name); + info->full_name = g_strdup (fi->full_name); + info->unread = fi->unread; + info->flags = fi->flags; + + if (fi->next) + info->next = folder_info_clone_rec (fi->next, parent); + else + info->next = NULL; + + if (fi->child) + info->child = folder_info_clone_rec (fi->child, info); + else + info->child = NULL; + + return info; +} + +/** + * camel_folder_info_clone: + * @fi: a #CamelFolderInfo + * + * Clones @fi recursively. + * + * Returns: the cloned #CamelFolderInfo tree. + **/ +CamelFolderInfo * +camel_folder_info_clone (CamelFolderInfo *fi) +{ + if (fi == NULL) + return NULL; + + return folder_info_clone_rec (fi, NULL); +} + +/** + * camel_store_supports_subscriptions: + * @store: a #CamelStore + * + * Get whether or not @store supports subscriptions to folders. + * + * Returns: %TRUE if folder subscriptions are supported or %FALSE otherwise + **/ +gboolean +camel_store_supports_subscriptions (CamelStore *store) +{ + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + + return (store->flags & CAMEL_STORE_SUBSCRIPTIONS); +} + +/** + * camel_store_folder_is_subscribed: + * @store: a #CamelStore + * @folder_name: full path of the folder + * + * Find out if a folder has been subscribed to. + * + * Returns: %TRUE if the folder has been subscribed to or %FALSE otherwise + **/ +gboolean +camel_store_folder_is_subscribed (CamelStore *store, + const gchar *folder_name) +{ + CamelStoreClass *class; + gboolean is_subscribed; + + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (folder_name != NULL, FALSE); + g_return_val_if_fail (store->flags & CAMEL_STORE_SUBSCRIPTIONS, FALSE); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->folder_is_subscribed != NULL, FALSE); + + camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + + is_subscribed = class->folder_is_subscribed (store, folder_name); + + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + + return is_subscribed; +} + +/** + * camel_store_folder_uri_equal: + * @store: a #CamelStore + * @uri0: a folder uri + * @uri1: another folder uri + * + * Compares two folder uris to check that they are equal. + * + * Returns: %TRUE if they are equal or %FALSE otherwise + **/ +gint +camel_store_folder_uri_equal (CamelStore *store, + const gchar *uri0, + const gchar *uri1) +{ + CamelStoreClass *class; + CamelProvider *provider; + CamelURL *url0, *url1; + gint equal; + + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (uri0 && uri1, FALSE); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->compare_folder_name != NULL, FALSE); + + provider = ((CamelService *) store)->provider; + + if (!(url0 = camel_url_new (uri0, NULL))) + return FALSE; + + if (!(url1 = camel_url_new (uri1, NULL))) { + camel_url_free (url0); + return FALSE; + } + + if ((equal = provider->url_equal (url0, url1))) { + const gchar *name0, *name1; + + if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) { + name0 = url0->fragment; + name1 = url1->fragment; + } else { + name0 = url0->path && url0->path[0] == '/' ? url0->path + 1 : url0->path; + name1 = url1->path && url1->path[0] == '/' ? url1->path + 1 : url1->path; + } + + if (name0 == NULL) + g_warning("URI is badly formed, missing folder name: %s", uri0); + + if (name1 == NULL) + g_warning("URI is badly formed, missing folder name: %s", uri1); + + equal = name0 && name1 && class->compare_folder_name (name0, name1); + } + + camel_url_free (url0); + camel_url_free (url1); + + return equal; +} + +/** + * camel_store_can_refresh_folder + * @store: a #CamelStore + * @info: a #CamelFolderInfo + * @error: return location for a #GError, or %NULL + * + * Returns if this folder (param info) should be checked for new mail or not. + * It should not look into sub infos (info->child) or next infos, it should + * return value only for the actual folder info. + * Default behavior is that all Inbox folders are intended to be refreshed. + * + * Returns: whether folder should be checked for new mails + * + * Since: 2.22 + **/ +gboolean +camel_store_can_refresh_folder (CamelStore *store, + CamelFolderInfo *info, + GError **error) +{ + CamelStoreClass *class; + + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (info != NULL, FALSE); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->can_refresh_folder != NULL, FALSE); + + return class->can_refresh_folder (store, info, error); +} + +/** + * camel_store_lock: + * @store: a #CamelStore + * @lock: lock type to lock + * + * Locks #store's #lock. Unlock it with camel_store_unlock(). + * + * Since: 2.32 + **/ +void +camel_store_lock (CamelStore *store, + CamelStoreLock lock) +{ + g_return_if_fail (CAMEL_IS_STORE (store)); + + switch (lock) { + case CAMEL_STORE_FOLDER_LOCK: + g_static_rec_mutex_lock (&store->priv->folder_lock); + break; + default: + g_return_if_reached (); + } +} + +/** + * camel_store_unlock: + * @store: a #CamelStore + * @lock: lock type to unlock + * + * Unlocks #store's #lock, previously locked with camel_store_lock(). + * + * Since: 2.32 + **/ +void +camel_store_unlock (CamelStore *store, + CamelStoreLock lock) +{ + g_return_if_fail (CAMEL_IS_STORE (store)); + + switch (lock) { + case CAMEL_STORE_FOLDER_LOCK: + g_static_rec_mutex_unlock (&store->priv->folder_lock); + break; + default: + g_return_if_reached (); + } +} + +/** + * camel_store_get_folder_sync: + * @store: a #CamelStore + * @folder_name: name of the folder to get + * @flags: folder flags (create, save body index, etc) + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Gets a specific folder object from @store by name. + * + * Returns: the requested #CamelFolder object, or %NULL on error + * + * Since: 2.34 + **/ +CamelFolder * +camel_store_get_folder_sync (CamelStore *store, + const gchar *folder_name, + guint32 flags, + GCancellable *cancellable, + GError **error) +{ + CamelStoreClass *class; + CamelFolder *folder = NULL; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (folder_name != NULL, NULL); + + class = CAMEL_STORE_GET_CLASS (store); + + /* O_EXCL doesn't make sense if we aren't requesting to also create the folder if it doesn't exist */ + if (!(flags & CAMEL_STORE_FOLDER_CREATE)) + flags &= ~CAMEL_STORE_FOLDER_EXCL; + + if (store->folders) { + /* Try cache first. */ + folder = camel_object_bag_reserve (store->folders, folder_name); + if (folder && (flags & CAMEL_STORE_FOLDER_EXCL)) { + g_set_error ( + error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, + _("Cannot create folder '%s': folder exists"), + folder_name); + camel_object_bag_abort (store->folders, folder_name); + g_object_unref (folder); + return NULL; + } + } + + if (!folder) { + + if (flags & CAMEL_STORE_IS_MIGRATING) { + if ((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0) { + if (store->folders) + camel_object_bag_abort (store->folders, folder_name); + return NULL; + } + + if ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0) { + if (store->folders) + camel_object_bag_abort (store->folders, folder_name); + return NULL; + } + } + + if ((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0) { + folder = class->get_trash_folder_sync (store, cancellable, error); + CAMEL_CHECK_GERROR (store, get_trash_folder_sync, folder != NULL, error); + } else if ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0) { + folder = class->get_junk_folder_sync (store, cancellable, error); + CAMEL_CHECK_GERROR (store, get_junk_folder_sync, folder != NULL, error); + } else { + folder = class->get_folder_sync ( + store, folder_name, flags, cancellable, error); + CAMEL_CHECK_GERROR (store, get_folder_sync, folder != NULL, error); + + if (folder) { + CamelVeeFolder *vfolder; + + if ((store->flags & CAMEL_STORE_VTRASH) + && (vfolder = camel_object_bag_get (store->folders, CAMEL_VTRASH_NAME))) { + camel_vee_folder_add_folder (vfolder, folder); + g_object_unref (vfolder); + } + + if ((store->flags & CAMEL_STORE_VJUNK) + && (vfolder = camel_object_bag_get (store->folders, CAMEL_VJUNK_NAME))) { + camel_vee_folder_add_folder (vfolder, folder); + g_object_unref (vfolder); + } + } + } + + if (store->folders) { + if (folder) + camel_object_bag_add (store->folders, folder_name, folder); + else + camel_object_bag_abort (store->folders, folder_name); + } + + if (folder) + g_signal_emit (store, signals[FOLDER_OPENED], 0, folder); + } + + return folder; +} + +/** + * camel_store_get_folder: + * @store: a #CamelStore + * @folder_name: name of the folder to get + * @flags: folder flags (create, save body index, etc) + * @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 gets a specific folder object from @store by name. + * + * When the operation is finished, @callback will be called. You can then + * call camel_store_get_folder_finish() to get the result of the operation. + * + * Since: 2.34 + **/ +void +camel_store_get_folder (CamelStore *store, + const gchar *folder_name, + guint32 flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + g_return_if_fail (folder_name != NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->get_folder != NULL); + + class->get_folder ( + store, folder_name, flags, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_store_get_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_store_get_folder(). + * + * Returns: the requested #CamelFolder object, or %NULL on error + * + * Since: 2.34 + **/ +CamelFolder * +camel_store_get_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + CamelStoreClass *class; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->get_folder_finish != NULL, NULL); + + return class->get_folder_finish (store, result, error); +} + +/** + * camel_store_get_folder_info_sync: + * @store: a #CamelStore + * @top: the name of the folder to start from + * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * This fetches information about the folder structure of @store, + * starting with @top, and returns a tree of #CamelFolderInfo + * structures. If @flags includes %CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, + * only subscribed folders will be listed. If the store doesn't support + * subscriptions, then it will list all folders. If @flags includes + * %CAMEL_STORE_FOLDER_INFO_RECURSIVE, the returned tree will include + * all levels of hierarchy below @top. If not, it will only include + * the immediate subfolders of @top. If @flags includes + * %CAMEL_STORE_FOLDER_INFO_FAST, the unread_message_count fields of + * some or all of the structures may be set to %-1, if the store cannot + * determine that information quickly. If @flags includes + * %CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, don't include special virtual * folders (such as vTrash or vJunk). * - * The CAMEL_STORE_FOLDER_INFO_FAST flag should be considered - * deprecated; most backends will behave the same whether it is - * supplied or not. The only guaranteed way to get updated folder - * counts is to both open the folder and invoke refresh_info() it. + * The returned #CamelFolderInfo tree should be freed with + * camel_store_free_folder_info(). + * + * The CAMEL_STORE_FOLDER_INFO_FAST flag should be considered + * deprecated; most backends will behave the same whether it is + * supplied or not. The only guaranteed way to get updated folder + * counts is to both open the folder and invoke refresh_info() it. + * + * Returns: a #CamelFolderInfo tree, or %NULL on error + * + * Since: 2.34 + **/ +CamelFolderInfo * +camel_store_get_folder_info_sync (CamelStore *store, + const gchar *top, + guint32 flags, + GCancellable *cancellable, + GError **error) +{ + CamelStoreClass *class; + CamelFolderInfo *info; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->get_folder_info_sync != NULL, NULL); + + info = class->get_folder_info_sync ( + store, top, flags, cancellable, error); + if (!(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)) + CAMEL_CHECK_GERROR ( + store, get_folder_info_sync, info != NULL, error); + + if (info && (top == NULL || *top == '\0') && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) { + if (info->uri && (store->flags & CAMEL_STORE_VTRASH)) + /* the name of the Trash folder, used for deleted messages */ + add_special_info (store, info, CAMEL_VTRASH_NAME, _("Trash"), FALSE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_TRASH); + if (info->uri && (store->flags & CAMEL_STORE_VJUNK)) + /* the name of the Junk folder, used for spam messages */ + add_special_info (store, info, CAMEL_VJUNK_NAME, _("Junk"), TRUE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_JUNK); + } + + if (camel_debug_start("store:folder_info")) { + gchar *url = camel_url_to_string (((CamelService *)store)->url, CAMEL_URL_HIDE_ALL); + printf("Get folder info(%p:%s, '%s') =\n", (gpointer) store, url, top?top:""); + g_free (url); + dump_fi (info, 2); + camel_debug_end (); + } + + return info; +} + +/** + * camel_store_get_folder_info: + * @store: a #CamelStore + * @top: the name of the folder to start from + * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior + * @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 fetches information about the folder structure of @store, + * starting with @top. For details of the behavior, see + * camel_store_get_folder_info_sync(). + * + * When the operation is finished, @callback will be called. You can + * then call camel_store_get_folder_info_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_store_get_folder_info (CamelStore *store, + const gchar *top, + guint32 flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->get_folder_info != NULL); + + class->get_folder_info ( + store, top, flags, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_store_get_folder_info_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_store_get_folder_info(). + * The returned #CamelFolderInfo tree should be freed with + * camel_store_free_folder_info(). + * + * Returns: a #CamelFolderInfo tree, or %NULL on error + * + * Since: 2.34 + **/ +CamelFolderInfo * +camel_store_get_folder_info_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + CamelStoreClass *class; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->get_folder_info_finish != NULL, NULL); + + return class->get_folder_info_finish (store, result, error); +} + +/** + * camel_store_get_inbox_folder_sync: + * @store: a #CamelStore + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Gets the folder in @store into which new mail is delivered. + * + * Returns: the inbox folder for @store, or %NULL on error or if no such + * folder exists + * + * Since: 2.34 + **/ +CamelFolder * +camel_store_get_inbox_folder_sync (CamelStore *store, + GCancellable *cancellable, + GError **error) +{ + CamelStoreClass *class; + CamelFolder *folder; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->get_inbox_folder_sync != NULL, NULL); + + camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + return NULL; + } + + folder = class->get_inbox_folder_sync (store, cancellable, error); + CAMEL_CHECK_GERROR ( + store, get_inbox_folder_sync, folder != NULL, error); + + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + + return folder; +} + +/** + * camel_store_get_inbox_folder: + * @store: a #CamelStore + * @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 gets the folder in @store into which new mail is delivered. + * + * When the operation is finished, @callback will be called. You can + * then call camel_store_get_inbox_folder_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_store_get_inbox_folder (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->get_inbox_folder != NULL); + + class->get_inbox_folder ( + store, io_priority, cancellable, callback, user_data); +} + +/** + * camel_store_get_inbox_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_store_get_inbox_folder(). + * + * Returns: the inbox folder for @store, or %NULL on error or if no such + * folder exists + * + * Since: 2.34 + **/ +CamelFolder * +camel_store_get_inbox_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + CamelStoreClass *class; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->get_inbox_folder_finish != NULL, NULL); + + return class->get_inbox_folder_finish (store, result, error); +} + +/** + * camel_store_get_junk_folder_sync: + * @store: a #CamelStore + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Gets the folder in @store into which junk is delivered. + * + * Returns: the junk folder for @store, or %NULL on error or if no such + * folder exists + * + * Since: 2.34 + **/ +CamelFolder * +camel_store_get_junk_folder_sync (CamelStore *store, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + + if ((store->flags & CAMEL_STORE_VJUNK) == 0) { + CamelStoreClass *class; + CamelFolder *folder; + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->get_junk_folder_sync != NULL, NULL); + + folder = class->get_junk_folder_sync (store, cancellable, error); + CAMEL_CHECK_GERROR ( + store, get_junk_folder_sync, folder != NULL, error); + + return folder; + } + + return camel_store_get_folder_sync ( + store, CAMEL_VJUNK_NAME, 0, cancellable, error); +} + +/** + * camel_store_get_junk_folder: + * @store: a #CamelStore + * @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 gets the folder in @store into which junk is delivered. + * + * When the operation is finished, @callback will be called. You can + * then call camel_store_get_junk_folder_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_store_get_junk_folder (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->get_junk_folder != NULL); + + class->get_junk_folder ( + store, io_priority, cancellable, callback, user_data); +} + +/** + * camel_store_get_junk_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_store_get_junk_folder(). + * + * Returns: the junk folder for @store, or %NULL on error or if no such + * folder exists + * + * Since: 2.34 + **/ +CamelFolder * +camel_store_get_junk_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + CamelStoreClass *class; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->get_junk_folder_finish != NULL, NULL); + + return class->get_junk_folder_finish (store, result, error); +} + +/** + * camel_store_get_trash_folder_sync: + * @store: a #CamelStore + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Gets the folder in @store into which trash is delivered. + * + * Returns: the trash folder for @store, or %NULL on error or if no such + * folder exists + * + * Since: 2.34 + **/ +CamelFolder * +camel_store_get_trash_folder_sync (CamelStore *store, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + + if ((store->flags & CAMEL_STORE_VTRASH) == 0) { + CamelStoreClass *class; + CamelFolder *folder; + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->get_trash_folder_sync != NULL, NULL); + + folder = class->get_trash_folder_sync ( + store, cancellable, error); + CAMEL_CHECK_GERROR ( + store, get_trash_folder_sync, folder != NULL, error); + + return folder; + } + + return camel_store_get_folder_sync ( + store, CAMEL_VTRASH_NAME, 0, cancellable, error); +} + +/** + * camel_store_get_trash_folder: + * @store: a #CamelStore + * @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 gets the folder in @store into which trash is delivered. + * + * When the operation is finished, @callback will be called. You can + * then call camel_store_get_trash_folder_finish() to get the result of + * the operation. * - * Returns: a #CamelFolderInfo tree, which must be freed with - * #camel_store_free_folder_info, or %NULL. + * Since: 2.34 **/ -CamelFolderInfo * -camel_store_get_folder_info_sync (CamelStore *store, - const gchar *top, - guint32 flags, - GCancellable *cancellable, - GError **error) +void +camel_store_get_trash_folder (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->get_trash_folder != NULL); + + class->get_trash_folder ( + store, io_priority, cancellable, callback, user_data); +} + +/** + * camel_store_get_trash_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_store_get_trash_folder(). + * + * Returns: the trash folder for @store, or %NULL on error or if no such + * folder exists + * + * Since: 2.34 + **/ +CamelFolder * +camel_store_get_trash_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { CamelStoreClass *class; - CamelFolderInfo *info; g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->get_folder_info_sync != NULL, NULL); + g_return_val_if_fail (class->get_trash_folder_finish != NULL, NULL); - info = class->get_folder_info_sync ( - store, top, flags, cancellable, error); - if (!(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)) - CAMEL_CHECK_GERROR ( - store, get_folder_info_sync, info != NULL, error); + return class->get_trash_folder_finish (store, result, error); +} - if (info && (top == NULL || *top == '\0') && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) { - if (info->uri && (store->flags & CAMEL_STORE_VTRASH)) - /* the name of the Trash folder, used for deleted messages */ - add_special_info (store, info, CAMEL_VTRASH_NAME, _("Trash"), FALSE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_TRASH); - if (info->uri && (store->flags & CAMEL_STORE_VJUNK)) - /* the name of the Junk folder, used for spam messages */ - add_special_info (store, info, CAMEL_VJUNK_NAME, _("Junk"), TRUE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_JUNK); +/** + * camel_store_create_folder_sync: + * @store: a #CamelStore + * @parent_name: name of the new folder's parent, or %NULL + * @folder_name: name of the folder to create + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Creates a new folder as a child of an existing folder. + * @parent_name can be %NULL to create a new top-level folder. + * The returned #CamelFolderInfo struct should be freed with + * camel_store_free_folder_info(). + * + * Returns: info about the created folder, or %NULL on error + * + * Since: 2.34 + **/ +CamelFolderInfo * +camel_store_create_folder_sync (CamelStore *store, + const gchar *parent_name, + const gchar *folder_name, + GCancellable *cancellable, + GError **error) +{ + CamelStoreClass *class; + CamelFolderInfo *fi; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (folder_name != NULL, NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->create_folder_sync != NULL, NULL); + + if ((parent_name == NULL || parent_name[0] == 0) + && (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0) + || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0))) { + g_set_error ( + error, CAMEL_STORE_ERROR, + CAMEL_STORE_ERROR_INVALID, + _("Cannot create folder: %s: folder exists"), + folder_name); + return NULL; } - if (camel_debug_start("store:folder_info")) { - gchar *url = camel_url_to_string (((CamelService *)store)->url, CAMEL_URL_HIDE_ALL); - printf("Get folder info(%p:%s, '%s') =\n", (gpointer) store, url, top?top:""); - g_free (url); - dump_fi (info, 2); - camel_debug_end (); + camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + return NULL; } - return info; + fi = class->create_folder_sync ( + store, parent_name, folder_name, cancellable, error); + CAMEL_CHECK_GERROR (store, create_folder_sync, fi != NULL, error); + + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + + return fi; } /** - * camel_store_free_folder_info: - * @store: a #CamelStore object - * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info + * camel_store_create_folder: + * @store: a #CamelStore + * @parent_name: name of the new folder's parent, or %NULL + * @folder_name: name of the folder to create + * @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 * - * Frees the data returned by #camel_store_get_folder_info. If @fi is %NULL, - * nothing is done, the routine simply returns. + * Asynchronously creates a new folder as a child of an existing folder. + * @parent_name can be %NULL to create a new top-level folder. + * + * When the operation is finished, @callback will be called. You can then + * call camel_store_create_folder_finish() to get the result of the operation. + * + * Since: 2.34 **/ void -camel_store_free_folder_info (CamelStore *store, - CamelFolderInfo *fi) +camel_store_create_folder (CamelStore *store, + const gchar *parent_name, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { CamelStoreClass *class; g_return_if_fail (CAMEL_IS_STORE (store)); - - if (fi == NULL) - return; + g_return_if_fail (folder_name != NULL); class = CAMEL_STORE_GET_CLASS (store); - g_return_if_fail (class->free_folder_info != NULL); + g_return_if_fail (class->create_folder != NULL); - class->free_folder_info (store, fi); + class->create_folder ( + store, parent_name, folder_name, io_priority, + cancellable, callback, user_data); } /** - * camel_store_free_folder_info_full: - * @store: a #CamelStore object - * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info + * camel_store_create_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL * - * An implementation for #CamelStore::free_folder_info. Frees all - * of the data. + * Finishes the operation started with camel_store_create_folder(). + * The returned #CamelFolderInfo struct should be freed with + * camel_store_free_folder_info(). + * + * Returns: info about the created folder, or %NULL on error + * + * Since: 2.34 **/ -void -camel_store_free_folder_info_full (CamelStore *store, - CamelFolderInfo *fi) +CamelFolderInfo * +camel_store_create_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - camel_folder_info_free (fi); + CamelStoreClass *class; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->create_folder_finish != NULL, NULL); + + return class->create_folder_finish (store, result, error); } /** - * camel_store_free_folder_info_nop: - * @store: a #CamelStore object - * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info + * camel_store_delete_folder_sync: + * @store: a #CamelStore + * @folder_name: name of the folder to delete + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL * - * An implementation for #CamelStore::free_folder_info. Does nothing. + * Deletes the folder described by @folder_name. The folder must be empty. + * + * Returns: %TRUE on success, %FALSE on failure + * + * Since: 2.34 **/ -void -camel_store_free_folder_info_nop (CamelStore *store, - CamelFolderInfo *fi) +gboolean +camel_store_delete_folder_sync (CamelStore *store, + const gchar *folder_name, + GCancellable *cancellable, + GError **error) { - ; + CamelStoreClass *class; + gboolean success; + GError *local_error = NULL; + + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (folder_name != NULL, FALSE); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->delete_folder_sync != NULL, FALSE); + + /* TODO: should probably be a parameter/bit on the storeinfo */ + if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0) + || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0)) { + g_set_error ( + error, CAMEL_STORE_ERROR, + CAMEL_STORE_ERROR_NO_FOLDER, + _("Cannot delete folder: %s: Invalid operation"), + folder_name); + return FALSE; + } + + camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + return FALSE; + } + + success = class->delete_folder_sync ( + store, folder_name, cancellable, &local_error); + CAMEL_CHECK_GERROR (store, delete_folder_sync, success, &local_error); + + /* ignore 'no such table' errors */ + if (local_error != NULL && + g_ascii_strncasecmp (local_error->message, "no such table", 13) == 0) + g_clear_error (&local_error); + + if (local_error == NULL) + cs_delete_cached_folder(store, folder_name); + else + g_propagate_error (error, local_error); + + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + + return success; } /** - * camel_folder_info_free: - * @fi: a #CamelFolderInfo + * camel_store_delete_folder: + * @store: a #CamelStore + * @folder_name: name of the folder to delete + * @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 * - * Frees @fi. + * Asynchronously deletes the folder described by @folder_name. The + * folder must be empty. + * + * When the operation is finished, @callback will be called. You can then + * call camel_store_delete_folder_finish() to get the result of the operation. + * + * Since: 2.34 **/ void -camel_folder_info_free (CamelFolderInfo *fi) +camel_store_delete_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - if (fi != NULL) { - camel_folder_info_free (fi->next); - camel_folder_info_free (fi->child); - g_free (fi->name); - g_free (fi->full_name); - g_free (fi->uri); - g_slice_free (CamelFolderInfo, fi); - } + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + g_return_if_fail (folder_name != NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->delete_folder != NULL); + + class->delete_folder ( + store, folder_name, io_priority, + cancellable, callback, user_data); } /** - * camel_folder_info_new: + * camel_store_delete_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL * - * Returns: a new empty CamelFolderInfo instance + * Finishes the operation started with camel_store_delete_folder(). * - * Since: 2.22 + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -CamelFolderInfo * -camel_folder_info_new (void) +gboolean +camel_store_delete_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - return g_slice_new0 (CamelFolderInfo); -} + CamelStoreClass *class; -static gint -folder_info_cmp (gconstpointer ap, - gconstpointer bp) -{ - const CamelFolderInfo *a = ((CamelFolderInfo **)ap)[0]; - const CamelFolderInfo *b = ((CamelFolderInfo **)bp)[0]; + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->delete_folder_finish != NULL, FALSE); - return strcmp (a->full_name, b->full_name); + return class->delete_folder_finish (store, result, error); } /** - * camel_folder_info_build: - * @folders: an array of #CamelFolderInfo - * @namespace: an ignorable prefix on the folder names - * @separator: the hieararchy separator character - * @short_names: %TRUE if the (short) name of a folder is the part after - * the last @separator in the full name. %FALSE if it is the full name. + * camel_store_rename_folder_sync: + * @store: a #CamelStore + * @old_name: the current name of the folder + * @new_name: the new name of the folder + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL * - * This takes an array of folders and attaches them together according - * to the hierarchy described by their full_names and @separator. If - * @namespace is non-%NULL, then it will be ignored as a full_name - * prefix, for purposes of comparison. If necessary, - * #camel_folder_info_build will create additional #CamelFolderInfo with - * %NULL urls to fill in gaps in the tree. The value of @short_names - * is used in constructing the names of these intermediate folders. + * Renames the folder described by @old_name to @new_name. * - * NOTE: This is deprected, do not use this. - * FIXME: remove this/move it to imap, which is the only user of it now. + * Returns: %TRUE on success, %FALSE on error * - * Returns: the top level of the tree of linked folder info. + * Since: 2.34 **/ -CamelFolderInfo * -camel_folder_info_build (GPtrArray *folders, - const gchar *namespace, - gchar separator, - gboolean short_names) +gboolean +camel_store_rename_folder_sync (CamelStore *store, + const gchar *old_namein, + const gchar *new_name, + GCancellable *cancellable, + GError **error) { - CamelFolderInfo *fi, *pfi, *top = NULL, *tail = NULL; - GHashTable *hash; - gchar *p, *pname; - gint i, nlen; + CamelStoreClass *class; + CamelFolder *folder; + gint i, oldlen, namelen; + GPtrArray *folders = NULL; + gchar *old_name; + gboolean success; - if (!namespace) - namespace = ""; - nlen = strlen (namespace); + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (old_namein != NULL, FALSE); + g_return_val_if_fail (new_name != NULL, FALSE); - qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_info_cmp); + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->rename_folder_sync != NULL, FALSE); - /* Hash the folders. */ - hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - for (i = 0; i < folders->len; i++) { - fi = folders->pdata[i]; - g_hash_table_insert (hash, g_strdup (fi->full_name), fi); - } + if (strcmp (old_namein, new_name) == 0) + return TRUE; - /* Now find parents. */ - for (i = 0; i < folders->len; i++) { - fi = folders->pdata[i]; - if (!strncmp (namespace, fi->full_name, nlen) - && (p = strrchr (fi->full_name+nlen, separator))) { - pname = g_strndup (fi->full_name, p - fi->full_name); - pfi = g_hash_table_lookup (hash, pname); - if (pfi) { - g_free (pname); - } else { - /* we are missing a folder in the heirarchy so - create a fake folder node */ - const gchar *path; - CamelURL *url; - gchar *sep; + if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (old_namein, CAMEL_VTRASH_NAME) == 0) + || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (old_namein, CAMEL_VJUNK_NAME) == 0)) { + g_set_error ( + error, CAMEL_STORE_ERROR, + CAMEL_STORE_ERROR_NO_FOLDER, + _("Cannot rename folder: %s: Invalid operation"), + old_namein); + return FALSE; + } - pfi = camel_folder_info_new (); - if (short_names) { - pfi->name = strrchr (pname, separator); - if (pfi->name) - pfi->name = g_strdup (pfi->name + 1); - else - pfi->name = g_strdup (pname); - } else - pfi->name = g_strdup (pname); + /* need to save this, since old_namein might be folder->full_name, which could go away */ + old_name = g_strdup (old_namein); + oldlen = strlen (old_name); - url = camel_url_new (fi->uri, NULL); - if (url->fragment) - path = url->fragment; - else - path = url->path + 1; + camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); - sep = strrchr (path, separator); - if (sep) - *sep = '\0'; - else { - d(g_warning ("huh, no \"%c\" in \"%s\"?", separator, fi->uri)); - } + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + return FALSE; + } - pfi->full_name = g_strdup (path); + /* If the folder is open (or any subfolders of the open folder) + We need to rename them atomically with renaming the actual folder path */ + if (store->folders) { + folders = camel_object_bag_list (store->folders); + for (i=0;ilen;i++) { + const gchar *full_name; - /* since this is a "fake" folder node, it is not selectable */ - camel_url_set_param (url, "noselect", "yes"); - pfi->uri = camel_url_to_string (url, 0); - camel_url_free (url); + folder = folders->pdata[i]; + full_name = camel_folder_get_full_name (folder); - g_hash_table_insert (hash, pname, pfi); - g_ptr_array_add (folders, pfi); + namelen = strlen (full_name); + if ((namelen == oldlen && + strcmp (full_name, old_name) == 0) + || ((namelen > oldlen) + && strncmp (full_name, old_name, oldlen) == 0 + && full_name[oldlen] == '/')) { + camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK); + } else { + g_ptr_array_remove_index_fast (folders, i); + i--; + g_object_unref (folder); } - tail = (CamelFolderInfo *)&pfi->child; - while (tail->next) - tail = tail->next; - tail->next = fi; - fi->parent = pfi; - } else if (!top) - top = fi; + } } - g_hash_table_destroy (hash); - /* Link together the top-level folders */ - tail = top; - for (i = 0; i < folders->len; i++) { - fi = folders->pdata[i]; + /* Now try the real rename (will emit renamed signal) */ + success = class->rename_folder_sync ( + store, old_name, new_name, cancellable, error); + CAMEL_CHECK_GERROR (store, rename_folder_sync, success, error); - if (fi->child) - fi->flags &= ~CAMEL_FOLDER_NOCHILDREN; + /* If it worked, update all open folders/unlock them */ + if (folders) { + if (success) { + guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE; + CamelFolderInfo *folder_info; - if (fi->parent || fi == top) - continue; - if (tail == NULL) { - tail = fi; - top = fi; - } else { - tail->next = fi; - tail = fi; - } - } + for (i=0;ilen;i++) { + const gchar *full_name; + gchar *new; - return top; -} + folder = folders->pdata[i]; + full_name = camel_folder_get_full_name (folder); -static CamelFolderInfo * -folder_info_clone_rec (CamelFolderInfo *fi, - CamelFolderInfo *parent) -{ - CamelFolderInfo *info; + new = g_strdup_printf("%s%s", new_name, full_name + strlen(old_name)); + camel_object_bag_rekey (store->folders, folder, new); + camel_folder_rename (folder, new); + g_free (new); - info = camel_folder_info_new (); - info->parent = parent; - info->uri = g_strdup (fi->uri); - info->name = g_strdup (fi->name); - info->full_name = g_strdup (fi->full_name); - info->unread = fi->unread; - info->flags = fi->flags; + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + g_object_unref (folder); + } - if (fi->next) - info->next = folder_info_clone_rec (fi->next, parent); - else - info->next = NULL; + /* Emit renamed signal */ + if (store->flags & CAMEL_STORE_SUBSCRIPTIONS) + flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED; - if (fi->child) - info->child = folder_info_clone_rec (fi->child, info); - else - info->child = NULL; + folder_info = class->get_folder_info_sync ( + store, new_name, flags, cancellable, error); + CAMEL_CHECK_GERROR (store, get_folder_info, folder_info != NULL, error); - return info; -} + if (folder_info != NULL) { + camel_store_folder_renamed (store, old_name, folder_info); + class->free_folder_info (store, folder_info); + } + } else { + /* Failed, just unlock our folders for re-use */ + for (i=0;ilen;i++) { + folder = folders->pdata[i]; + camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK); + g_object_unref (folder); + } + } + } -/** - * camel_folder_info_clone: - * @fi: a #CamelFolderInfo - * - * Clones @fi recursively. - * - * Returns: the cloned #CamelFolderInfo tree. - **/ -CamelFolderInfo * -camel_folder_info_clone (CamelFolderInfo *fi) -{ - if (fi == NULL) - return NULL; + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); - return folder_info_clone_rec (fi, NULL); + g_ptr_array_free (folders, TRUE); + g_free (old_name); + + return success; } /** - * camel_store_supports_subscriptions: - * @store: a #CamelStore object + * camel_store_rename_folder: + * @store: a #CamelStore + * @old_name: the current name of the folder + * @new_name: the new name of the folder + * @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 * - * Get whether or not @store supports subscriptions to folders. + * Asynchronously renames the folder described by @old_name to @new_name. * - * Returns: %TRUE if folder subscriptions are supported or %FALSE otherwise + * When the operation is finished, @callback will be called. You can then + * call camel_store_rename_folder_finish() to get the result of the operation. + * + * Since: 2.34 **/ -gboolean -camel_store_supports_subscriptions (CamelStore *store) +void +camel_store_rename_folder (CamelStore *store, + const gchar *old_name, + const gchar *new_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + CamelStoreClass *class; - return (store->flags & CAMEL_STORE_SUBSCRIPTIONS); + g_return_if_fail (CAMEL_IS_STORE (store)); + g_return_if_fail (old_name != NULL); + g_return_if_fail (new_name != NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->rename_folder != NULL); + + class->rename_folder ( + store, old_name, new_name, io_priority, + cancellable, callback, user_data); } /** - * camel_store_folder_is_subscribed: - * @store: a #CamelStore object - * @folder_name: full path of the folder + * camel_store_rename_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL * - * Find out if a folder has been subscribed to. + * Finishes the operation started with camel_store_rename_folder(). * - * Returns: %TRUE if the folder has been subscribed to or %FALSE otherwise + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ gboolean -camel_store_folder_is_subscribed (CamelStore *store, - const gchar *folder_name) +camel_store_rename_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { CamelStoreClass *class; - gboolean is_subscribed; g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); - g_return_val_if_fail (folder_name != NULL, FALSE); - g_return_val_if_fail (store->flags & CAMEL_STORE_SUBSCRIPTIONS, FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->folder_is_subscribed != NULL, FALSE); - - camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); - - is_subscribed = class->folder_is_subscribed (store, folder_name); + g_return_val_if_fail (class->rename_folder_finish != NULL, FALSE); - camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); - - return is_subscribed; + return class->rename_folder_finish (store, result, error); } /** * camel_store_subscribe_folder_sync: - * @store: a #CamelStore object + * @store: a #CamelStore * @folder_name: full path of the folder * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * - * Subscribe to the folder described by @folder_name. + * Subscribes to the folder described by @folder_name. * - * Returns: %TRUE on success, %FALSE on failure + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ gboolean camel_store_subscribe_folder_sync (CamelStore *store, @@ -1526,6 +3054,12 @@ camel_store_subscribe_folder_sync (CamelStore *store, camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + return FALSE; + } + success = class->subscribe_folder_sync ( store, folder_name, cancellable, error); CAMEL_CHECK_GERROR (store, subscribe_folder_sync, success, error); @@ -1536,15 +3070,83 @@ camel_store_subscribe_folder_sync (CamelStore *store, } /** + * camel_store_subscribe_folder: + * @store: a #CamelStore + * @folder_name: full path of the folder + * @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 subscribes to the folder described by @folder_name. + * + * When the operation is finished, @callback will be called. You can + * then call camel_store_subscribe_folder_finish() to get the result of + * the operation. + * + * Since: 2.34 + **/ +void +camel_store_subscribe_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + g_return_if_fail (folder_name != NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->subscribe_folder != NULL); + + class->subscribe_folder ( + store, folder_name, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_store_subscribe_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_store_subscribe_folder(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_store_subscribe_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + CamelStoreClass *class; + + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->subscribe_folder_finish != NULL, FALSE); + + return class->subscribe_folder_finish (store, result, error); +} + +/** * camel_store_unsubscribe_folder_sync: - * @store: a #CamelStore object + * @store: a #CamelStore * @folder_name: full path of the folder * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * - * Unsubscribe from the folder described by @folder_name. + * Unsubscribes from the folder described by @folder_name. * - * Returns: %TRUE on success, %FALSE on failure + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ gboolean camel_store_unsubscribe_folder_sync (CamelStore *store, @@ -1564,6 +3166,12 @@ camel_store_unsubscribe_folder_sync (CamelStore *store, camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK); + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK); + return FALSE; + } + success = class->unsubscribe_folder_sync ( store, folder_name, cancellable, error); CAMEL_CHECK_GERROR (store, unsubscribe_folder_sync, success, error); @@ -1577,171 +3185,257 @@ camel_store_unsubscribe_folder_sync (CamelStore *store, } /** - * camel_store_noop_sync: - * @store: a #CamelStore object + * camel_store_unsubscribe_folder: + * @store: a #CamelStore + * @folder_name: full path of the folder + * @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 unsubscribes from the folder described by @folder_name. + * + * When the operation is finished, @callback will be called. You can then + * call camel_store_unsubscribe_folder_finish() to get the result of the + * operation. + * + * Since: 2.34 + **/ +void +camel_store_unsubscribe_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelStoreClass *class; + + g_return_if_fail (CAMEL_IS_STORE (store)); + g_return_if_fail (folder_name != NULL); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->unsubscribe_folder != NULL); + + class->unsubscribe_folder ( + store, folder_name, io_priority, + cancellable, callback, user_data); +} + +/** + * camel_store_unsubscribe_folder_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * - * Pings @store so that its connection doesn't timeout. + * Finishes the operation started with camel_store_unsubscribe_folder(). * - * Returns: %TRUE on success, %FALSE on failure + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ gboolean -camel_store_noop_sync (CamelStore *store, - GCancellable *cancellable, - GError **error) +camel_store_unsubscribe_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { CamelStoreClass *class; - gboolean success; g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->noop_sync != NULL, FALSE); + g_return_val_if_fail (class->unsubscribe_folder_finish != NULL, FALSE); - success = class->noop_sync (store, cancellable, error); - CAMEL_CHECK_GERROR (store, noop_sync, success, error); - - return success; + return class->unsubscribe_folder_finish (store, result, error); } /** - * camel_store_folder_uri_equal: - * @store: a #CamelStore object - * @uri0: a folder uri - * @uri1: another folder uri + * camel_store_synchronize_sync: + * @store: a #CamelStore + * @expunge: whether to expunge after synchronizing + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL * - * Compares two folder uris to check that they are equal. + * Synchronizes any changes that have been made to @store and its folders + * with the real store. * - * Returns: %TRUE if they are equal or %FALSE otherwise + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -gint -camel_store_folder_uri_equal (CamelStore *store, - const gchar *uri0, - const gchar *uri1) +gboolean +camel_store_synchronize_sync (CamelStore *store, + gboolean expunge, + GCancellable *cancellable, + GError **error) { CamelStoreClass *class; - CamelProvider *provider; - CamelURL *url0, *url1; - gint equal; + gboolean success; g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); - g_return_val_if_fail (uri0 && uri1, FALSE); class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->compare_folder_name != NULL, FALSE); + g_return_val_if_fail (class->synchronize_sync != NULL, FALSE); - provider = ((CamelService *) store)->provider; + success = class->synchronize_sync (store, expunge, cancellable, error); + CAMEL_CHECK_GERROR (store, synchronize_sync, success, error); - if (!(url0 = camel_url_new (uri0, NULL))) - return FALSE; + return success; +} - if (!(url1 = camel_url_new (uri1, NULL))) { - camel_url_free (url0); - return FALSE; - } +/** + * camel_store_synchronize: + * @store: a #CamelStore + * @expunge: whether to expunge after synchronizing + * @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 + * + * Synchronizes any changes that have been made to @store and its folders + * with the real store asynchronously. + * + * When the operation is finished, @callback will be called. You can then + * call camel_store_synchronize_finish() to get the result of the operation. + * + * Since: 2.34 + **/ +void +camel_store_synchronize (CamelStore *store, + gboolean expunge, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CamelStoreClass *class; - if ((equal = provider->url_equal (url0, url1))) { - const gchar *name0, *name1; + g_return_if_fail (CAMEL_IS_STORE (store)); - if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) { - name0 = url0->fragment; - name1 = url1->fragment; - } else { - name0 = url0->path && url0->path[0] == '/' ? url0->path + 1 : url0->path; - name1 = url1->path && url1->path[0] == '/' ? url1->path + 1 : url1->path; - } + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->synchronize != NULL); - if (name0 == NULL) - g_warning("URI is badly formed, missing folder name: %s", uri0); + class->synchronize ( + store, expunge, io_priority, + cancellable, callback, user_data); +} - if (name1 == NULL) - g_warning("URI is badly formed, missing folder name: %s", uri1); +/** + * camel_store_synchronize_finish: + * @store: a #CamelStore + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with camel_store_synchronize(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 + **/ +gboolean +camel_store_synchronize_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + CamelStoreClass *class; - equal = name0 && name1 && class->compare_folder_name (name0, name1); - } + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); - camel_url_free (url0); - camel_url_free (url1); + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->synchronize_finish != NULL, FALSE); - return equal; + return class->synchronize_finish (store, result, error); } /** - * camel_store_can_refresh_folder + * camel_store_noop_sync: * @store: a #CamelStore - * @info: a #CamelFolderInfo + * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * - * Returns if this folder (param info) should be checked for new mail or not. - * It should not look into sub infos (info->child) or next infos, it should - * return value only for the actual folder info. - * Default behavior is that all Inbox folders are intended to be refreshed. + * Pings @store so its connection doesn't time out. * - * Returns: whether folder should be checked for new mails + * Returns: %TRUE on success, %FALSE on error * - * Since: 2.22 + * Since: 2.34 **/ gboolean -camel_store_can_refresh_folder (CamelStore *store, - CamelFolderInfo *info, - GError **error) +camel_store_noop_sync (CamelStore *store, + GCancellable *cancellable, + GError **error) { CamelStoreClass *class; + gboolean success; g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); - g_return_val_if_fail (info != NULL, FALSE); class = CAMEL_STORE_GET_CLASS (store); - g_return_val_if_fail (class->can_refresh_folder != NULL, FALSE); + g_return_val_if_fail (class->noop_sync != NULL, FALSE); - return class->can_refresh_folder (store, info, error); + success = class->noop_sync (store, cancellable, error); + CAMEL_CHECK_GERROR (store, noop_sync, success, error); + + return success; } /** - * camel_store_lock: + * camel_store_noop: * @store: a #CamelStore - * @lock: lock type to lock + * @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 * - * Locks #store's #lock. Unlock it with camel_store_unlock(). + * Pings @store asynchronously so its connection doesn't time out. * - * Since: 2.32 + * When the operation is finished, @callback will be called. You can then + * call camel_store_noop_finish() to get the result of the operation. + * + * Since: 2.34 **/ void -camel_store_lock (CamelStore *store, - CamelStoreLock lock) +camel_store_noop (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + CamelStoreClass *class; + g_return_if_fail (CAMEL_IS_STORE (store)); - switch (lock) { - case CAMEL_STORE_FOLDER_LOCK: - g_static_rec_mutex_lock (&store->priv->folder_lock); - break; - default: - g_return_if_reached (); - } + class = CAMEL_STORE_GET_CLASS (store); + g_return_if_fail (class->noop != NULL); + + class->noop (store, io_priority, cancellable, callback, user_data); } /** - * camel_store_unlock: + * camel_store_noop_finish: * @store: a #CamelStore - * @lock: lock type to unlock + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL * - * Unlocks #store's #lock, previously locked with camel_store_lock(). + * Finishes the operation started with camel_store_noop(). * - * Since: 2.32 + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -void -camel_store_unlock (CamelStore *store, - CamelStoreLock lock) +gboolean +camel_store_noop_finish (CamelStore *store, + GAsyncResult *result, + GError **error) { - g_return_if_fail (CAMEL_IS_STORE (store)); + CamelStoreClass *class; - switch (lock) { - case CAMEL_STORE_FOLDER_LOCK: - g_static_rec_mutex_unlock (&store->priv->folder_lock); - break; - default: - g_return_if_reached (); - } + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_STORE_GET_CLASS (store); + g_return_val_if_fail (class->noop_finish != NULL, FALSE); + + return class->noop_finish (store, result, error); } diff --git a/camel/camel-store.h b/camel/camel-store.h index 641c6e1..ce53de6 100644 --- a/camel/camel-store.h +++ b/camel/camel-store.h @@ -220,7 +220,7 @@ struct _CamelStoreClass { GHashFunc hash_folder_name; GCompareFunc compare_folder_name; - /* Methods */ + /* Non-Blocking Methods */ gboolean (*can_refresh_folder) (CamelStore *store, CamelFolderInfo *info, GError **error); @@ -229,6 +229,7 @@ struct _CamelStoreClass { void (*free_folder_info) (CamelStore *store, CamelFolderInfo *fi); + /* Synchronous I/O Methods */ CamelFolder * (*get_folder_sync) (CamelStore *store, const gchar *folder_name, guint32 flags, @@ -284,6 +285,124 @@ struct _CamelStoreClass { GCancellable *cancellable, GError **error); + /* Asyncrhonous I/O Methods (all have defaults) */ + void (*get_folder) (CamelStore *store, + const gchar *folder_name, + guint32 flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelFolder * (*get_folder_finish) (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*get_folder_info) (CamelStore *store, + const gchar *top, + guint32 flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelFolderInfo * + (*get_folder_info_finish) + (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*get_inbox_folder) (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelFolder * (*get_inbox_folder_finish) + (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*get_junk_folder) (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelFolder * (*get_junk_folder_finish) + (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*get_trash_folder) (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelFolder * (*get_trash_folder_finish) + (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*create_folder) (CamelStore *store, + const gchar *parent_name, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + CamelFolderInfo * + (*create_folder_finish) (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*delete_folder) (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*delete_folder_finish) (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*rename_folder) (CamelStore *store, + const gchar *old_name, + const gchar *new_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*rename_folder_finish) (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*subscribe_folder) (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*subscribe_folder_finish) + (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*unsubscribe_folder) (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*unsubscribe_folder_finish) + (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*synchronize) (CamelStore *store, + gboolean expunge, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*synchronize_finish) (CamelStore *store, + GAsyncResult *result, + GError **error); + void (*noop) (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*noop_finish) (CamelStore *store, + GAsyncResult *result, + GError **error); + /* Signals */ void (*folder_created) (CamelStore *store, CamelFolderInfo *info); @@ -352,6 +471,16 @@ CamelFolder * camel_store_get_folder_sync (CamelStore *store, guint32 flags, GCancellable *cancellable, GError **error); +void camel_store_get_folder (CamelStore *store, + const gchar *folder_name, + guint32 flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolder * camel_store_get_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error); CamelFolderInfo * camel_store_get_folder_info_sync (CamelStore *store, @@ -359,50 +488,159 @@ CamelFolderInfo * guint32 flags, GCancellable *cancellable, GError **error); +void camel_store_get_folder_info (CamelStore *store, + const gchar *top, + guint32 flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolderInfo * + camel_store_get_folder_info_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); CamelFolder * camel_store_get_inbox_folder_sync (CamelStore *store, GCancellable *cancellable, GError **error); -CamelFolder * camel_store_get_trash_folder_sync - (CamelStore *store, +void camel_store_get_inbox_folder (CamelStore *store, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolder * camel_store_get_inbox_folder_finish + (CamelStore *store, + GAsyncResult *result, GError **error); CamelFolder * camel_store_get_junk_folder_sync (CamelStore *store, GCancellable *cancellable, GError **error); +void camel_store_get_junk_folder (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolder * camel_store_get_junk_folder_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); +CamelFolder * camel_store_get_trash_folder_sync + (CamelStore *store, + GCancellable *cancellable, + GError **error); +void camel_store_get_trash_folder (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolder * camel_store_get_trash_folder_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); CamelFolderInfo * camel_store_create_folder_sync (CamelStore *store, const gchar *parent_name, const gchar *folder_name, GCancellable *cancellable, GError **error); +void camel_store_create_folder (CamelStore *store, + const gchar *parent_name, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolderInfo * + camel_store_create_folder_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); gboolean camel_store_delete_folder_sync (CamelStore *store, const gchar *folder_name, GCancellable *cancellable, GError **error); +void camel_store_delete_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_store_delete_folder_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); gboolean camel_store_rename_folder_sync (CamelStore *store, - const gchar *old_namein, + const gchar *old_name, const gchar *new_name, GCancellable *cancellable, GError **error); +void camel_store_rename_folder (CamelStore *store, + const gchar *old_name, + const gchar *new_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_store_rename_folder_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); gboolean camel_store_subscribe_folder_sync (CamelStore *store, const gchar *folder_name, GCancellable *cancellable, GError **error); +void camel_store_subscribe_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_store_subscribe_folder_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); gboolean camel_store_unsubscribe_folder_sync (CamelStore *store, const gchar *folder_name, GCancellable *cancellable, GError **error); +void camel_store_unsubscribe_folder (CamelStore *store, + const gchar *folder_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_store_unsubscribe_folder_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); gboolean camel_store_synchronize_sync (CamelStore *store, gboolean expunge, GCancellable *cancellable, GError **error); +void camel_store_synchronize (CamelStore *store, + gboolean expunge, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_store_synchronize_finish (CamelStore *store, + GAsyncResult *result, + GError **error); gboolean camel_store_noop_sync (CamelStore *store, GCancellable *cancellable, GError **error); +void camel_store_noop (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_store_noop_finish (CamelStore *store, + GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/camel/camel-transport.c b/camel/camel-transport.c index 24bdc7b..068c2ef 100644 --- a/camel/camel-transport.c +++ b/camel/camel-transport.c @@ -36,13 +36,37 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_TRANSPORT, CamelTransportPrivate)) +typedef struct _AsyncContext AsyncContext; + struct _CamelTransportPrivate { GMutex *send_lock; /* for locking send operations */ }; +struct _AsyncContext { + /* arguments */ + CamelAddress *from; + CamelAddress *recipients; + CamelMimeMessage *message; +}; + G_DEFINE_ABSTRACT_TYPE (CamelTransport, camel_transport, CAMEL_TYPE_SERVICE) static void +async_context_free (AsyncContext *async_context) +{ + if (async_context->from != NULL) + g_object_unref (async_context->from); + + if (async_context->recipients != NULL) + g_object_unref (async_context->recipients); + + if (async_context->message != NULL) + g_object_unref (async_context->message); + + g_slice_free (AsyncContext, async_context); +} + +static void transport_finalize (GObject *object) { CamelTransportPrivate *priv; @@ -56,6 +80,74 @@ transport_finalize (GObject *object) } static void +transport_send_to_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *async_context; + GError *error = NULL; + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + camel_transport_send_to_sync ( + CAMEL_TRANSPORT (object), async_context->message, + async_context->from, async_context->recipients, + cancellable, &error); + + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } +} + +static void +transport_send_to (CamelTransport *transport, + CamelMimeMessage *message, + CamelAddress *from, + CamelAddress *recipients, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->from = g_object_ref (from); + async_context->recipients = g_object_ref (recipients); + async_context->message = g_object_ref (message); + + simple = g_simple_async_result_new ( + G_OBJECT (transport), callback, user_data, transport_send_to); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, transport_send_to_thread, io_priority, cancellable); + + g_object_unref (simple); +} + +static gboolean +transport_send_to_finish (CamelTransport *transport, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (transport), transport_send_to), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void camel_transport_class_init (CamelTransportClass *class) { GObjectClass *object_class; @@ -64,6 +156,9 @@ camel_transport_class_init (CamelTransportClass *class) object_class = G_OBJECT_CLASS (class); object_class->finalize = transport_finalize; + + class->send_to = transport_send_to; + class->send_to_finish = transport_send_to_finish; } static void @@ -75,8 +170,56 @@ camel_transport_init (CamelTransport *transport) } /** + * camel_transport_lock: + * @transport: a #CamelTransport + * @lock: lock type to lock + * + * Locks #transport's #lock. Unlock it with camel_transport_unlock(). + * + * Since: 2.32 + **/ +void +camel_transport_lock (CamelTransport *transport, + CamelTransportLock lock) +{ + g_return_if_fail (CAMEL_IS_TRANSPORT (transport)); + + switch (lock) { + case CAMEL_TRANSPORT_SEND_LOCK: + g_mutex_lock (transport->priv->send_lock); + break; + default: + g_return_if_reached (); + } +} + +/** + * camel_transport_unlock: + * @transport: a #CamelTransport + * @lock: lock type to unlock + * + * Unlocks #transport's #lock, previously locked with camel_transport_lock(). + * + * Since: 2.32 + **/ +void +camel_transport_unlock (CamelTransport *transport, + CamelTransportLock lock) +{ + g_return_if_fail (CAMEL_IS_TRANSPORT (transport)); + + switch (lock) { + case CAMEL_TRANSPORT_SEND_LOCK: + g_mutex_unlock (transport->priv->send_lock); + break; + default: + g_return_if_reached (); + } +} + +/** * camel_transport_send_to_sync: - * @transport: a #CamelTransport object + * @transport: a #CamelTransport * @message: a #CamelMimeMessage to send * @from: a #CamelAddress to send from * @recipients: a #CamelAddress containing all recipients @@ -84,10 +227,12 @@ camel_transport_init (CamelTransport *transport) * @error: return location for a #GError, or %NULL * * Sends the message to the given recipients, regardless of the contents - * of @message. If the message contains a "Bcc" header, the transport + * of @message. If the message contains a "Bcc" header, the transport * is responsible for stripping it. * - * Return %TRUE on success or %FALSE on fail + * Returns: %TRUE on success or %FALSE on error + * + * Since: 2.34 **/ gboolean camel_transport_send_to_sync (CamelTransport *transport, @@ -110,6 +255,12 @@ camel_transport_send_to_sync (CamelTransport *transport, camel_transport_lock (transport, CAMEL_TRANSPORT_SEND_LOCK); + /* Check for cancellation after locking. */ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + camel_transport_unlock (transport, CAMEL_TRANSPORT_SEND_LOCK); + return FALSE; + } + success = class->send_to_sync ( transport, message, from, recipients, cancellable, error); CAMEL_CHECK_GERROR (transport, send_to_sync, success, error); @@ -120,49 +271,74 @@ camel_transport_send_to_sync (CamelTransport *transport, } /** - * camel_transport_lock: + * camel_transport_send_to: * @transport: a #CamelTransport - * @lock: lock type to lock + * @message: a #CamelMimeMessage to send + * @from: a #CamelAddress to send from + * @recipients: a #CamelAddress containing all recipients + * @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 * - * Locks #transport's #lock. Unlock it with camel_transport_unlock(). + * Sends the message asynchronously to the given recipients, regardless of + * the contents of @message. If the message contains a "Bcc" header, the + * transport is responsible for stripping it. * - * Since: 2.32 + * When the operation is finished, @callback will be called. You can then + * call camel_transport_send_to_finish() to get the result of the operation. + * + * Since: 2.34 **/ void -camel_transport_lock (CamelTransport *transport, - CamelTransportLock lock) +camel_transport_send_to (CamelTransport *transport, + CamelMimeMessage *message, + CamelAddress *from, + CamelAddress *recipients, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + CamelTransportClass *class; + g_return_if_fail (CAMEL_IS_TRANSPORT (transport)); + g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); + g_return_if_fail (CAMEL_IS_ADDRESS (from)); + g_return_if_fail (CAMEL_IS_ADDRESS (recipients)); - switch (lock) { - case CAMEL_TRANSPORT_SEND_LOCK: - g_mutex_lock (transport->priv->send_lock); - break; - default: - g_return_if_reached (); - } + class = CAMEL_TRANSPORT_GET_CLASS (transport); + g_return_if_fail (class->send_to != NULL); + + class->send_to ( + transport, message, from, recipients, io_priority, + cancellable, callback, user_data); } /** - * camel_transport_unlock: + * camel_transport_send_to_finish: * @transport: a #CamelTransport - * @lock: lock type to unlock + * @result: a #GAsyncResult + * @error: return locaton for a #GError, or %NULL * - * Unlocks #transport's #lock, previously locked with camel_transport_lock(). + * Finishes the operation started with camel_transport_send_to(). * - * Since: 2.32 + * Returns: %TRUE on success, %FALSE on error + * + * Since: 2.34 **/ -void -camel_transport_unlock (CamelTransport *transport, - CamelTransportLock lock) +gboolean +camel_transport_send_to_finish (CamelTransport *transport, + GAsyncResult *result, + GError **error) { - g_return_if_fail (CAMEL_IS_TRANSPORT (transport)); + CamelTransportClass *class; - switch (lock) { - case CAMEL_TRANSPORT_SEND_LOCK: - g_mutex_unlock (transport->priv->send_lock); - break; - default: - g_return_if_reached (); - } + g_return_val_if_fail (CAMEL_IS_TRANSPORT (transport), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + class = CAMEL_TRANSPORT_GET_CLASS (transport); + g_return_val_if_fail (class->send_to_finish != NULL, FALSE); + + return class->send_to_finish (transport, result, error); } diff --git a/camel/camel-transport.h b/camel/camel-transport.h index 7a53961..ce01ef2 100644 --- a/camel/camel-transport.h +++ b/camel/camel-transport.h @@ -76,26 +76,52 @@ struct _CamelTransport { struct _CamelTransportClass { CamelServiceClass parent_class; + /* Synchronous I/O Methods */ gboolean (*send_to_sync) (CamelTransport *transport, CamelMimeMessage *message, CamelAddress *from, CamelAddress *recipients, GCancellable *cancellable, GError **error); -}; -GType camel_transport_get_type (void); -gboolean camel_transport_send_to_sync (CamelTransport *transport, + /* Asynchronous I/O Methods (all have defaults) */ + void (*send_to) (CamelTransport *transport, CamelMimeMessage *message, CamelAddress *from, CamelAddress *recipients, + gint io_priority, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*send_to_finish) (CamelTransport *transport, + GAsyncResult *result, GError **error); +}; + +GType camel_transport_get_type (void); void camel_transport_lock (CamelTransport *transport, CamelTransportLock lock); void camel_transport_unlock (CamelTransport *transport, CamelTransportLock lock); +gboolean camel_transport_send_to_sync (CamelTransport *transport, + CamelMimeMessage *message, + CamelAddress *from, + CamelAddress *recipients, + GCancellable *cancellable, + GError **error); +void camel_transport_send_to (CamelTransport *transport, + CamelMimeMessage *message, + CamelAddress *from, + CamelAddress *recipients, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean camel_transport_send_to_finish (CamelTransport *transport, + GAsyncResult *result, + GError **error); + G_END_DECLS #endif /* CAMEL_TRANSPORT_H */ diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c index 8585108..17c985c 100644 --- a/camel/camel-vee-folder.c +++ b/camel/camel-vee-folder.c @@ -1210,7 +1210,7 @@ vee_folder_thaw (CamelFolder *folder) static gboolean vee_folder_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -1372,8 +1372,8 @@ static gboolean vee_folder_transfer_messages_to_sync (CamelFolder *folder, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { diff --git a/camel/camel-vtrash-folder.c b/camel/camel-vtrash-folder.c index 63fd5db..31fd387 100644 --- a/camel/camel-vtrash-folder.c +++ b/camel/camel-vtrash-folder.c @@ -70,7 +70,7 @@ transfer_messages (CamelFolder *folder, camel_folder_transfer_messages_to_sync ( md->folder, md->uids, md->dest, - NULL, md->delete, md->cancellable, error); + md->delete, NULL, md->cancellable, error); if (md->cancellable != NULL) g_object_unref (md->cancellable); @@ -86,7 +86,7 @@ transfer_messages (CamelFolder *folder, static gboolean vtrash_folder_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -102,8 +102,8 @@ static gboolean vtrash_folder_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { diff --git a/camel/providers/groupwise/camel-groupwise-folder.c b/camel/providers/groupwise/camel-groupwise-folder.c index 53da6ce..622c57b 100644 --- a/camel/providers/groupwise/camel-groupwise-folder.c +++ b/camel/providers/groupwise/camel-groupwise-folder.c @@ -77,7 +77,7 @@ struct _CamelGroupwiseFolderPrivate { extern gint camel_application_is_exiting; /*prototypes*/ -static gboolean groupwise_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *destination, GPtrArray **transferred_uids, gboolean delete_originals, GCancellable *cancellable, GError **error); +static gboolean groupwise_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *destination, gboolean delete_originals, GPtrArray **transferred_uids, GCancellable *cancellable, GError **error); void convert_to_calendar (EGwItem *item, gchar **str, gint *len); static void convert_to_task (EGwItem *item, gchar **str, gint *len); static void convert_to_note (EGwItem *item, gchar **str, gint *len); @@ -548,7 +548,7 @@ move_to_mailbox (CamelFolder *folder, CAMEL_GW_MESSAGE_JUNK, 0); if (dest) groupwise_transfer_messages_to_sync ( - folder, uids, dest, NULL, TRUE, cancellable, error); + folder, uids, dest, TRUE, NULL, cancellable, error); else g_warning ("No Mailbox folder found"); @@ -577,7 +577,7 @@ move_to_junk (CamelFolder *folder, if (dest) groupwise_transfer_messages_to_sync ( - folder, uids, dest, NULL, TRUE, cancellable, error); + folder, uids, dest, TRUE, NULL, cancellable, error); else { fi = create_junk_folder (parent_store); dest = camel_store_get_folder_sync ( @@ -586,7 +586,7 @@ move_to_junk (CamelFolder *folder, g_warning ("Could not get JunkFolder:Message not moved"); else groupwise_transfer_messages_to_sync ( - folder, uids, dest, NULL, TRUE, cancellable, error); + folder, uids, dest, TRUE, NULL, cancellable, error); } update_junk_list (parent_store, info, ADD_JUNK_ENTRY); } @@ -1030,7 +1030,7 @@ update_update (CamelSession *session, goto end1; } - camel_operation_start ( + camel_operation_push_message ( msg->cancellable, _("Checking for deleted messages %s"), camel_folder_get_name (m->folder)); @@ -1103,12 +1103,12 @@ update_update (CamelSession *session, g_print ("\nNumber of items in the folder: %d \n", g_list_length(items_full_list)); gw_update_all_items (m->folder, items_full_list, NULL, NULL); - camel_operation_end (msg->cancellable); + camel_operation_pop_message (msg->cancellable); return; end1: camel_service_unlock (CAMEL_SERVICE (gw_store), CAMEL_SERVICE_REC_CONNECT_LOCK); - camel_operation_end (msg->cancellable); + camel_operation_pop_message (msg->cancellable); if (items_full_list) { g_list_foreach (items_full_list, (GFunc)g_free, NULL); g_list_free (items_full_list); @@ -1515,7 +1515,7 @@ gw_update_cache (CamelFolder *folder, is_junk = TRUE; } - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Fetching summary information for new messages in %s"), camel_folder_get_name (folder)); @@ -1714,7 +1714,7 @@ gw_update_cache (CamelFolder *folder, g_object_unref (item); } - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_free (container_id); g_string_free (str_to, TRUE); @@ -2060,7 +2060,7 @@ groupwise_folder_item_to_msg ( CamelFolder *folder, msg = camel_mime_message_new (); if (has_mime_822 && body) { temp_stream = camel_stream_mem_new_with_buffer (body, body_len); - if (camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, temp_stream, NULL, error) == -1) { + if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, temp_stream, NULL, error)) { g_object_unref (msg); g_object_unref (temp_stream); msg = NULL; @@ -2398,7 +2398,7 @@ groupwise_folder_constructed (GObject *object) static gboolean groupwise_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -2653,7 +2653,7 @@ groupwise_folder_get_message_sync (CamelFolder *folder, camel_stream_reset (stream, NULL); camel_stream_write_to_stream (cache_stream, stream, cancellable, NULL); camel_stream_reset (stream, NULL); - if (camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, stream, cancellable, error) == -1) { + if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, stream, cancellable, error)) { if (errno == EINTR) { g_object_unref (msg); g_object_unref (cache_stream); @@ -2810,8 +2810,8 @@ static gboolean groupwise_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *destination, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { diff --git a/camel/providers/groupwise/camel-groupwise-journal.c b/camel/providers/groupwise/camel-groupwise-journal.c index 0927106..81fa47c 100644 --- a/camel/providers/groupwise/camel-groupwise-journal.c +++ b/camel/providers/groupwise/camel-groupwise-journal.c @@ -175,7 +175,7 @@ groupwise_entry_play_append (CamelOfflineJournal *journal, } message = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error) == -1) { + if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error)) { g_object_unref (message); g_object_unref (stream); goto done; @@ -229,7 +229,7 @@ groupwise_entry_play_transfer (CamelOfflineJournal *journal, g_ptr_array_add (uids, entry->original_uid); if (camel_folder_transfer_messages_to_sync ( - src, uids, folder, &xuids, FALSE, cancellable, error)) { + src, uids, folder, FALSE, &xuids, cancellable, error)) { real = (CamelGroupwiseMessageInfo *) camel_folder_summary_uid (folder->summary, xuids->pdata[0]); /* transfer all the system flags, user flags/tags, etc */ diff --git a/camel/providers/groupwise/camel-groupwise-store.c b/camel/providers/groupwise/camel-groupwise-store.c index cdc8cd9..0a8d5ff 100644 --- a/camel/providers/groupwise/camel-groupwise-store.c +++ b/camel/providers/groupwise/camel-groupwise-store.c @@ -667,7 +667,7 @@ groupwise_store_get_folder_sync (CamelStore *store, return NULL; } - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Fetching summary information for new messages in %s"), camel_folder_get_name (folder)); @@ -712,7 +712,7 @@ groupwise_store_get_folder_sync (CamelStore *store, e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); } if (done && all_ok) { if (summary->time_string) @@ -798,7 +798,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store, return FALSE; } - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Fetching summary information for new messages in %s"), camel_folder_get_name (folder)); @@ -815,7 +815,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store, error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_INVALID, _("Authentication failed")); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_free (container_id); return FALSE; } @@ -849,7 +849,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store, e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); } if (done) { diff --git a/camel/providers/groupwise/camel-groupwise-transport.c b/camel/providers/groupwise/camel-groupwise-transport.c index 12caf78..3b5336b 100644 --- a/camel/providers/groupwise/camel-groupwise-transport.c +++ b/camel/providers/groupwise/camel-groupwise-transport.c @@ -94,7 +94,7 @@ groupwise_send_to_sync (CamelTransport *transport, CAMEL_URL_HIDE_PARAMS | CAMEL_URL_HIDE_AUTH) ); - camel_operation_start (cancellable, _("Sending Message") ); + camel_operation_push_message (cancellable, _("Sending Message") ); /*camel groupwise store and cnc*/ store = camel_session_get_store (service->session, url, NULL); @@ -113,7 +113,7 @@ groupwise_send_to_sync (CamelTransport *transport, cnc = cnc_lookup (priv); if (!cnc) { g_warning ("||| Eh!!! Failure |||\n"); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_set_error ( error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE, @@ -140,7 +140,7 @@ groupwise_send_to_sync (CamelTransport *transport, status = e_gw_connection_send_item (cnc, item, &sent_item_list); if (status != E_GW_CONNECTION_STATUS_OK) { g_warning (" Error Sending mail"); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); e_gw_item_set_link_info (item, NULL); g_object_unref (item); if (temp_item) @@ -169,7 +169,7 @@ groupwise_send_to_sync (CamelTransport *transport, g_object_unref (temp_item); g_object_unref (item); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return TRUE; } diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 0f073a3..6517e80 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -89,23 +89,27 @@ static CamelMimeMessage *imap_get_message_sync (CamelFolder *folder, const gchar static gboolean imap_synchronize_message_sync (CamelFolder *folder, const gchar *uid, GCancellable *cancellable, GError **error); static gboolean imap_append_online (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, gchar **appended_uid, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error); static gboolean imap_append_offline (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, gchar **appended_uid, + CamelMessageInfo *info, gchar **appended_uid, GError **error); -static gboolean imap_transfer_online (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, - GCancellable *cancellable, - GError **error); -static gboolean imap_transfer_offline (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, - GCancellable *cancellable, - GError **error); +static gboolean imap_transfer_online (CamelFolder *source, + GPtrArray *uids, + CamelFolder *dest, + gboolean delete_originals, + GPtrArray **transferred_uids, + GCancellable *cancellable, + GError **error); +static gboolean imap_transfer_offline (CamelFolder *source, + GPtrArray *uids, + CamelFolder *dest, + gboolean delete_originals, + GPtrArray **transferred_uids, + GCancellable *cancellable, + GError **error); /* searching */ static GPtrArray *imap_search_by_expression (CamelFolder *folder, const gchar *expression, GError **error); @@ -124,11 +128,14 @@ static CamelImapMessageInfo * imap_folder_summary_uid_or_error ( const gchar * uid, GError **error); -static gboolean -imap_transfer_messages (CamelFolder *source, GPtrArray *uids, - CamelFolder *dest, GPtrArray **transferred_uids, - gboolean delete_originals, gboolean can_call_sync, - GCancellable *cancellable, GError **error); +static gboolean imap_transfer_messages (CamelFolder *source, + GPtrArray *uids, + CamelFolder *dest, + gboolean delete_originals, + GPtrArray **transferred_uids, + gboolean can_call_sync, + GCancellable *cancellable, + GError **error); #ifdef G_OS_WIN32 /* The strtok() in Microsoft's C library is MT-safe (but still uses @@ -979,13 +986,13 @@ imap_rescan (CamelFolder *folder, } /* Check UIDs and flags of all messages we already know of. */ - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Scanning for changed messages in %s"), camel_folder_get_name (folder)); uid = camel_folder_summary_uid_from_index (folder->summary, summary_len - 1); if (!uid) { - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return TRUE; } @@ -994,7 +1001,7 @@ imap_rescan (CamelFolder *folder, "UID FETCH 1:%s (FLAGS)", uid); g_free (uid); if (!ok) { - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return FALSE; } @@ -1029,13 +1036,13 @@ imap_rescan (CamelFolder *folder, } if (summary_got == 0 && summary_len == 0) { - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK); g_free (new); return TRUE; } - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); if (type == CAMEL_IMAP_RESPONSE_ERROR || camel_application_is_exiting) { for (i = 0; i < summary_len && new[i].uid; i++) { @@ -1486,8 +1493,8 @@ move_messages (CamelFolder *src_folder, if (src_folder != des_folder) { /* do 'copy' to not be bothered with CAMEL_MESSAGE_DELETED again */ if (!imap_transfer_messages ( - src_folder, uids, des_folder, NULL, - FALSE, FALSE, cancellable, error)) + src_folder, uids, des_folder, FALSE, + NULL, FALSE, cancellable, error)) return; } @@ -2175,7 +2182,7 @@ get_temp_uid (void) static gboolean imap_append_offline (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GError **error) { @@ -2231,7 +2238,7 @@ imap_folder_uid_in_ignore_recent (CamelImapFolder *imap_folder, const gchar *uid static CamelImapResponse * do_append (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **uid, GCancellable *cancellable, GError **error) @@ -2341,7 +2348,7 @@ retry: static gboolean imap_append_online (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -2397,7 +2404,7 @@ imap_append_online (CamelFolder *folder, gboolean camel_imap_append_resyncing (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -2439,8 +2446,8 @@ static gboolean imap_transfer_offline (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { @@ -2758,8 +2765,8 @@ static gboolean imap_transfer_messages (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, gboolean can_call_sync, GCancellable *cancellable, GError **error) @@ -2774,8 +2781,8 @@ imap_transfer_messages (CamelFolder *source, if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) return imap_transfer_offline ( - source, uids, dest, transferred_uids, - delete_originals, cancellable, error); + source, uids, dest, delete_originals, + transferred_uids, cancellable, error); /* Sync message flags if needed. */ if (can_call_sync && !imap_synchronize_sync ( @@ -2806,22 +2813,22 @@ static gboolean imap_transfer_online (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { return imap_transfer_messages ( - source, uids, dest, transferred_uids, - delete_originals, TRUE, cancellable, error); + source, uids, dest, delete_originals, + transferred_uids, TRUE, cancellable, error); } gboolean camel_imap_transfer_resyncing (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { @@ -3097,7 +3104,7 @@ get_content (CamelImapFolder *imap_folder, if (camel_content_type_is (ci->type, "multipart", "signed")) { CamelMultipartSigned *body_mp; gchar *spec; - gint ret; + gboolean success; /* Note: because we get the content parts uninterpreted anyway, we could potentially just use the normalmultipart code, except that multipart/signed wont let you yet! */ @@ -3116,10 +3123,10 @@ get_content (CamelImapFolder *imap_folder, stream = camel_imap_folder_fetch_data (imap_folder, uid, spec, FALSE, cancellable, error); if (stream) { - ret = camel_data_wrapper_construct_from_stream_sync ( + success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (body_mp), stream, cancellable, error); g_object_unref (CAMEL_OBJECT (stream)); - if (ret == -1) { + if (!success) { g_object_unref ( body_mp); return NULL; } @@ -3154,13 +3161,13 @@ get_content (CamelImapFolder *imap_folder, sprintf (child_spec + speclen, "%d.MIME", num++); stream = camel_imap_folder_fetch_data (imap_folder, uid, child_spec, FALSE, cancellable, error); if (stream) { - gint ret; + gboolean success; part = camel_mime_part_new (); - ret = camel_data_wrapper_construct_from_stream_sync ( + success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (part), stream, cancellable, error); g_object_unref (CAMEL_OBJECT (stream)); - if (ret == -1) { + if (!success) { g_object_unref (CAMEL_OBJECT (part)); g_object_unref (CAMEL_OBJECT (body_mp)); g_free (child_spec); @@ -3244,7 +3251,7 @@ get_message (CamelImapFolder *imap_folder, CamelMimeMessage *msg; CamelStream *stream; gchar *section_text, *part_spec; - gint ret; + gboolean success; folder = CAMEL_FOLDER (imap_folder); parent_store = camel_folder_get_parent_store (folder); @@ -3262,10 +3269,10 @@ get_message (CamelImapFolder *imap_folder, return NULL; msg = camel_mime_message_new (); - ret = camel_data_wrapper_construct_from_stream_sync ( + success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (msg), stream, cancellable, error); g_object_unref (CAMEL_OBJECT (stream)); - if (ret == -1) { + if (!success) { g_object_unref (CAMEL_OBJECT (msg)); return NULL; } @@ -3302,7 +3309,7 @@ get_message_simple (CamelImapFolder *imap_folder, GError **error) { CamelMimeMessage *msg; - gint ret; + gboolean success; if (!stream) { stream = camel_imap_folder_fetch_data (imap_folder, uid, "", @@ -3312,10 +3319,10 @@ get_message_simple (CamelImapFolder *imap_folder, } msg = camel_mime_message_new (); - ret = camel_data_wrapper_construct_from_stream_sync ( + success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (msg), stream, cancellable, error); g_object_unref (CAMEL_OBJECT (stream)); - if (ret == -1) { + if (!success) { g_prefix_error (error, _("Unable to retrieve message: ")); g_object_unref (CAMEL_OBJECT (msg)); return NULL; @@ -3730,8 +3737,8 @@ add_message_from_data (CamelFolder *folder, g_ptr_array_set_size (messages, seq - first + 1); msg = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream_sync ( - CAMEL_DATA_WRAPPER (msg), stream, cancellable, NULL) == -1) { + if (!camel_data_wrapper_construct_from_stream_sync ( + CAMEL_DATA_WRAPPER (msg), stream, cancellable, NULL)) { g_object_unref (CAMEL_OBJECT (msg)); return; } @@ -3907,7 +3914,7 @@ imap_update_summary (CamelFolder *folder, return FALSE; } - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Fetching summary information for new messages in %s"), camel_folder_get_name (folder)); @@ -3954,7 +3961,7 @@ imap_update_summary (CamelFolder *folder, g_ptr_array_add (fetch_data, data); } - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); if (type == CAMEL_IMAP_RESPONSE_ERROR || camel_application_is_exiting) { if (type != CAMEL_IMAP_RESPONSE_ERROR && type != CAMEL_IMAP_RESPONSE_TAGGED) @@ -3989,7 +3996,7 @@ imap_update_summary (CamelFolder *folder, qsort (needheaders->pdata, needheaders->len, sizeof (gpointer), uid_compar); - camel_operation_start ( + camel_operation_push_message ( cancellable, _("Fetching summary information for new messages in %s"), camel_folder_get_name (folder)); @@ -4000,7 +4007,7 @@ imap_update_summary (CamelFolder *folder, "UID FETCH %s BODYSTRUCTURE BODY.PEEK[%s]", uidset, header_spec->str)) { g_ptr_array_free (needheaders, TRUE); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_free (uidset); g_string_free (header_spec, TRUE); goto lose; @@ -4028,7 +4035,7 @@ imap_update_summary (CamelFolder *folder, if (type == CAMEL_IMAP_RESPONSE_ERROR || camel_application_is_exiting) { g_ptr_array_free (needheaders, TRUE); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); if (type != CAMEL_IMAP_RESPONSE_ERROR && type != CAMEL_IMAP_RESPONSE_TAGGED) camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK); @@ -4038,7 +4045,7 @@ imap_update_summary (CamelFolder *folder, } g_string_free (header_spec, TRUE); g_ptr_array_free (needheaders, TRUE); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); } /* Now finish up summary entries (fix UIDs, set flags and size) */ diff --git a/camel/providers/imap/camel-imap-folder.h b/camel/providers/imap/camel-imap-folder.h index e24bd96..7ea9711 100644 --- a/camel/providers/imap/camel-imap-folder.h +++ b/camel/providers/imap/camel-imap-folder.h @@ -102,15 +102,15 @@ CamelStream * camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, GError **error); gboolean camel_imap_append_resyncing (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error); gboolean camel_imap_transfer_resyncing (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error); gboolean camel_imap_expunge_uids_resyncing diff --git a/camel/providers/imap/camel-imap-journal.c b/camel/providers/imap/camel-imap-journal.c index cd6f74f..d94b522 100644 --- a/camel/providers/imap/camel-imap-journal.c +++ b/camel/providers/imap/camel-imap-journal.c @@ -370,7 +370,7 @@ imap_entry_play (CamelOfflineJournal *journal, if (!camel_imap_transfer_resyncing ( journal->folder, imap_entry->uids, destination, - &ret_uids, imap_entry->move, cancellable, error)) + imap_entry->move, &ret_uids, cancellable, error)) return -1; if (ret_uids) { diff --git a/camel/providers/imapx/camel-imapx-folder.c b/camel/providers/imapx/camel-imapx-folder.c index bf5595a..02457cb 100644 --- a/camel/providers/imapx/camel-imapx-folder.c +++ b/camel/providers/imapx/camel-imapx-folder.c @@ -278,7 +278,7 @@ imapx_search_by_expression (CamelFolder *folder, const gchar *expression, GError static gboolean imapx_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -399,8 +399,8 @@ imapx_get_message_sync (CamelFolder *folder, msg = camel_mime_message_new (); g_mutex_lock (ifolder->stream_lock); - if (camel_data_wrapper_construct_from_stream_sync ( - (CamelDataWrapper *)msg, stream, cancellable, error) == -1) { + if (!camel_data_wrapper_construct_from_stream_sync ( + (CamelDataWrapper *)msg, stream, cancellable, error)) { g_object_unref (msg); msg = NULL; } @@ -521,8 +521,8 @@ static gboolean imapx_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c index f2bf917..2776d02 100644 --- a/camel/providers/imapx/camel-imapx-server.c +++ b/camel/providers/imapx/camel-imapx-server.c @@ -3847,7 +3847,7 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is, /* If we have any new messages, download their headers, but only a few (100?) at a time */ if (fetch_new) { - camel_operation_start ( + camel_operation_push_message ( job->cancellable, _("Fetching summary information for new messages in %s"), camel_folder_get_name (job->folder)); @@ -3889,7 +3889,7 @@ imapx_job_scan_changes_start (CamelIMAPXServer *is, { CamelIMAPXCommand *ic; - camel_operation_start ( + camel_operation_push_message ( job->cancellable, _("Scanning for changed messages in %s"), camel_folder_get_name (job->folder)); @@ -3974,7 +3974,7 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is, } else uid = g_strdup ("1"); - camel_operation_start ( + camel_operation_push_message ( job->cancellable, _("Fetching summary information for new messages in %s"), camel_folder_get_name (folder)); diff --git a/camel/providers/local/camel-maildir-folder.c b/camel/providers/local/camel-maildir-folder.c index 57f322f..764b1ee 100644 --- a/camel/providers/local/camel-maildir-folder.c +++ b/camel/providers/local/camel-maildir-folder.c @@ -114,7 +114,7 @@ maildir_folder_get_filename (CamelFolder *folder, static gboolean maildir_folder_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -253,9 +253,9 @@ maildir_folder_get_message_sync (CamelFolder *folder, } message = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream_sync ( + if (!camel_data_wrapper_construct_from_stream_sync ( (CamelDataWrapper *)message, - message_stream, cancellable, error) == -1) { + message_stream, cancellable, error)) { g_prefix_error ( error, _("Cannot get message %s from folder %s: "), uid, lf->folder_path); @@ -281,8 +281,8 @@ static gboolean maildir_folder_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, - GPtrArray **transferred_uids, gboolean delete_originals, + GPtrArray **transferred_uids, GCancellable *cancellable, GError **error) { @@ -293,7 +293,8 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source, CamelLocalFolder *lf = (CamelLocalFolder *) source; CamelLocalFolder *df = (CamelLocalFolder *) dest; - camel_operation_start (cancellable, _("Moving messages")); + camel_operation_push_message ( + cancellable, _("Moving messages")); camel_folder_freeze (dest); camel_folder_freeze (source); @@ -346,7 +347,7 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source, camel_folder_thaw (source); camel_folder_thaw (dest); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); } else fallback = TRUE; @@ -356,8 +357,8 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source, /* Chain up to parent's transfer_messages_to() method. */ folder_class = CAMEL_FOLDER_CLASS (camel_maildir_folder_parent_class); return folder_class->transfer_messages_to_sync ( - source, uids, dest, transferred_uids, - delete_originals, cancellable, error); + source, uids, dest, delete_originals, + transferred_uids, cancellable, error); } return TRUE; diff --git a/camel/providers/local/camel-maildir-summary.c b/camel/providers/local/camel-maildir-summary.c index dca9bb8..7ad3e24 100644 --- a/camel/providers/local/camel-maildir-summary.c +++ b/camel/providers/local/camel-maildir-summary.c @@ -552,7 +552,8 @@ maildir_summary_check (CamelLocalSummary *cls, d(printf("checking summary ...\n")); - camel_operation_start (cancellable, _("Checking folder consistency")); + camel_operation_push_message ( + cancellable, _("Checking folder consistency")); /* scan the directory, check for mail files not in the index, or index entries that no longer exist */ @@ -565,7 +566,7 @@ maildir_summary_check (CamelLocalSummary *cls, cls->folder_path, g_strerror (errno)); g_free (cur); g_free (new); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_mutex_unlock (((CamelMaildirSummary *) cls)->priv->summary_lock); return -1; } @@ -642,9 +643,10 @@ maildir_summary_check (CamelLocalSummary *cls, g_hash_table_foreach (left, (GHFunc)remove_summary, &rd); g_hash_table_destroy (left); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); - camel_operation_start (cancellable, _("Checking for new messages")); + camel_operation_push_message ( + cancellable, _("Checking for new messages")); /* now, scan new for new messages, and copy them to cur, and so forth */ dir = opendir (new); @@ -704,7 +706,8 @@ maildir_summary_check (CamelLocalSummary *cls, g_free (src); g_free (dest); } - camel_operation_end (cancellable); + + camel_operation_pop_message (cancellable); closedir (dir); } @@ -736,7 +739,7 @@ maildir_summary_sync (CamelLocalSummary *cls, if (camel_local_summary_check (cls, changes, cancellable, error) == -1) return -1; - camel_operation_start (cancellable, _("Storing folder")); + camel_operation_push_message (cancellable, _("Storing folder")); camel_folder_summary_prepare_fetch_all ((CamelFolderSummary *)cls, error); count = camel_folder_summary_count ((CamelFolderSummary *)cls); @@ -792,7 +795,7 @@ maildir_summary_sync (CamelLocalSummary *cls, camel_message_info_free (info); } - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); /* Chain up to parent's sync() method. */ local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (camel_maildir_summary_parent_class); diff --git a/camel/providers/local/camel-mbox-folder.c b/camel/providers/local/camel-mbox-folder.c index 32abf33..8174904 100644 --- a/camel/providers/local/camel-mbox-folder.c +++ b/camel/providers/local/camel-mbox-folder.c @@ -138,7 +138,7 @@ fail: static gboolean mbox_folder_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -380,8 +380,8 @@ retry: } message = camel_mime_message_new (); - if (camel_mime_part_construct_from_parser_sync ( - (CamelMimePart *)message, parser, cancellable, error) == -1) { + if (!camel_mime_part_construct_from_parser_sync ( + (CamelMimePart *)message, parser, cancellable, error)) { g_prefix_error ( error, _("Cannot get message %s from folder %s: "), uid, lf->folder_path); diff --git a/camel/providers/local/camel-mbox-summary.c b/camel/providers/local/camel-mbox-summary.c index 86d0562..5ce1476 100644 --- a/camel/providers/local/camel-mbox-summary.c +++ b/camel/providers/local/camel-mbox-summary.c @@ -469,7 +469,7 @@ summary_update (CamelLocalSummary *cls, cls->index_force = FALSE; - camel_operation_start (cancellable, _("Storing folder")); + camel_operation_push_message (cancellable, _("Storing folder")); fd = g_open (cls->folder_path, O_LARGEFILE | O_RDONLY | O_BINARY, 0); if (fd == -1) { @@ -479,7 +479,7 @@ summary_update (CamelLocalSummary *cls, g_io_error_from_errno (errno), _("Could not open folder: %s: %s"), cls->folder_path, g_strerror (errno)); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return -1; } @@ -598,7 +598,7 @@ summary_update (CamelLocalSummary *cls, } } - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return ok; } @@ -691,7 +691,7 @@ mbox_summary_sync_full (CamelMboxSummary *mbs, d(printf("performing full summary/sync\n")); - camel_operation_start (cancellable, _("Storing folder")); + camel_operation_push_message (cancellable, _("Storing folder")); fd = g_open (cls->folder_path, O_LARGEFILE | O_RDONLY | O_BINARY, 0); if (fd == -1) { @@ -700,7 +700,7 @@ mbox_summary_sync_full (CamelMboxSummary *mbs, g_io_error_from_errno (errno), _("Could not open file: %s: %s"), cls->folder_path, g_strerror (errno)); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return -1; } @@ -763,7 +763,7 @@ mbox_summary_sync_full (CamelMboxSummary *mbs, } tmpname = NULL; - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return 0; error: @@ -776,7 +776,7 @@ mbox_summary_sync_full (CamelMboxSummary *mbs, if (tmpname) g_unlink (tmpname); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return -1; } @@ -827,7 +827,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs, d(printf("Performing quick summary sync\n")); - camel_operation_start (cancellable, _("Storing folder")); + camel_operation_push_message (cancellable, _("Storing folder")); fd = g_open (cls->folder_path, O_LARGEFILE|O_RDWR|O_BINARY, 0); if (fd == -1) { @@ -837,7 +837,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs, _("Could not open file: %s: %s"), cls->folder_path, g_strerror (errno)); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return -1; } @@ -960,7 +960,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs, g_ptr_array_free (summary, TRUE); g_object_unref (mp); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); camel_folder_summary_unlock (s, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK); return 0; @@ -974,7 +974,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs, if (info) camel_message_info_free ((CamelMessageInfo *)info); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); camel_folder_summary_unlock (s, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK); return -1; diff --git a/camel/providers/local/camel-mh-folder.c b/camel/providers/local/camel-mh-folder.c index a005a13..59147ef 100644 --- a/camel/providers/local/camel-mh-folder.c +++ b/camel/providers/local/camel-mh-folder.c @@ -55,7 +55,7 @@ mh_folder_get_filename (CamelFolder *folder, static gboolean mh_folder_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, - const CamelMessageInfo *info, + CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) @@ -171,9 +171,9 @@ mh_folder_get_message_sync (CamelFolder *folder, } message = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream_sync ( + if (!camel_data_wrapper_construct_from_stream_sync ( (CamelDataWrapper *)message, - message_stream, cancellable, error) == -1) { + message_stream, cancellable, error)) { g_prefix_error ( error, _("Cannot get message %s from folder %s: "), name, lf->folder_path); diff --git a/camel/providers/local/camel-spool-summary.c b/camel/providers/local/camel-spool-summary.c index 30fc168..3dbf398 100644 --- a/camel/providers/local/camel-spool-summary.c +++ b/camel/providers/local/camel-spool-summary.c @@ -128,7 +128,7 @@ spool_summary_sync_full (CamelMboxSummary *cls, d(printf("performing full summary/sync\n")); - camel_operation_start (cancellable, _("Storing folder")); + camel_operation_push_message (cancellable, _("Storing folder")); fd = open (((CamelLocalSummary *)cls)->folder_path, O_RDWR|O_LARGEFILE); if (fd == -1) { @@ -138,7 +138,7 @@ spool_summary_sync_full (CamelMboxSummary *cls, _("Could not open file: %s: %s"), ((CamelLocalSummary *)cls)->folder_path, g_strerror (errno)); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return -1; } @@ -286,7 +286,7 @@ spool_summary_sync_full (CamelMboxSummary *cls, if (tmpname[0] != '\0') unlink (tmpname); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return 0; error: @@ -299,7 +299,7 @@ spool_summary_sync_full (CamelMboxSummary *cls, if (tmpname[0] != '\0') unlink (tmpname); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return -1; } diff --git a/camel/providers/nntp/camel-nntp-folder.c b/camel/providers/nntp/camel-nntp-folder.c index 450b903..5c0e1b3 100644 --- a/camel/providers/nntp/camel-nntp-folder.c +++ b/camel/providers/nntp/camel-nntp-folder.c @@ -414,7 +414,7 @@ nntp_folder_get_message_sync (CamelFolder *folder, } message = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error) == -1) { + if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error)) { g_prefix_error (error, _("Cannot get message %s: "), uid); g_object_unref (message); message = NULL; diff --git a/camel/providers/nntp/camel-nntp-summary.c b/camel/providers/nntp/camel-nntp-summary.c index 1076171..68129a7 100644 --- a/camel/providers/nntp/camel-nntp-summary.c +++ b/camel/providers/nntp/camel-nntp-summary.c @@ -241,7 +241,7 @@ add_range_xover (CamelNNTPSummary *cns, s = (CamelFolderSummary *)cns; summary_table = camel_folder_summary_get_hashtable (s); - camel_operation_start ( + camel_operation_push_message ( cancellable, _("%s: Scanning new messages"), ((CamelService *)store)->url->host); @@ -250,7 +250,7 @@ add_range_xover (CamelNNTPSummary *cns, ret = camel_nntp_raw_command_auth (store, cancellable, error, &line, "xover %r", low, high); if (ret != 224) { - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); if (ret != -1) g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, @@ -321,7 +321,7 @@ add_range_xover (CamelNNTPSummary *cns, camel_header_raw_clear (&headers); } - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); camel_folder_summary_free_hashtable (summary_table); @@ -352,7 +352,7 @@ add_range_head (CamelNNTPSummary *cns, mp = camel_mime_parser_new (); - camel_operation_start ( + camel_operation_push_message ( cancellable, _("%s: Scanning new messages"), ((CamelService *)store)->url->host); @@ -426,7 +426,7 @@ ioerror: } g_object_unref (mp); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); camel_folder_summary_free_hashtable (summary_table); diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c index 390fd77..fce90e9 100644 --- a/camel/providers/pop3/camel-pop3-folder.c +++ b/camel/providers/pop3/camel-pop3-folder.c @@ -338,7 +338,7 @@ pop3_folder_get_message_sync (CamelFolder *folder, /* Sigh, most of the crap in this function is so that the cancel button returns the proper exception code. Sigh. */ - camel_operation_start_transient ( + camel_operation_push_message ( cancellable, _("Retrieving POP message %d"), fi->id); /* If we have an oustanding retrieve message running, wait for that to complete @@ -450,8 +450,8 @@ pop3_folder_get_message_sync (CamelFolder *folder, } message = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream_sync ( - CAMEL_DATA_WRAPPER (message), stream, cancellable, error) == -1) { + if (!camel_data_wrapper_construct_from_stream_sync ( + CAMEL_DATA_WRAPPER (message), stream, cancellable, error)) { g_prefix_error (error, _("Cannot get message %s: "), uid); g_object_unref (message); message = NULL; @@ -459,7 +459,7 @@ pop3_folder_get_message_sync (CamelFolder *folder, done: g_object_unref (stream); fail: - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return message; } @@ -479,7 +479,8 @@ pop3_folder_refresh_info_sync (CamelFolder *folder, parent_store = camel_folder_get_parent_store (folder); pop3_store = CAMEL_POP3_STORE (parent_store); - camel_operation_start (cancellable, _("Retrieving POP summary")); + camel_operation_push_message ( + cancellable, _("Retrieving POP summary")); pop3_folder->uids = g_ptr_array_new (); pop3_folder->uids_uid = g_hash_table_new (g_str_hash, g_str_equal); @@ -528,7 +529,7 @@ pop3_folder_refresh_info_sync (CamelFolder *folder, /* dont need this anymore */ g_hash_table_destroy (pop3_folder->uids_id); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return success; } @@ -553,17 +554,22 @@ pop3_folder_synchronize_sync (CamelFolder *folder, if (pop3_store->delete_after && !expunge) { d(printf("%s(%d): pop3_store->delete_after = [%d], expunge=[%d]\n", __FILE__, __LINE__, pop3_store->delete_after, expunge)); - camel_operation_start (cancellable, _("Expunging old messages")); + camel_operation_push_message ( + cancellable, _("Expunging old messages")); + camel_pop3_delete_old ( folder, pop3_store->delete_after, cancellable, error); + + camel_operation_pop_message (cancellable); } if (!expunge) { return TRUE; } - camel_operation_start (cancellable, _("Expunging deleted messages")); + camel_operation_push_message ( + cancellable, _("Expunging deleted messages")); for (i = 0; i < pop3_folder->uids->len; i++) { fi = pop3_folder->uids->pdata[i]; @@ -602,7 +608,7 @@ pop3_folder_synchronize_sync (CamelFolder *folder, cancellable, (i+1) * 100 / pop3_folder->uids->len); } - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); camel_pop3_store_expunge (pop3_store, error); @@ -681,8 +687,8 @@ pop3_get_message_time_from_cache (CamelFolder *folder, const gchar *uid, time_t CamelMimeMessage *message; message = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream_sync ( - (CamelDataWrapper *)message, stream, NULL, NULL) == -1) { + if (!camel_data_wrapper_construct_from_stream_sync ( + (CamelDataWrapper *)message, stream, NULL, NULL)) { g_warning (_("Cannot get message %s: %s"), uid, g_strerror (errno)); g_object_unref (message); message = NULL; @@ -782,8 +788,6 @@ camel_pop3_delete_old (CamelFolder *folder, cancellable, (i+1) * 100 / pop3_folder->uids->len); } - camel_operation_end (cancellable); - camel_pop3_store_expunge (pop3_store, error); return 0; diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c index 9f17160..2b17ec0 100644 --- a/camel/providers/smtp/camel-smtp-transport.c +++ b/camel/providers/smtp/camel-smtp-transport.c @@ -614,7 +614,7 @@ smtp_send_to_sync (CamelTransport *transport, return FALSE; } - camel_operation_start (cancellable, _("Sending message")); + camel_operation_push_message (cancellable, _("Sending message")); /* find out if the message has 8bit mime parts */ has_8bit_parts = camel_mime_message_has_8bit_parts (message); @@ -623,7 +623,7 @@ smtp_send_to_sync (CamelTransport *transport, you'll be sending an 8bit mime message at "MAIL FROM:" time. */ if (!smtp_mail ( smtp_transport, addr, has_8bit_parts, cancellable, error)) { - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return FALSE; } @@ -632,7 +632,7 @@ smtp_send_to_sync (CamelTransport *transport, g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot send message: no recipients defined.")); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return FALSE; } @@ -645,28 +645,28 @@ smtp_send_to_sync (CamelTransport *transport, error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot send message: " "one or more invalid recipients")); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return FALSE; } enc = camel_internet_address_encode_address (NULL, NULL, addr); if (!smtp_rcpt (smtp_transport, enc, cancellable, error)) { g_free (enc); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return FALSE; } g_free (enc); } if (!smtp_data (smtp_transport, message, cancellable, error)) { - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return FALSE; } /* reset the service for our next transfer session */ smtp_rset (smtp_transport, cancellable, NULL); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return TRUE; } @@ -1011,7 +1011,7 @@ smtp_helo (CamelSmtpTransport *transport, transport->authtypes = NULL; } - camel_operation_start_transient (cancellable, _("SMTP Greeting")); + camel_operation_push_message (cancellable, _("SMTP Greeting")); addr = transport->localaddr; addrlen = transport->localaddrlen; @@ -1039,7 +1039,7 @@ smtp_helo (CamelSmtpTransport *transport, transport->ostream, cmdbuf, cancellable, error) == -1) { g_free (cmdbuf); g_prefix_error (error, _("HELO command failed: ")); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); camel_service_disconnect_sync ( (CamelService *) transport, FALSE, NULL); @@ -1057,14 +1057,14 @@ smtp_helo (CamelSmtpTransport *transport, if (respbuf == NULL) { g_prefix_error (error, _("HELO command failed: ")); transport->connected = FALSE; - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return FALSE; } if (strncmp (respbuf, "250", 3)) { smtp_set_error ( transport, respbuf, cancellable, error); g_prefix_error (error, _("HELO command failed: ")); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_free (respbuf); return FALSE; } @@ -1113,7 +1113,7 @@ smtp_helo (CamelSmtpTransport *transport, } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */ g_free (respbuf); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); return TRUE; } @@ -1131,11 +1131,11 @@ smtp_auth (CamelSmtpTransport *transport, service = CAMEL_SERVICE (transport); - camel_operation_start_transient (cancellable, _("SMTP Authentication")); + camel_operation_push_message (cancellable, _("SMTP Authentication")); sasl = camel_sasl_new ("smtp", mech, service); if (!sasl) { - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Error creating SASL authentication object.")); @@ -1242,7 +1242,7 @@ smtp_auth (CamelSmtpTransport *transport, } g_object_unref (sasl); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_free (respbuf); @@ -1258,7 +1258,7 @@ smtp_auth (CamelSmtpTransport *transport, lose: g_object_unref (sasl); - camel_operation_end (cancellable); + camel_operation_pop_message (cancellable); g_free (respbuf); diff --git a/docs/reference/camel/camel-docs.sgml b/docs/reference/camel/camel-docs.sgml index eb472fe..d20d7a0 100644 --- a/docs/reference/camel/camel-docs.sgml +++ b/docs/reference/camel/camel-docs.sgml @@ -207,6 +207,10 @@ Index of deprecated symbols + + Index of new symbols in 2.34 + + Index of new symbols in 2.32 diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt index 0d18659..c80d562 100644 --- a/docs/reference/camel/camel-sections.txt +++ b/docs/reference/camel/camel-sections.txt @@ -139,14 +139,26 @@ camel_cipher_validity_encrypt_t camel_cipher_validity_mode_t camel_cipher_context_new camel_cipher_context_get_session -camel_cipher_id_to_hash -camel_cipher_hash_to_id -camel_cipher_sign_sync -camel_cipher_verify_sync -camel_cipher_encrypt_sync -camel_cipher_decrypt_sync -camel_cipher_import_keys_sync -camel_cipher_export_keys_sync +camel_cipher_context_id_to_hash +camel_cipher_context_hash_to_id +camel_cipher_context_sign_sync +camel_cipher_context_sign +camel_cipher_context_sign_finish +camel_cipher_context_verify_sync +camel_cipher_context_verify +camel_cipher_context_verify_finish +camel_cipher_context_encrypt_sync +camel_cipher_context_encrypt +camel_cipher_context_encrypt_finish +camel_cipher_context_decrypt_sync +camel_cipher_context_decrypt +camel_cipher_context_decrypt_finish +camel_cipher_context_import_keys_sync +camel_cipher_context_import_keys +camel_cipher_context_import_keys_finish +camel_cipher_context_export_keys_sync +camel_cipher_context_export_keys +camel_cipher_context_export_keys_finish camel_cipher_validity_new camel_cipher_validity_init camel_cipher_validity_get_valid @@ -210,8 +222,14 @@ camel_data_wrapper_get_mime_type_field camel_data_wrapper_set_mime_type_field camel_data_wrapper_is_offline camel_data_wrapper_write_to_stream_sync +camel_data_wrapper_write_to_stream +camel_data_wrapper_write_to_stream_finish camel_data_wrapper_decode_to_stream_sync +camel_data_wrapper_decode_to_stream +camel_data_wrapper_decode_to_stream_finish camel_data_wrapper_construct_from_stream_sync +camel_data_wrapper_construct_from_stream +camel_data_wrapper_construct_from_stream_finish CamelDataWrapperLock camel_data_wrapper_lock camel_data_wrapper_unlock @@ -467,12 +485,26 @@ camel_folder_free_shallow camel_folder_free_deep camel_folder_get_filename camel_folder_append_message_sync +camel_folder_append_message +camel_folder_append_message_finish camel_folder_expunge_sync +camel_folder_expunge +camel_folder_expunge_finish camel_folder_get_message_sync +camel_folder_get_message +camel_folder_get_message_finish camel_folder_refresh_info_sync +camel_folder_refresh_info +camel_folder_refresh_info_finish camel_folder_synchronize_sync +camel_folder_synchronize +camel_folder_synchronize_finish camel_folder_synchronize_message_sync +camel_folder_synchronize_message +camel_folder_synchronize_message_finish camel_folder_transfer_messages_to_sync +camel_folder_transfer_messages_to +camel_folder_transfer_messages_to_finish camel_folder_change_info_new camel_folder_change_info_clear camel_folder_change_info_free @@ -1244,6 +1276,7 @@ camel_mime_message_get_part_by_content_id camel_mime_message_build_mbox_from camel_mime_message_has_attachment camel_mime_message_dump +camel_mime_message_build_preview CAMEL_MIME_MESSAGE CAMEL_IS_MIME_MESSAGE @@ -1327,10 +1360,10 @@ camel_mime_part_get_content_languages camel_mime_part_set_content_type camel_mime_part_get_content_type camel_mime_part_construct_from_parser_sync +camel_mime_part_construct_from_parser +camel_mime_part_construct_from_parser_finish camel_mime_part_set_content -camel_mime_part_get_content_size camel_mime_part_construct_content_from_parser -camel_mime_message_build_preview CAMEL_MIME_PART CAMEL_IS_MIME_PART @@ -1487,6 +1520,8 @@ CamelOfflineFolder camel_offline_folder_get_offline_sync camel_offline_folder_set_offline_sync camel_offline_folder_downsync_sync +camel_offline_folder_downsync +camel_offline_folder_downsync_finish CAMEL_OFFLINE_FOLDER CAMEL_IS_OFFLINE_FOLDER @@ -1599,10 +1634,9 @@ camel_operation_uncancel camel_operation_cancel_check camel_operation_cancel_fd camel_operation_cancel_prfd -camel_operation_start -camel_operation_start_transient +camel_operation_push_message +camel_operation_pop_message camel_operation_progress -camel_operation_end CAMEL_OPERATION CAMEL_IS_OPERATION @@ -1839,7 +1873,11 @@ camel_sasl_get_mechanism camel_sasl_get_service camel_sasl_get_service_name camel_sasl_challenge_sync +camel_sasl_challenge +camel_sasl_challenge_finish camel_sasl_challenge_base64_sync +camel_sasl_challenge_base64 +camel_sasl_challenge_base64_finish camel_sasl_authtype_list camel_sasl_authtype @@ -2128,17 +2166,41 @@ CamelStoreLock camel_store_lock camel_store_unlock camel_store_get_folder_sync +camel_store_get_folder +camel_store_get_folder_finish camel_store_get_folder_info_sync +camel_store_get_folder_info +camel_store_get_folder_info_finish camel_store_get_inbox_folder_sync +camel_store_get_inbox_folder +camel_store_get_inbox_folder_finish camel_store_get_junk_folder_sync +camel_store_get_junk_folder +camel_store_get_junk_folder_finish camel_store_get_trash_folder_sync +camel_store_get_trash_folder +camel_store_get_trash_folder_finish camel_store_create_folder_sync +camel_store_create_folder +camel_store_create_folder_finish camel_store_delete_folder_sync +camel_store_delete_folder +camel_store_delete_folder_finish camel_store_rename_folder_sync +camel_store_rename_folder +camel_store_rename_folder_finish camel_store_subscribe_folder_sync +camel_store_subscribe_folder +camel_store_subscribe_folder_finish camel_store_unsubscribe_folder_sync +camel_store_unsubscribe_folder +camel_store_unsubscribe_folder_finish camel_store_synchronize_sync +camel_store_synchronize +camel_store_synchronize_finish camel_store_noop_sync +camel_store_noop +camel_store_noop_finish CAMEL_STORE CAMEL_IS_STORE @@ -2459,10 +2521,12 @@ camel_text_index_name_get_type camel-transport CamelTransport CamelTransport -camel_transport_send_to_sync CamelTransportLock camel_transport_lock camel_transport_unlock +camel_transport_send_to_sync +camel_transport_send_to +camel_transport_send_to_finish CAMEL_TRANSPORT CAMEL_IS_TRANSPORT diff --git a/docs/reference/camel/tmpl/camel-cipher-context.sgml b/docs/reference/camel/tmpl/camel-cipher-context.sgml index 1068c8f..aa30635 100644 --- a/docs/reference/camel/tmpl/camel-cipher-context.sgml +++ b/docs/reference/camel/tmpl/camel-cipher-context.sgml @@ -116,7 +116,7 @@ CamelCipherContext @Returns: - + @@ -126,7 +126,7 @@ CamelCipherContext @Returns: - + @@ -136,7 +136,7 @@ CamelCipherContext @Returns: - + @@ -151,19 +151,70 @@ CamelCipherContext @Returns: - + @context: +@userid: +@hash: @ipart: +@opart: +@io_priority: @cancellable: +@callback: +@user_data: + + + + + + + +@context: +@result: +@error: +@Returns: + + + + + + + +@context: +@ipart: +@cancellable: +@error: +@Returns: + + + + + + + +@context: +@ipart: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@context: +@result: @error: @Returns: - + @@ -178,7 +229,34 @@ CamelCipherContext @Returns: - + + + + + +@context: +@userid: +@recipients: +@ipart: +@opart: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@context: +@result: +@error: +@Returns: + + + @@ -191,19 +269,68 @@ CamelCipherContext @Returns: - + + + + + +@context: +@ipart: +@opart: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@context: +@result: +@error: +@Returns: + + + + + + + +@context: +@istream: +@cancellable: +@error: +@Returns: + + + @context: @istream: +@io_priority: @cancellable: +@callback: +@user_data: + + + + + + + +@context: +@result: @error: @Returns: - + @@ -216,6 +343,31 @@ CamelCipherContext @Returns: + + + + + +@context: +@keys: +@ostream: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@context: +@result: +@error: +@Returns: + + @@ -528,6 +680,44 @@ CamelCipherContext @gpointer cert_data: @gpointer cert_data: @gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: +@gpointer cert_data: @gpointer cert_data: diff --git a/docs/reference/camel/tmpl/camel-data-wrapper.sgml b/docs/reference/camel/tmpl/camel-data-wrapper.sgml index a27a941..cb746fa 100644 --- a/docs/reference/camel/tmpl/camel-data-wrapper.sgml +++ b/docs/reference/camel/tmpl/camel-data-wrapper.sgml @@ -92,6 +92,30 @@ CamelDataWrapper @Returns: + + + + + +@data_wrapper: +@stream: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@data_wrapper: +@result: +@error: +@Returns: + + @@ -104,6 +128,30 @@ CamelDataWrapper @Returns: + + + + + +@data_wrapper: +@stream: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@data_wrapper: +@result: +@error: +@Returns: + + @@ -116,6 +164,30 @@ CamelDataWrapper @Returns: + + + + + +@data_wrapper: +@stream: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@data_wrapper: +@result: +@error: +@Returns: + + diff --git a/docs/reference/camel/tmpl/camel-db.sgml b/docs/reference/camel/tmpl/camel-db.sgml index 08e58fa..be18b4d 100644 --- a/docs/reference/camel/tmpl/camel-db.sgml +++ b/docs/reference/camel/tmpl/camel-db.sgml @@ -82,9 +82,9 @@ CamelDB @Param1: -@Varargs: +@Param2: @Param3: -@Varargs: +@Param4: @Param5: @Returns: diff --git a/docs/reference/camel/tmpl/camel-folder-summary.sgml b/docs/reference/camel/tmpl/camel-folder-summary.sgml index 5cdadca..9769acc 100644 --- a/docs/reference/camel/tmpl/camel-folder-summary.sgml +++ b/docs/reference/camel/tmpl/camel-folder-summary.sgml @@ -718,6 +718,7 @@ CamelFolderSummary @info: +@Returns: diff --git a/docs/reference/camel/tmpl/camel-folder.sgml b/docs/reference/camel/tmpl/camel-folder.sgml index 99b6483..4e52502 100644 --- a/docs/reference/camel/tmpl/camel-folder.sgml +++ b/docs/reference/camel/tmpl/camel-folder.sgml @@ -648,6 +648,32 @@ CamelFolder @Returns: + + + + + +@folder: +@message: +@info: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@folder: +@result: +@appended_uid: +@error: +@Returns: + + @@ -659,18 +685,65 @@ CamelFolder @Returns: + + + + + +@folder: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@folder: +@result: +@error: +@Returns: + + @folder: -@uid: +@message_uid: @cancellable: @error: @Returns: + + + + + +@folder: +@message_uid: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@folder: +@result: +@error: +@Returns: + + @@ -682,6 +755,29 @@ CamelFolder @Returns: + + + + + +@folder: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@folder: +@result: +@error: +@Returns: + + @@ -694,29 +790,104 @@ CamelFolder @Returns: + + + + + +@folder: +@expunge: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@folder: +@result: +@error: +@Returns: + + @folder: -@uid: +@message_uid: @cancellable: @error: @Returns: + + + + + +@folder: +@message_uid: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@folder: +@result: +@error: +@Returns: + + @source: -@uids: -@dest: +@message_uids: +@destination: +@delete_originals: @transferred_uids: +@cancellable: +@error: +@Returns: + + + + + + + +@source: +@message_uids: +@destination: @delete_originals: +@io_priority: @cancellable: +@callback: +@user_data: + + + + + + + +@source: +@result: +@transferred_uids: @error: @Returns: diff --git a/docs/reference/camel/tmpl/camel-mime-message.sgml b/docs/reference/camel/tmpl/camel-mime-message.sgml index 8b91f07..dd7e37b 100644 --- a/docs/reference/camel/tmpl/camel-mime-message.sgml +++ b/docs/reference/camel/tmpl/camel-mime-message.sgml @@ -284,7 +284,17 @@ CamelMimeMessage -@msg: +@message: @body: + + + + + +@mime_part: +@info: +@Returns: + + diff --git a/docs/reference/camel/tmpl/camel-mime-part.sgml b/docs/reference/camel/tmpl/camel-mime-part.sgml index 55cad4b..28c7905 100644 --- a/docs/reference/camel/tmpl/camel-mime-part.sgml +++ b/docs/reference/camel/tmpl/camel-mime-part.sgml @@ -238,45 +238,50 @@ CamelMimePart @Returns: - + @mime_part: -@data: -@length: -@type: +@parser: +@io_priority: +@cancellable: +@callback: +@user_data: - + @mime_part: +@result: +@error: @Returns: - + @mime_part: -@mp: -@cancellable: -@error: -@Returns: +@data: +@length: +@type: - + @mime_part: -@info: +@mp: +@cancellable: +@error: @Returns: diff --git a/docs/reference/camel/tmpl/camel-offline-folder.sgml b/docs/reference/camel/tmpl/camel-offline-folder.sgml index e84bfae..6c51d3a 100644 --- a/docs/reference/camel/tmpl/camel-offline-folder.sgml +++ b/docs/reference/camel/tmpl/camel-offline-folder.sgml @@ -36,7 +36,7 @@ CamelOfflineFolder -@offline: +@folder: @Returns: @@ -45,7 +45,7 @@ CamelOfflineFolder -@offline: +@folder: @offline_sync: @@ -54,10 +54,34 @@ CamelOfflineFolder -@offline: +@folder: @expression: @cancellable: @error: @Returns: + + + + + +@folder: +@expression: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@folder: +@result: +@error: +@Returns: + + diff --git a/docs/reference/camel/tmpl/camel-operation.sgml b/docs/reference/camel/tmpl/camel-operation.sgml index 3660bc7..1555b1b 100644 --- a/docs/reference/camel/tmpl/camel-operation.sgml +++ b/docs/reference/camel/tmpl/camel-operation.sgml @@ -80,24 +80,22 @@ camel-operation @Returns: - + @cancellable: -@what: +@format: @Varargs: - + @cancellable: -@what: -@Varargs: @@ -106,14 +104,6 @@ camel-operation @cancellable: -@pc: - - - - - - - -@cancellable: +@percent: diff --git a/docs/reference/camel/tmpl/camel-sasl.sgml b/docs/reference/camel/tmpl/camel-sasl.sgml index 9d4c81f..ab15851 100644 --- a/docs/reference/camel/tmpl/camel-sasl.sgml +++ b/docs/reference/camel/tmpl/camel-sasl.sgml @@ -114,6 +114,30 @@ CamelSasl @Returns: + + + + + +@sasl: +@token: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@sasl: +@result: +@error: +@Returns: + + @@ -126,6 +150,30 @@ CamelSasl @Returns: + + + + + +@sasl: +@token: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@sasl: +@result: +@error: +@Returns: + + diff --git a/docs/reference/camel/tmpl/camel-store.sgml b/docs/reference/camel/tmpl/camel-store.sgml index 7976bfc..aa399d9 100644 --- a/docs/reference/camel/tmpl/camel-store.sgml +++ b/docs/reference/camel/tmpl/camel-store.sgml @@ -561,6 +561,31 @@ CamelStore @Returns: + + + + + +@store: +@folder_name: +@flags: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -574,6 +599,31 @@ CamelStore @Returns: + + + + + +@store: +@top: +@flags: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -585,6 +635,29 @@ CamelStore @Returns: + + + + + +@store: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -596,6 +669,29 @@ CamelStore @Returns: + + + + + +@store: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -607,6 +703,29 @@ CamelStore @Returns: + + + + + +@store: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -620,6 +739,31 @@ CamelStore @Returns: + + + + + +@store: +@parent_name: +@folder_name: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -632,15 +776,64 @@ CamelStore @Returns: + + + + + +@store: +@folder_name: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @store: -@old_namein: +@old_name: +@new_name: +@cancellable: +@error: +@Returns: + + + + + + + +@store: +@old_name: @new_name: +@io_priority: @cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: @error: @Returns: @@ -657,6 +850,30 @@ CamelStore @Returns: + + + + + +@store: +@folder_name: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -669,6 +886,30 @@ CamelStore @Returns: + + + + + +@store: +@folder_name: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -681,6 +922,30 @@ CamelStore @Returns: + + + + + +@store: +@expunge: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + @@ -692,3 +957,26 @@ CamelStore @Returns: + + + + + +@store: +@io_priority: +@cancellable: +@callback: +@user_data: + + + + + + + +@store: +@result: +@error: +@Returns: + + diff --git a/docs/reference/camel/tmpl/camel-transport.sgml b/docs/reference/camel/tmpl/camel-transport.sgml index c6bd743..ba5ff96 100644 --- a/docs/reference/camel/tmpl/camel-transport.sgml +++ b/docs/reference/camel/tmpl/camel-transport.sgml @@ -26,6 +26,31 @@ CamelTransport + + + + + +@CAMEL_TRANSPORT_SEND_LOCK: + + + + + + +@transport: +@lock: + + + + + + + +@transport: +@lock: + + @@ -40,28 +65,29 @@ CamelTransport @Returns: - - - - - -@CAMEL_TRANSPORT_SEND_LOCK: - - + @transport: -@lock: +@message: +@from: +@recipients: +@io_priority: +@cancellable: +@callback: +@user_data: - + @transport: -@lock: +@result: +@error: +@Returns: diff --git a/docs/reference/camel/tmpl/camel-unused.sgml b/docs/reference/camel/tmpl/camel-unused.sgml index 152229e..cadb274 100644 --- a/docs/reference/camel/tmpl/camel-unused.sgml +++ b/docs/reference/camel/tmpl/camel-unused.sgml @@ -4522,6 +4522,18 @@ streams @error: @Returns: + + + + + +@context: +@ipart: +@opart: +@cancellable: +@error: +@Returns: + @@ -4536,6 +4548,20 @@ streams @error: @Returns: + + + + + +@context: +@userid: +@recipients: +@ipart: +@opart: +@cancellable: +@error: +@Returns: + @@ -4548,96 +4574,129 @@ streams @error: @Returns: - + @context: -@istream: +@keys: +@ostream: @cancellable: @error: @Returns: - + @context: -@userid: @hash: -@ipart: -@opart: -@cancellable: -@error: @Returns: - + @context: -@ipart: +@id: +@Returns: + + + + + + +@context: +@istream: @cancellable: @error: @Returns: - + -@cache: -@path: -@ex: +@context: +@istream: +@cancellable: +@error: @Returns: - + -@cache: -@old: -@new: -@ex: +@context: +@userid: +@hash: +@ipart: +@opart: +@cancellable: +@error: @Returns: - + -@data_wrapper: -@stream: +@context: +@userid: +@hash: +@ipart: +@opart: @cancellable: @error: @Returns: - + -@data_wrapper: -@stream: +@context: +@ipart: @cancellable: @error: @Returns: - + -@data_wrapper: -@stream: +@context: +@ipart: @cancellable: @error: @Returns: + + + + + +@cache: +@path: +@ex: +@Returns: + + + + + + +@cache: +@old: +@new: +@ex: +@Returns: + @@ -4786,19 +4845,6 @@ streams @n: @Returns: - - - - - -@folder: -@message: -@info: -@appended_uid: -@cancellable: -@error: -@Returns: - @@ -4809,37 +4855,6 @@ streams @full_name: @name: - - - - - -@folder: -@cancellable: -@error: -@Returns: - - - - - - -@folder: -@uid: -@cancellable: -@error: -@Returns: - - - - - - -@folder: -@cancellable: -@error: -@Returns: - @@ -4912,20 +4927,6 @@ streams @error: @Returns: - - - - - -@source: -@uids: -@dest: -@transferred_uids: -@delete_originals: -@cancellable: -@error: -@Returns: - @@ -6808,17 +6809,6 @@ streams @stream: @Returns: - - - - - -@mime_part: -@parser: -@cancellable: -@error: -@Returns: - @@ -7480,17 +7470,6 @@ streams @Param1: - - - - - -@offline: -@expression: -@cancellable: -@error: -@Returns: - @@ -7535,6 +7514,13 @@ streams @cc: + + + + + +@cancellable: + @@ -7573,6 +7559,24 @@ streams @void: @Returns: + + + + + +@cancellable: +@what: +@Varargs: + + + + + + +@cancellable: +@what: +@Varargs: + @@ -7802,28 +7806,6 @@ streams @sasl: @Returns: - - - - - -@sasl: -@token: -@cancellable: -@error: -@Returns: - - - - - - -@sasl: -@token: -@cancellable: -@error: -@Returns: - @@ -8096,53 +8078,6 @@ streams @xevline: @Returns: - - - - - -@store: -@parent_name: -@folder_name: -@cancellable: -@error: -@Returns: - - - - - - -@store: -@folder_name: -@cancellable: -@error: -@Returns: - - - - - - -@store: -@folder_name: -@flags: -@cancellable: -@error: -@Returns: - - - - - - -@store: -@top: -@flags: -@cancellable: -@error: -@Returns: - @@ -8173,39 +8108,6 @@ streams @error: @Returns: - - - - - -@store: -@cancellable: -@error: -@Returns: - - - - - - -@store: -@old_namein: -@new_name: -@cancellable: -@error: -@Returns: - - - - - - -@store: -@folder_name: -@cancellable: -@error: -@Returns: - @@ -8217,17 +8119,6 @@ streams @error: @Returns: - - - - - -@store: -@folder_name: -@cancellable: -@error: -@Returns: - @@ -8357,19 +8248,6 @@ streams @Returns: - - - - - -@transport: -@message: -@from: -@recipients: -@cancellable: -@error: -@Returns: -