Add new ESource classes.
[platform/upstream/evolution-data-server.git] / libedataserver / e-source-mail-signature.c
1 /*
2  * e-source-mail-signature.c
3  *
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.
8  *
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.
13  *
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/>
16  *
17  */
18
19 /**
20  * SECTION: e-source-mail-signature
21  * @include: libedataserver/e-source-mail-signature.h
22  * @short_description: #ESource extension for email signatures
23  *
24  * The #ESourceMailSignature extension refers to a personalized email
25  * signature.
26  *
27  * Access the extension as follows:
28  *
29  * |[
30  *   #include <libedataserver/e-source-mail-signature.h>
31  *
32  *   ESourceMailSignature *extension;
33  *
34  *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_SIGNATURE);
35  * ]|
36  **/
37
38 #include "e-source-mail-signature.h"
39
40 #include <config.h>
41 #include <string.h>
42 #include <glib/gi18n-lib.h>
43
44 #include <libedataserver/e-data-server-util.h>
45
46 #define E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE(obj) \
47         (G_TYPE_INSTANCE_GET_PRIVATE \
48         ((obj), E_TYPE_SOURCE_MAIL_SIGNATURE, ESourceMailSignaturePrivate))
49
50 typedef struct _AsyncContext AsyncContext;
51
52 struct _ESourceMailSignaturePrivate {
53         GMutex *property_lock;
54         GFile *file;
55         gchar *mime_type;
56 };
57
58 struct _AsyncContext {
59         gchar *contents;
60         gchar *symlink_target;
61         gsize length;
62 };
63
64 enum {
65         PROP_0,
66         PROP_FILE,
67         PROP_MIME_TYPE
68 };
69
70 G_DEFINE_TYPE (
71         ESourceMailSignature,
72         e_source_mail_signature,
73         E_TYPE_SOURCE_EXTENSION)
74
75 static void
76 async_context_free (AsyncContext *async_context)
77 {
78         g_free (async_context->contents);
79         g_free (async_context->symlink_target);
80
81         g_slice_free (AsyncContext, async_context);
82 }
83
84 static void
85 source_mail_signature_set_property (GObject *object,
86                                     guint property_id,
87                                     const GValue *value,
88                                     GParamSpec *pspec)
89 {
90         switch (property_id) {
91                 case PROP_MIME_TYPE:
92                         e_source_mail_signature_set_mime_type (
93                                 E_SOURCE_MAIL_SIGNATURE (object),
94                                 g_value_get_string (value));
95                         return;
96         }
97
98         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
99 }
100
101 static void
102 source_mail_signature_get_property (GObject *object,
103                                     guint property_id,
104                                     GValue *value,
105                                     GParamSpec *pspec)
106 {
107         switch (property_id) {
108                 case PROP_FILE:
109                         g_value_set_object (
110                                 value,
111                                 e_source_mail_signature_get_file (
112                                 E_SOURCE_MAIL_SIGNATURE (object)));
113                         return;
114
115                 case PROP_MIME_TYPE:
116                         g_value_take_string (
117                                 value,
118                                 e_source_mail_signature_dup_mime_type (
119                                 E_SOURCE_MAIL_SIGNATURE (object)));
120                         return;
121         }
122
123         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
124 }
125
126 static void
127 source_mail_signature_dispose (GObject *object)
128 {
129         ESourceMailSignaturePrivate *priv;
130
131         priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
132
133         if (priv->file != NULL) {
134                 g_object_unref (priv->file);
135                 priv->file = NULL;
136         }
137
138         /* Chain up to parent's dispose() method. */
139         G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
140                 dispose (object);
141 }
142
143 static void
144 source_mail_signature_finalize (GObject *object)
145 {
146         ESourceMailSignaturePrivate *priv;
147
148         priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
149
150         g_mutex_free (priv->property_lock);
151
152         g_free (priv->mime_type);
153
154         /* Chain up to parent's finalize() method. */
155         G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
156                 finalize (object);
157 }
158
159 static void
160 source_mail_signature_constructed (GObject *object)
161 {
162         ESourceMailSignaturePrivate *priv;
163         ESourceExtension *extension;
164         ESource *source;
165         const gchar *config_dir;
166         const gchar *uid;
167         gchar *base_dir;
168         gchar *path;
169
170         priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
171
172         /* Chain up to parent's constructed() method. */
173         G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
174                 constructed (object);
175
176         extension = E_SOURCE_EXTENSION (object);
177         source = e_source_extension_get_source (extension);
178         uid = e_source_get_uid (source);
179
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);
185         g_free (base_dir);
186         g_free (path);
187 }
188
189 static void
190 e_source_mail_signature_class_init (ESourceMailSignatureClass *class)
191 {
192         GObjectClass *object_class;
193         ESourceExtensionClass *extension_class;
194
195         g_type_class_add_private (
196                 class, sizeof (ESourceMailSignaturePrivate));
197
198         object_class = G_OBJECT_CLASS (class);
199         object_class->set_property = source_mail_signature_set_property;
200         object_class->get_property = source_mail_signature_get_property;
201         object_class->dispose = source_mail_signature_dispose;
202         object_class->finalize = source_mail_signature_finalize;
203         object_class->constructed = source_mail_signature_constructed;
204
205         extension_class = E_SOURCE_EXTENSION_CLASS (class);
206         extension_class->name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
207
208         g_object_class_install_property (
209                 object_class,
210                 PROP_FILE,
211                 g_param_spec_object (
212                         "file",
213                         "File",
214                         "File containing signature content",
215                         G_TYPE_FILE,
216                         G_PARAM_READABLE |
217                         G_PARAM_STATIC_STRINGS));
218
219         g_object_class_install_property (
220                 object_class,
221                 PROP_MIME_TYPE,
222                 g_param_spec_string (
223                         "mime-type",
224                         "MIME Type",
225                         "MIME type of the signature content",
226                         NULL,
227                         G_PARAM_READWRITE |
228                         G_PARAM_CONSTRUCT |
229                         G_PARAM_STATIC_STRINGS |
230                         E_SOURCE_PARAM_SETTING));
231 }
232
233 static void
234 e_source_mail_signature_init (ESourceMailSignature *extension)
235 {
236         extension->priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (extension);
237         extension->priv->property_lock = g_mutex_new ();
238 }
239
240 /**
241  * e_source_mail_signature_get_file:
242  * @extension: an #ESourceMailSignature
243  *
244  * Returns a #GFile instance pointing to the signature file for @extension.
245  * The signature file may be a regular file containing the static signature
246  * content, or it may be a symbolic link to an executable file that produces
247  * the signature content.
248  *
249  * e_source_mail_signature_load() uses this to load the signature content.
250  *
251  * Returns: a #GFile
252  *
253  * Since: 3.6
254  **/
255 GFile *
256 e_source_mail_signature_get_file (ESourceMailSignature *extension)
257 {
258         g_return_val_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension), NULL);
259
260         return extension->priv->file;
261 }
262
263 /**
264  * e_source_mail_signature_get_mime_type:
265  * @extension: an #ESourceMailSignature
266  *
267  * Returns the MIME type of the signature content for @extension, or %NULL
268  * if it has not yet been determined.
269  *
270  * e_source_mail_signature_load() sets this automatically if the MIME type
271  * has not yet been determined.
272  *
273  * Returns: the MIME type of the signature content, or %NULL
274  *
275  * Since: 3.6
276  **/
277 const gchar *
278 e_source_mail_signature_get_mime_type (ESourceMailSignature *extension)
279 {
280         g_return_val_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension), NULL);
281
282         return extension->priv->mime_type;
283 }
284
285 /**
286  * e_source_mail_signature_dup_mime_type:
287  * @extension: an #ESourceMailSignature
288  *
289  * Thread-safe variation of e_source_mail_signature_get_mime_type().
290  * Use this function when accessing @extension from multiple threads.
291  *
292  * The returned string should be freed with g_free() when no longer needed.
293  *
294  * Returns: a newly-allocated copy of #ESourceMailSignature:mime-type
295  *
296  * Since: 3.6
297  **/
298 gchar *
299 e_source_mail_signature_dup_mime_type (ESourceMailSignature *extension)
300 {
301         const gchar *protected;
302         gchar *duplicate;
303
304         g_return_val_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension), NULL);
305
306         g_mutex_lock (extension->priv->property_lock);
307
308         protected = e_source_mail_signature_get_mime_type (extension);
309         duplicate = g_strdup (protected);
310
311         g_mutex_unlock (extension->priv->property_lock);
312
313         return duplicate;
314 }
315
316 /**
317  * e_source_mail_signature_set_mime_type:
318  * @extension: an #ESourceMailSignature
319  * @mime_type: (allow-none): a MIME type, or %NULL
320  *
321  * Sets the MIME type of the signature content for @extension.
322  *
323  * e_source_mail_signature_load() sets this automatically if the MIME type
324  * has not yet been determined.
325  *
326  * The internal copy of @mime_type is automatically stripped of leading
327  * and trailing whitespace.  If the resulting string is empty, %NULL is
328  * set instead.
329  *
330  * Since: 3.6
331  **/
332 void
333 e_source_mail_signature_set_mime_type (ESourceMailSignature *extension,
334                                        const gchar *mime_type)
335 {
336         g_return_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension));
337
338         g_mutex_lock (extension->priv->property_lock);
339
340         g_free (extension->priv->mime_type);
341         extension->priv->mime_type = e_util_strdup_strip (mime_type);
342
343         g_mutex_unlock (extension->priv->property_lock);
344
345         g_object_notify (G_OBJECT (extension), "mime-type");
346 }
347
348 /********************** e_source_mail_signature_load() ***********************/
349
350 /* Helper for e_source_mail_signature_load() */
351 static void
352 source_mail_signature_load_thread (GSimpleAsyncResult *simple,
353                                    GObject *object,
354                                    GCancellable *cancellable)
355 {
356         AsyncContext *async_context;
357         GError *error = NULL;
358
359         async_context = g_simple_async_result_get_op_res_gpointer (simple);
360
361         e_source_mail_signature_load_sync (
362                 E_SOURCE (object),
363                 &async_context->contents,
364                 &async_context->length,
365                 cancellable, &error);
366
367         if (error != NULL)
368                 g_simple_async_result_take_error (simple, error);
369 }
370
371 /**
372  * e_source_mail_signature_load_sync:
373  * @source: an #ESource
374  * @contents: return location for the signature content
375  * @length: (allow-none): return location for the length of the signature
376  *          content, or %NULL if the length is not needed
377  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
378  * @error: return location for a #GError, or %NULL
379  *
380  * Loads a signature from the signature file for @source, which is
381  * given by e_source_mail_signature_get_file().  The signature contents
382  * are placed in @contents, and @length is set to the size of the @contents
383  * string.  The @contents string should be freed with g_free() when no
384  * longer needed.
385  *
386  * If the signature file is executable, it will be executed and its output
387  * captured as the email signature content.  If the signature file is not
388  * executable, the email signature content is read directly from the file.
389  *
390  * Returns; %TRUE on success, %FALSE on failure
391  *
392  * Since: 3.6
393  **/
394 gboolean
395 e_source_mail_signature_load_sync (ESource *source,
396                                    gchar **contents,
397                                    gsize *length,
398                                    GCancellable *cancellable,
399                                    GError **error)
400 {
401         ESourceMailSignature *extension;
402         GFileInfo *file_info;
403         GFile *file;
404         const gchar *content_type;
405         const gchar *extension_name;
406         gchar *local_contents = NULL;
407         gboolean can_execute;
408         gboolean success;
409         gchar *guessed_content_type;
410         gchar *command_line;
411         gchar *mime_type;
412         gchar *path;
413
414         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
415         g_return_val_if_fail (contents != NULL, FALSE);
416
417         extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
418         extension = e_source_get_extension (source, extension_name);
419         file = e_source_mail_signature_get_file (extension);
420
421         file_info = g_file_query_info (
422                 file,
423                 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE ","
424                 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
425                 G_FILE_QUERY_INFO_NONE,
426                 cancellable, error);
427
428         if (file_info == NULL)
429                 return FALSE;
430
431         can_execute = g_file_info_get_attribute_boolean (
432                 file_info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE);
433
434         content_type = g_file_info_get_content_type (file_info);
435         mime_type = g_content_type_get_mime_type (content_type);
436
437         if (can_execute)
438                 goto execute;
439
440         /*** Load signature file contents ***/
441
442         success = g_file_load_contents (
443                 file, cancellable, &local_contents, NULL, NULL, error);
444
445         if (!success)
446                 goto exit;
447
448         g_return_val_if_fail (local_contents != NULL, FALSE);
449
450         /* Signatures are saved as UTF-8, but we still need to check that
451          * the signature is valid UTF-8 because the user may be opening a
452          * signature file this is in his/her locale character set.  If it
453          * is not UTF-8 then try converting from the current locale. */
454         if (!g_utf8_validate (local_contents, -1, NULL)) {
455                 gchar *utf8;
456
457                 utf8 = g_locale_to_utf8 (
458                         local_contents, -1, NULL, NULL, error);
459
460                 if (utf8 == NULL) {
461                         success = FALSE;
462                         goto exit;
463                 }
464
465                 g_free (local_contents);
466                 local_contents = utf8;
467         }
468
469         goto exit;
470
471 execute:
472
473         /*** Execute signature file and capture output ***/
474
475         path = g_file_get_path (file);
476
477         if (path == NULL) {
478                 g_set_error (
479                         error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
480                         _("Signature script must be a local file"));
481                 success = FALSE;
482                 goto exit;
483         }
484
485         /* Enclose the path in single-quotes for compatibility on Windows.
486          * (See g_spawn_command_line_sync() documentation for rationale.) */
487         command_line = g_strdup_printf ("'%s'", path);
488
489         success = g_spawn_command_line_sync (
490                 command_line, &local_contents, NULL, NULL, error);
491
492         g_free (command_line);
493         g_free (path);
494
495         /* Check if we failed to spawn the script. */
496         if (!success)
497                 goto exit;
498
499         /* Check if we were cancelled while the script was running. */
500         if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
501                 success = FALSE;
502                 goto exit;
503         }
504
505         g_return_val_if_fail (local_contents != NULL, FALSE);
506
507         /* Signature scripts are supposed to generate UTF-8 content, but
508          * because users are known to never read the manual, we try to do
509          * our best if the content isn't valid UTF-8 by assuming that the
510          * content is in the user's locale character set. */
511         if (!g_utf8_validate (local_contents, -1, NULL)) {
512                 gchar *utf8;
513
514                 utf8 = g_locale_to_utf8 (
515                         local_contents, -1, NULL, NULL, error);
516
517                 if (utf8 == NULL) {
518                         success = FALSE;
519                         goto exit;
520                 }
521
522                 g_free (local_contents);
523                 local_contents = utf8;
524         }
525
526         g_free (mime_type);
527
528         /* Try and guess the content type of the script output
529          * so it can be applied correctly to the mail message. */
530         guessed_content_type = g_content_type_guess (
531                 NULL, (guchar *) local_contents,
532                 strlen (local_contents), NULL);
533         mime_type = g_content_type_get_mime_type (guessed_content_type);
534         g_free (guessed_content_type);
535
536 exit:
537         if (success) {
538                 const gchar *ext_mime_type;
539
540                 if (length != NULL)
541                         *length = strlen (local_contents);
542
543                 *contents = local_contents;
544                 local_contents = NULL;
545
546                 ext_mime_type =
547                         e_source_mail_signature_get_mime_type (extension);
548
549                 /* Don't override the MIME type if it's already set. */
550                 if (ext_mime_type == NULL || *ext_mime_type == '\0')
551                         e_source_mail_signature_set_mime_type (
552                                 extension, mime_type);
553         }
554
555         g_object_unref (file_info);
556         g_free (local_contents);
557         g_free (mime_type);
558
559         return success;
560 }
561
562 /**
563  * e_source_mail_signature_load:
564  * @source: an #ESource
565  * @io_priority: the I/O priority of the request
566  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
567  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
568  *            is satisfied
569  * @user_data: (closure): data to pass to the callback function
570  *
571  * Asynchronously loads a signature from the signature file for @source,
572  * which is given by e_source_mail_signature_get_file().
573  *
574  * If the signature file is executable, it will be executed and its output
575  * captured as the email signature content.  If the signature file is not
576  * executable, the email signature content is read directly from the file.
577  *
578  * When the operation is finished, @callback will be called.  You can
579  * then call e_source_mail_signature_load_finish() to get the result of
580  * the operation.
581  *
582  * Since: 3.6
583  **/
584 void
585 e_source_mail_signature_load (ESource *source,
586                               gint io_priority,
587                               GCancellable *cancellable,
588                               GAsyncReadyCallback callback,
589                               gpointer user_data)
590 {
591         GSimpleAsyncResult *simple;
592         AsyncContext *async_context;
593
594         g_return_if_fail (E_IS_SOURCE (source));
595
596         async_context = g_slice_new0 (AsyncContext);
597
598         simple = g_simple_async_result_new (
599                 G_OBJECT (source), callback, user_data,
600                 e_source_mail_signature_load);
601
602         g_simple_async_result_set_check_cancellable (simple, cancellable);
603
604         g_simple_async_result_set_op_res_gpointer (
605                 simple, async_context, (GDestroyNotify) async_context_free);
606
607         g_simple_async_result_run_in_thread (
608                 simple, source_mail_signature_load_thread,
609                 io_priority, cancellable);
610
611         g_object_unref (simple);
612 }
613
614 /**
615  * e_source_mail_signature_load_finish:
616  * @source: an #ESource
617  * @result: a #GAsyncResult
618  * @contents: return location for the signature content
619  * @length: (allow-none): return location for the length of the signature
620  *          content, or %NULL if the length is not needed
621  * @error: return location for a #GError, or %NULL
622  *
623  * Finishes an operation started with e_source_mail_signature_load().  The
624  * signature file contents are placed in @contents, and @length is set to
625  * the size of the @contents string.  The @contents string should be freed
626  * with g_free() when no longer needed.
627  *
628  * Returns: %TRUE on success, %FALSE on failure
629  *
630  * Since: 3.6
631  **/
632 gboolean
633 e_source_mail_signature_load_finish (ESource *source,
634                                      GAsyncResult *result,
635                                      gchar **contents,
636                                      gsize *length,
637                                      GError **error)
638 {
639         GSimpleAsyncResult *simple;
640         AsyncContext *async_context;
641
642         g_return_val_if_fail (
643                 g_simple_async_result_is_valid (
644                 result, G_OBJECT (source),
645                 e_source_mail_signature_load), FALSE);
646
647         g_return_val_if_fail (contents != NULL, FALSE);
648
649         simple = G_SIMPLE_ASYNC_RESULT (result);
650         async_context = g_simple_async_result_get_op_res_gpointer (simple);
651
652         if (g_simple_async_result_propagate_error (simple, error))
653                 return FALSE;
654
655         g_return_val_if_fail (async_context->contents != NULL, FALSE);
656
657         *contents = async_context->contents;
658         async_context->contents = NULL;
659
660         if (length != NULL)
661                 *length = async_context->length;
662
663         return TRUE;
664 }
665
666 /********************* e_source_mail_signature_replace() *********************/
667
668 /* Helper for e_source_mail_signature_replace() */
669 static void
670 source_mail_signature_replace_thread (GSimpleAsyncResult *simple,
671                                       GObject *object,
672                                       GCancellable *cancellable)
673 {
674         AsyncContext *async_context;
675         GError *error = NULL;
676
677         async_context = g_simple_async_result_get_op_res_gpointer (simple);
678
679         e_source_mail_signature_replace_sync (
680                 E_SOURCE (object), async_context->contents,
681                 async_context->length, cancellable, &error);
682
683         if (error != NULL)
684                 g_simple_async_result_take_error (simple, error);
685 }
686
687 /**
688  * e_source_mail_signature_replace_sync:
689  * @source: an #ESource
690  * @contents: the signature contents
691  * @length: the length of @contents in bytes
692  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
693  * @error: return location for a #GError, or %NULL
694  *
695  * Replaces the signature file for @source with the given @contents
696  * of @length bytes.  The signature file for @source is given by
697  * e_source_mail_signature_get_file().
698  *
699  * Returns: %TRUE on success, %FALSE on failure
700  *
701  * Since: 3.6
702  **/
703 gboolean
704 e_source_mail_signature_replace_sync (ESource *source,
705                                       const gchar *contents,
706                                       gsize length,
707                                       GCancellable *cancellable,
708                                       GError **error)
709 {
710         ESourceMailSignature *extension;
711         const gchar *extension_name;
712         GFile *file;
713
714         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
715         g_return_val_if_fail (contents != NULL, FALSE);
716
717         extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
718         extension = e_source_get_extension (source, extension_name);
719         file = e_source_mail_signature_get_file (extension);
720
721         return g_file_replace_contents (
722                 file, contents, length, NULL, FALSE,
723                 G_FILE_CREATE_REPLACE_DESTINATION,
724                 NULL, cancellable, error);
725 }
726
727 /**
728  * e_source_mail_signature_replace:
729  * @source: an #ESource
730  * @contents: the signature contents
731  * @length: the length of @contents in bytes
732  * @io_priority: the I/O priority of the request
733  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
734  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
735  *            is satisfied
736  * @user_data: (closure): data to pass to the callback function
737  *
738  * Asynchrously replaces the signature file for @source with the given
739  * @contents of @length bytes.  The signature file for @source is given
740  * by e_source_mail_signature_get_file().
741  *
742  * When the operation is finished, @callback will be called.  You can
743  * then call e_source_mail_signature_replace_finish() to get the result
744  * of the operation.
745  *
746  * Since: 3.6
747  **/
748 void
749 e_source_mail_signature_replace (ESource *source,
750                                  const gchar *contents,
751                                  gsize length,
752                                  gint io_priority,
753                                  GCancellable *cancellable,
754                                  GAsyncReadyCallback callback,
755                                  gpointer user_data)
756 {
757         GSimpleAsyncResult *simple;
758         AsyncContext *async_context;
759
760         g_return_if_fail (E_IS_SOURCE (source));
761         g_return_if_fail (contents != NULL);
762
763         async_context = g_slice_new0 (AsyncContext);
764         async_context->contents = g_strdup (contents);
765         async_context->length = length;
766
767         simple = g_simple_async_result_new (
768                 G_OBJECT (source), callback, user_data,
769                 e_source_mail_signature_replace);
770
771         g_simple_async_result_set_check_cancellable (simple, cancellable);
772
773         g_simple_async_result_set_op_res_gpointer (
774                 simple, async_context, (GDestroyNotify) async_context_free);
775
776         g_simple_async_result_run_in_thread (
777                 simple, source_mail_signature_replace_thread,
778                 io_priority, cancellable);
779
780         g_object_unref (simple);
781 }
782
783 /**
784  * e_source_mail_signature_replace_finish:
785  * @source: an #ESource
786  * @result: a #GAsyncResult
787  * @error: return location for a #GError, or %NULL
788  *
789  * Finishes an operation started with e_source_mail_signature_replace().
790  *
791  * Returns: %TRUE on success, %FALSE on failure
792  *
793  * Since: 3.6
794  **/
795 gboolean
796 e_source_mail_signature_replace_finish (ESource *source,
797                                         GAsyncResult *result,
798                                         GError **error)
799 {
800         GSimpleAsyncResult *simple;
801
802         g_return_val_if_fail (
803                 g_simple_async_result_is_valid (
804                 result, G_OBJECT (source),
805                 e_source_mail_signature_replace), FALSE);
806
807         simple = G_SIMPLE_ASYNC_RESULT (result);
808
809         /* Assume success unless a GError is set. */
810         return !g_simple_async_result_propagate_error (simple, error);
811 }
812
813 /********************* e_source_mail_signature_symlink() *********************/
814
815 /* Helper for e_source_mail_signature_symlink() */
816 static void
817 source_mail_signature_symlink_thread (GSimpleAsyncResult *simple,
818                                       GObject *object,
819                                       GCancellable *cancellable)
820 {
821         AsyncContext *async_context;
822         GError *error = NULL;
823
824         async_context = g_simple_async_result_get_op_res_gpointer (simple);
825
826         e_source_mail_signature_symlink_sync (
827                 E_SOURCE (object),
828                 async_context->symlink_target,
829                 cancellable, &error);
830
831         if (error != NULL)
832                 g_simple_async_result_take_error (simple, error);
833 }
834
835 /**
836  * e_source_mail_signature_symlink_sync:
837  * @source: an #ESource
838  * @symlink_target: executable filename to link to
839  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
840  * @error: return location for a #GError, or %NULL
841  *
842  * Replaces the signature file for @source with a symbolic link to
843  * @symlink_target, which should be an executable file that prints
844  * a mail signature to standard output.  The signature file for
845  * @source is given by e_source_mail_signature_get_file().
846  *
847  * Returns: %TRUE on success, %FALSE on failure
848  *
849  * Since: 3.6
850  **/
851 gboolean
852 e_source_mail_signature_symlink_sync (ESource *source,
853                                       const gchar *symlink_target,
854                                       GCancellable *cancellable,
855                                       GError **error)
856 {
857         ESourceMailSignature *extension;
858         const gchar *extension_name;
859         GFile *file;
860
861         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
862         g_return_val_if_fail (symlink_target != NULL, FALSE);
863
864         extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
865         extension = e_source_get_extension (source, extension_name);
866         file = e_source_mail_signature_get_file (extension);
867
868         /* The file may not exist, so we don't care if this fails.
869          * If it fails for a different reason than G_IO_ERROR_NOT_FOUND
870          * then the next step will probably also fail and we'll capture
871          * THAT error. */
872         g_file_delete (file, cancellable, NULL);
873
874         return g_file_make_symbolic_link (
875                 file, symlink_target, cancellable, error);
876 }
877
878 /**
879  * e_source_mail_signature_symlink:
880  * @source: an #ESource
881  * @symlink_target: executable filename to link to
882  * @io_priority: the I/O priority of the request
883  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
884  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
885  *            is satisfied
886  * @user_data: (closure): data to pass to the callback function
887  *
888  * Asynchronously replaces the signature file for @source with a symbolic
889  * link to @symlink_target, which should be an executable file that prints
890  * a mail signature to standard output.  The signature file for @source
891  * is given by e_source_mail_signature_get_file().
892  *
893  * When the operation is finished, @callback will be called.  You can
894  * then call e_source_mail_signature_symlink_finish() to get the result
895  * of the operation.
896  *
897  * Since: 3.6
898  **/
899 void
900 e_source_mail_signature_symlink (ESource *source,
901                                  const gchar *symlink_target,
902                                  gint io_priority,
903                                  GCancellable *cancellable,
904                                  GAsyncReadyCallback callback,
905                                  gpointer user_data)
906 {
907         GSimpleAsyncResult *simple;
908         AsyncContext *async_context;
909
910         g_return_if_fail (E_IS_SOURCE (source));
911         g_return_if_fail (symlink_target != NULL);
912
913         async_context = g_slice_new0 (AsyncContext);
914         async_context->symlink_target = g_strdup (symlink_target);
915
916         simple = g_simple_async_result_new (
917                 G_OBJECT (source), callback, user_data,
918                 e_source_mail_signature_symlink);
919
920         g_simple_async_result_set_check_cancellable (simple, cancellable);
921
922         g_simple_async_result_set_op_res_gpointer (
923                 simple, async_context, (GDestroyNotify) async_context_free);
924
925         g_simple_async_result_run_in_thread (
926                 simple, source_mail_signature_symlink_thread,
927                 io_priority, cancellable);
928
929         g_object_unref (simple);
930 }
931
932 /**
933  * e_source_mail_signature_symlink_finish:
934  * @source: an #ESource
935  * @result: a #GAsyncResult
936  * @error: return location for a #GError, or %NULL
937  *
938  * Finishes an operation started with e_source_mail_signature_symlink().
939  *
940  * Returns: %TRUE on success, %FALSE on failure
941  *
942  * Since: 3.6
943  **/
944 gboolean
945 e_source_mail_signature_symlink_finish (ESource *source,
946                                         GAsyncResult *result,
947                                         GError **error)
948 {
949         GSimpleAsyncResult *simple;
950
951         g_return_val_if_fail (
952                 g_simple_async_result_is_valid (
953                 result, G_OBJECT (source),
954                 e_source_mail_signature_symlink), FALSE);
955
956         simple = G_SIMPLE_ASYNC_RESULT (result);
957
958         /* Assume success unless a GError is set. */
959         return !g_simple_async_result_propagate_error (simple, error);
960 }
961