2 * e-source-mail-signature.c
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
20 * SECTION: e-source-mail-signature
21 * @include: libedataserver/libedataserver.h
22 * @short_description: #ESource extension for email signatures
24 * The #ESourceMailSignature extension refers to a personalized email
27 * Access the extension as follows:
30 * #include <libedataserver/libedataserver.h>
32 * ESourceMailSignature *extension;
34 * extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_SIGNATURE);
38 #include "e-source-mail-signature.h"
42 #include <glib/gi18n-lib.h>
44 #include <libedataserver/e-data-server-util.h>
46 #define E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE(obj) \
47 (G_TYPE_INSTANCE_GET_PRIVATE \
48 ((obj), E_TYPE_SOURCE_MAIL_SIGNATURE, ESourceMailSignaturePrivate))
50 typedef struct _AsyncContext AsyncContext;
52 struct _ESourceMailSignaturePrivate {
58 struct _AsyncContext {
60 gchar *symlink_target;
72 e_source_mail_signature,
73 E_TYPE_SOURCE_EXTENSION)
76 async_context_free (AsyncContext *async_context)
78 g_free (async_context->contents);
79 g_free (async_context->symlink_target);
81 g_slice_free (AsyncContext, async_context);
85 source_mail_signature_set_property (GObject *object,
90 switch (property_id) {
92 e_source_mail_signature_set_mime_type (
93 E_SOURCE_MAIL_SIGNATURE (object),
94 g_value_get_string (value));
98 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
102 source_mail_signature_get_property (GObject *object,
107 switch (property_id) {
111 e_source_mail_signature_get_file (
112 E_SOURCE_MAIL_SIGNATURE (object)));
116 g_value_take_string (
118 e_source_mail_signature_dup_mime_type (
119 E_SOURCE_MAIL_SIGNATURE (object)));
123 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
127 source_mail_signature_dispose (GObject *object)
129 ESourceMailSignaturePrivate *priv;
131 priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
133 if (priv->file != NULL) {
134 g_object_unref (priv->file);
138 /* Chain up to parent's dispose() method. */
139 G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
144 source_mail_signature_finalize (GObject *object)
146 ESourceMailSignaturePrivate *priv;
148 priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
150 g_mutex_clear (&priv->property_lock);
152 g_free (priv->mime_type);
154 /* Chain up to parent's finalize() method. */
155 G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
160 source_mail_signature_constructed (GObject *object)
162 ESourceMailSignaturePrivate *priv;
163 ESourceExtension *extension;
165 const gchar *config_dir;
170 priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
172 /* Chain up to parent's constructed() method. */
173 G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
174 constructed (object);
176 extension = E_SOURCE_EXTENSION (object);
177 source = e_source_extension_ref_source (extension);
178 uid = e_source_get_uid (source);
180 config_dir = e_get_user_config_dir ();
181 base_dir = g_build_filename (config_dir, "signatures", NULL);
182 path = g_build_filename (base_dir, uid, NULL);
183 priv->file = g_file_new_for_path (path);
184 g_mkdir_with_parents (base_dir, 0700);
188 g_object_unref (source);
192 e_source_mail_signature_class_init (ESourceMailSignatureClass *class)
194 GObjectClass *object_class;
195 ESourceExtensionClass *extension_class;
197 g_type_class_add_private (
198 class, sizeof (ESourceMailSignaturePrivate));
200 object_class = G_OBJECT_CLASS (class);
201 object_class->set_property = source_mail_signature_set_property;
202 object_class->get_property = source_mail_signature_get_property;
203 object_class->dispose = source_mail_signature_dispose;
204 object_class->finalize = source_mail_signature_finalize;
205 object_class->constructed = source_mail_signature_constructed;
207 extension_class = E_SOURCE_EXTENSION_CLASS (class);
208 extension_class->name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
210 g_object_class_install_property (
213 g_param_spec_object (
216 "File containing signature content",
219 G_PARAM_STATIC_STRINGS));
221 g_object_class_install_property (
224 g_param_spec_string (
227 "MIME type of the signature content",
231 G_PARAM_STATIC_STRINGS |
232 E_SOURCE_PARAM_SETTING));
236 e_source_mail_signature_init (ESourceMailSignature *extension)
238 extension->priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (extension);
239 g_mutex_init (&extension->priv->property_lock);
243 * e_source_mail_signature_get_file:
244 * @extension: an #ESourceMailSignature
246 * Returns a #GFile instance pointing to the signature file for @extension.
247 * The signature file may be a regular file containing the static signature
248 * content, or it may be a symbolic link to an executable file that produces
249 * the signature content.
251 * e_source_mail_signature_load() uses this to load the signature content.
253 * Returns: (transfer none): a #GFile
258 e_source_mail_signature_get_file (ESourceMailSignature *extension)
260 g_return_val_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension), NULL);
262 return extension->priv->file;
266 * e_source_mail_signature_get_mime_type:
267 * @extension: an #ESourceMailSignature
269 * Returns the MIME type of the signature content for @extension, or %NULL
270 * if it has not yet been determined.
272 * e_source_mail_signature_load() sets this automatically if the MIME type
273 * has not yet been determined.
275 * Returns: the MIME type of the signature content, or %NULL
280 e_source_mail_signature_get_mime_type (ESourceMailSignature *extension)
282 g_return_val_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension), NULL);
284 return extension->priv->mime_type;
288 * e_source_mail_signature_dup_mime_type:
289 * @extension: an #ESourceMailSignature
291 * Thread-safe variation of e_source_mail_signature_get_mime_type().
292 * Use this function when accessing @extension from multiple threads.
294 * The returned string should be freed with g_free() when no longer needed.
296 * Returns: a newly-allocated copy of #ESourceMailSignature:mime-type
301 e_source_mail_signature_dup_mime_type (ESourceMailSignature *extension)
303 const gchar *protected;
306 g_return_val_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension), NULL);
308 g_mutex_lock (&extension->priv->property_lock);
310 protected = e_source_mail_signature_get_mime_type (extension);
311 duplicate = g_strdup (protected);
313 g_mutex_unlock (&extension->priv->property_lock);
319 * e_source_mail_signature_set_mime_type:
320 * @extension: an #ESourceMailSignature
321 * @mime_type: (allow-none): a MIME type, or %NULL
323 * Sets the MIME type of the signature content for @extension.
325 * e_source_mail_signature_load() sets this automatically if the MIME type
326 * has not yet been determined.
328 * The internal copy of @mime_type is automatically stripped of leading
329 * and trailing whitespace. If the resulting string is empty, %NULL is
335 e_source_mail_signature_set_mime_type (ESourceMailSignature *extension,
336 const gchar *mime_type)
338 g_return_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension));
340 g_mutex_lock (&extension->priv->property_lock);
342 if (g_strcmp0 (extension->priv->mime_type, mime_type) == 0) {
343 g_mutex_unlock (&extension->priv->property_lock);
347 g_free (extension->priv->mime_type);
348 extension->priv->mime_type = e_util_strdup_strip (mime_type);
350 g_mutex_unlock (&extension->priv->property_lock);
352 g_object_notify (G_OBJECT (extension), "mime-type");
355 /********************** e_source_mail_signature_load() ***********************/
357 /* Helper for e_source_mail_signature_load() */
359 source_mail_signature_load_thread (GSimpleAsyncResult *simple,
361 GCancellable *cancellable)
363 AsyncContext *async_context;
364 GError *error = NULL;
366 async_context = g_simple_async_result_get_op_res_gpointer (simple);
368 e_source_mail_signature_load_sync (
370 &async_context->contents,
371 &async_context->length,
372 cancellable, &error);
375 g_simple_async_result_take_error (simple, error);
379 * e_source_mail_signature_load_sync:
380 * @source: an #ESource
381 * @contents: return location for the signature content
382 * @length: (allow-none): return location for the length of the signature
383 * content, or %NULL if the length is not needed
384 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
385 * @error: return location for a #GError, or %NULL
387 * Loads a signature from the signature file for @source, which is
388 * given by e_source_mail_signature_get_file(). The signature contents
389 * are placed in @contents, and @length is set to the size of the @contents
390 * string. The @contents string should be freed with g_free() when no
393 * If the signature file is executable, it will be executed and its output
394 * captured as the email signature content. If the signature file is not
395 * executable, the email signature content is read directly from the file.
397 * Returns: %TRUE on success, %FALSE on failure
402 e_source_mail_signature_load_sync (ESource *source,
405 GCancellable *cancellable,
408 ESourceMailSignature *extension;
409 GFileInfo *file_info;
411 const gchar *content_type;
412 const gchar *extension_name;
413 gchar *local_contents = NULL;
414 gboolean can_execute;
416 gchar *guessed_content_type;
421 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
422 g_return_val_if_fail (contents != NULL, FALSE);
424 extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
425 extension = e_source_get_extension (source, extension_name);
426 file = e_source_mail_signature_get_file (extension);
428 file_info = g_file_query_info (
430 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE ","
431 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
432 G_FILE_QUERY_INFO_NONE,
435 if (file_info == NULL)
438 can_execute = g_file_info_get_attribute_boolean (
439 file_info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE);
441 content_type = g_file_info_get_content_type (file_info);
442 mime_type = g_content_type_get_mime_type (content_type);
447 /*** Load signature file contents ***/
449 success = g_file_load_contents (
450 file, cancellable, &local_contents, NULL, NULL, error);
455 g_return_val_if_fail (local_contents != NULL, FALSE);
457 /* Signatures are saved as UTF-8, but we still need to check that
458 * the signature is valid UTF-8 because the user may be opening a
459 * signature file this is in his/her locale character set. If it
460 * is not UTF-8 then try converting from the current locale. */
461 if (!g_utf8_validate (local_contents, -1, NULL)) {
464 utf8 = g_locale_to_utf8 (
465 local_contents, -1, NULL, NULL, error);
472 g_free (local_contents);
473 local_contents = utf8;
480 /*** Execute signature file and capture output ***/
482 path = g_file_get_path (file);
486 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
487 _("Signature script must be a local file"));
492 /* Enclose the path in single-quotes for compatibility on Windows.
493 * (See g_spawn_command_line_sync() documentation for rationale.) */
494 command_line = g_strdup_printf ("'%s'", path);
496 success = g_spawn_command_line_sync (
497 command_line, &local_contents, NULL, NULL, error);
499 g_free (command_line);
502 /* Check if we failed to spawn the script. */
506 /* Check if we were cancelled while the script was running. */
507 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
512 g_return_val_if_fail (local_contents != NULL, FALSE);
514 /* Signature scripts are supposed to generate UTF-8 content, but
515 * because users are known to never read the manual, we try to do
516 * our best if the content isn't valid UTF-8 by assuming that the
517 * content is in the user's locale character set. */
518 if (!g_utf8_validate (local_contents, -1, NULL)) {
521 utf8 = g_locale_to_utf8 (
522 local_contents, -1, NULL, NULL, error);
529 g_free (local_contents);
530 local_contents = utf8;
535 /* Try and guess the content type of the script output
536 * so it can be applied correctly to the mail message. */
537 guessed_content_type = g_content_type_guess (
538 NULL, (guchar *) local_contents,
539 strlen (local_contents), NULL);
540 mime_type = g_content_type_get_mime_type (guessed_content_type);
541 g_free (guessed_content_type);
545 const gchar *ext_mime_type;
548 *length = strlen (local_contents);
550 *contents = local_contents;
551 local_contents = NULL;
554 e_source_mail_signature_get_mime_type (extension);
556 /* Don't override the MIME type if it's already set. */
557 if (ext_mime_type == NULL || *ext_mime_type == '\0')
558 e_source_mail_signature_set_mime_type (
559 extension, mime_type);
562 g_object_unref (file_info);
563 g_free (local_contents);
570 * e_source_mail_signature_load:
571 * @source: an #ESource
572 * @io_priority: the I/O priority of the request
573 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
574 * @callback: (scope async): a #GAsyncReadyCallback to call when the request
576 * @user_data: (closure): data to pass to the callback function
578 * Asynchronously loads a signature from the signature file for @source,
579 * which is given by e_source_mail_signature_get_file().
581 * If the signature file is executable, it will be executed and its output
582 * captured as the email signature content. If the signature file is not
583 * executable, the email signature content is read directly from the file.
585 * When the operation is finished, @callback will be called. You can
586 * then call e_source_mail_signature_load_finish() to get the result of
592 e_source_mail_signature_load (ESource *source,
594 GCancellable *cancellable,
595 GAsyncReadyCallback callback,
598 GSimpleAsyncResult *simple;
599 AsyncContext *async_context;
601 g_return_if_fail (E_IS_SOURCE (source));
603 async_context = g_slice_new0 (AsyncContext);
605 simple = g_simple_async_result_new (
606 G_OBJECT (source), callback, user_data,
607 e_source_mail_signature_load);
609 g_simple_async_result_set_check_cancellable (simple, cancellable);
611 g_simple_async_result_set_op_res_gpointer (
612 simple, async_context, (GDestroyNotify) async_context_free);
614 g_simple_async_result_run_in_thread (
615 simple, source_mail_signature_load_thread,
616 io_priority, cancellable);
618 g_object_unref (simple);
622 * e_source_mail_signature_load_finish:
623 * @source: an #ESource
624 * @result: a #GAsyncResult
625 * @contents: return location for the signature content
626 * @length: (allow-none): return location for the length of the signature
627 * content, or %NULL if the length is not needed
628 * @error: return location for a #GError, or %NULL
630 * Finishes an operation started with e_source_mail_signature_load(). The
631 * signature file contents are placed in @contents, and @length is set to
632 * the size of the @contents string. The @contents string should be freed
633 * with g_free() when no longer needed.
635 * Returns: %TRUE on success, %FALSE on failure
640 e_source_mail_signature_load_finish (ESource *source,
641 GAsyncResult *result,
646 GSimpleAsyncResult *simple;
647 AsyncContext *async_context;
649 g_return_val_if_fail (
650 g_simple_async_result_is_valid (
651 result, G_OBJECT (source),
652 e_source_mail_signature_load), FALSE);
654 g_return_val_if_fail (contents != NULL, FALSE);
656 simple = G_SIMPLE_ASYNC_RESULT (result);
657 async_context = g_simple_async_result_get_op_res_gpointer (simple);
659 if (g_simple_async_result_propagate_error (simple, error))
662 g_return_val_if_fail (async_context->contents != NULL, FALSE);
664 *contents = async_context->contents;
665 async_context->contents = NULL;
668 *length = async_context->length;
673 /********************* e_source_mail_signature_replace() *********************/
675 /* Helper for e_source_mail_signature_replace() */
677 source_mail_signature_replace_thread (GSimpleAsyncResult *simple,
679 GCancellable *cancellable)
681 AsyncContext *async_context;
682 GError *error = NULL;
684 async_context = g_simple_async_result_get_op_res_gpointer (simple);
686 e_source_mail_signature_replace_sync (
687 E_SOURCE (object), async_context->contents,
688 async_context->length, cancellable, &error);
691 g_simple_async_result_take_error (simple, error);
695 * e_source_mail_signature_replace_sync:
696 * @source: an #ESource
697 * @contents: the signature contents
698 * @length: the length of @contents in bytes
699 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
700 * @error: return location for a #GError, or %NULL
702 * Replaces the signature file for @source with the given @contents
703 * of @length bytes. The signature file for @source is given by
704 * e_source_mail_signature_get_file().
706 * Returns: %TRUE on success, %FALSE on failure
711 e_source_mail_signature_replace_sync (ESource *source,
712 const gchar *contents,
714 GCancellable *cancellable,
717 ESourceMailSignature *extension;
718 const gchar *extension_name;
721 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
722 g_return_val_if_fail (contents != NULL, FALSE);
724 extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
725 extension = e_source_get_extension (source, extension_name);
726 file = e_source_mail_signature_get_file (extension);
728 return g_file_replace_contents (
729 file, contents, length, NULL, FALSE,
730 G_FILE_CREATE_REPLACE_DESTINATION,
731 NULL, cancellable, error);
735 * e_source_mail_signature_replace:
736 * @source: an #ESource
737 * @contents: the signature contents
738 * @length: the length of @contents in bytes
739 * @io_priority: the I/O priority of the request
740 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
741 * @callback: (scope async): a #GAsyncReadyCallback to call when the request
743 * @user_data: (closure): data to pass to the callback function
745 * Asynchrously replaces the signature file for @source with the given
746 * @contents of @length bytes. The signature file for @source is given
747 * by e_source_mail_signature_get_file().
749 * When the operation is finished, @callback will be called. You can
750 * then call e_source_mail_signature_replace_finish() to get the result
756 e_source_mail_signature_replace (ESource *source,
757 const gchar *contents,
760 GCancellable *cancellable,
761 GAsyncReadyCallback callback,
764 GSimpleAsyncResult *simple;
765 AsyncContext *async_context;
767 g_return_if_fail (E_IS_SOURCE (source));
768 g_return_if_fail (contents != NULL);
770 async_context = g_slice_new0 (AsyncContext);
771 async_context->contents = g_strdup (contents);
772 async_context->length = length;
774 simple = g_simple_async_result_new (
775 G_OBJECT (source), callback, user_data,
776 e_source_mail_signature_replace);
778 g_simple_async_result_set_check_cancellable (simple, cancellable);
780 g_simple_async_result_set_op_res_gpointer (
781 simple, async_context, (GDestroyNotify) async_context_free);
783 g_simple_async_result_run_in_thread (
784 simple, source_mail_signature_replace_thread,
785 io_priority, cancellable);
787 g_object_unref (simple);
791 * e_source_mail_signature_replace_finish:
792 * @source: an #ESource
793 * @result: a #GAsyncResult
794 * @error: return location for a #GError, or %NULL
796 * Finishes an operation started with e_source_mail_signature_replace().
798 * Returns: %TRUE on success, %FALSE on failure
803 e_source_mail_signature_replace_finish (ESource *source,
804 GAsyncResult *result,
807 GSimpleAsyncResult *simple;
809 g_return_val_if_fail (
810 g_simple_async_result_is_valid (
811 result, G_OBJECT (source),
812 e_source_mail_signature_replace), FALSE);
814 simple = G_SIMPLE_ASYNC_RESULT (result);
816 /* Assume success unless a GError is set. */
817 return !g_simple_async_result_propagate_error (simple, error);
820 /********************* e_source_mail_signature_symlink() *********************/
822 /* Helper for e_source_mail_signature_symlink() */
824 source_mail_signature_symlink_thread (GSimpleAsyncResult *simple,
826 GCancellable *cancellable)
828 AsyncContext *async_context;
829 GError *error = NULL;
831 async_context = g_simple_async_result_get_op_res_gpointer (simple);
833 e_source_mail_signature_symlink_sync (
835 async_context->symlink_target,
836 cancellable, &error);
839 g_simple_async_result_take_error (simple, error);
843 * e_source_mail_signature_symlink_sync:
844 * @source: an #ESource
845 * @symlink_target: executable filename to link to
846 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
847 * @error: return location for a #GError, or %NULL
849 * Replaces the signature file for @source with a symbolic link to
850 * @symlink_target, which should be an executable file that prints
851 * a mail signature to standard output. The signature file for
852 * @source is given by e_source_mail_signature_get_file().
854 * Returns: %TRUE on success, %FALSE on failure
859 e_source_mail_signature_symlink_sync (ESource *source,
860 const gchar *symlink_target,
861 GCancellable *cancellable,
864 ESourceMailSignature *extension;
865 const gchar *extension_name;
868 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
869 g_return_val_if_fail (symlink_target != NULL, FALSE);
871 extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
872 extension = e_source_get_extension (source, extension_name);
873 file = e_source_mail_signature_get_file (extension);
875 /* The file may not exist, so we don't care if this fails.
876 * If it fails for a different reason than G_IO_ERROR_NOT_FOUND
877 * then the next step will probably also fail and we'll capture
879 g_file_delete (file, cancellable, NULL);
881 return g_file_make_symbolic_link (
882 file, symlink_target, cancellable, error);
886 * e_source_mail_signature_symlink:
887 * @source: an #ESource
888 * @symlink_target: executable filename to link to
889 * @io_priority: the I/O priority of the request
890 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
891 * @callback: (scope async): a #GAsyncReadyCallback to call when the request
893 * @user_data: (closure): data to pass to the callback function
895 * Asynchronously replaces the signature file for @source with a symbolic
896 * link to @symlink_target, which should be an executable file that prints
897 * a mail signature to standard output. The signature file for @source
898 * is given by e_source_mail_signature_get_file().
900 * When the operation is finished, @callback will be called. You can
901 * then call e_source_mail_signature_symlink_finish() to get the result
907 e_source_mail_signature_symlink (ESource *source,
908 const gchar *symlink_target,
910 GCancellable *cancellable,
911 GAsyncReadyCallback callback,
914 GSimpleAsyncResult *simple;
915 AsyncContext *async_context;
917 g_return_if_fail (E_IS_SOURCE (source));
918 g_return_if_fail (symlink_target != NULL);
920 async_context = g_slice_new0 (AsyncContext);
921 async_context->symlink_target = g_strdup (symlink_target);
923 simple = g_simple_async_result_new (
924 G_OBJECT (source), callback, user_data,
925 e_source_mail_signature_symlink);
927 g_simple_async_result_set_check_cancellable (simple, cancellable);
929 g_simple_async_result_set_op_res_gpointer (
930 simple, async_context, (GDestroyNotify) async_context_free);
932 g_simple_async_result_run_in_thread (
933 simple, source_mail_signature_symlink_thread,
934 io_priority, cancellable);
936 g_object_unref (simple);
940 * e_source_mail_signature_symlink_finish:
941 * @source: an #ESource
942 * @result: a #GAsyncResult
943 * @error: return location for a #GError, or %NULL
945 * Finishes an operation started with e_source_mail_signature_symlink().
947 * Returns: %TRUE on success, %FALSE on failure
952 e_source_mail_signature_symlink_finish (ESource *source,
953 GAsyncResult *result,
956 GSimpleAsyncResult *simple;
958 g_return_val_if_fail (
959 g_simple_async_result_is_valid (
960 result, G_OBJECT (source),
961 e_source_mail_signature_symlink), FALSE);
963 simple = G_SIMPLE_ASYNC_RESULT (result);
965 /* Assume success unless a GError is set. */
966 return !g_simple_async_result_propagate_error (simple, error);