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