1 /*
2  * e-mail-signature-script-dialog.c
3  *
4  * This program 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 program 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 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 program; if not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 #include "evolution-config.h"
19 
20 #include <glib/gi18n-lib.h>
21 
22 #include "e-mail-signature-script-dialog.h"
23 
24 #define E_MAIL_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE(obj) \
25 	(G_TYPE_INSTANCE_GET_PRIVATE \
26 	((obj), E_TYPE_MAIL_SIGNATURE_SCRIPT_DIALOG, \
27 	EMailSignatureScriptDialogPrivate))
28 
29 typedef struct _AsyncContext AsyncContext;
30 
31 struct _EMailSignatureScriptDialogPrivate {
32 	ESourceRegistry *registry;
33 	ESource *source;
34 
35 	GtkWidget *entry;		/* not referenced */
36 	GtkWidget *file_chooser;	/* not referenced */
37 	GtkWidget *alert;		/* not referenced */
38 
39 	gchar *symlink_target;
40 };
41 
42 struct _AsyncContext {
43 	ESource *source;
44 	GCancellable *cancellable;
45 	gchar *symlink_target;
46 };
47 
48 enum {
49 	PROP_0,
50 	PROP_REGISTRY,
51 	PROP_SOURCE,
52 	PROP_SYMLINK_TARGET
53 };
54 
G_DEFINE_TYPE(EMailSignatureScriptDialog,e_mail_signature_script_dialog,GTK_TYPE_DIALOG)55 G_DEFINE_TYPE (
56 	EMailSignatureScriptDialog,
57 	e_mail_signature_script_dialog,
58 	GTK_TYPE_DIALOG)
59 
60 static void
61 async_context_free (AsyncContext *async_context)
62 {
63 	if (async_context->source != NULL)
64 		g_object_unref (async_context->source);
65 
66 	if (async_context->cancellable != NULL)
67 		g_object_unref (async_context->cancellable);
68 
69 	g_free (async_context->symlink_target);
70 
71 	g_slice_free (AsyncContext, async_context);
72 }
73 
74 static gboolean
mail_signature_script_dialog_filter_cb(const GtkFileFilterInfo * filter_info)75 mail_signature_script_dialog_filter_cb (const GtkFileFilterInfo *filter_info)
76 {
77 	return g_file_test (filter_info->filename, G_FILE_TEST_IS_EXECUTABLE);
78 }
79 
80 static void
mail_signature_script_dialog_update_status(EMailSignatureScriptDialog * dialog)81 mail_signature_script_dialog_update_status (EMailSignatureScriptDialog *dialog)
82 {
83 	ESource *source;
84 	const gchar *display_name;
85 	const gchar *symlink_target;
86 	gboolean show_alert;
87 	gboolean sensitive;
88 
89 	source = e_mail_signature_script_dialog_get_source (dialog);
90 
91 	display_name = e_source_get_display_name (source);
92 	sensitive = (display_name != NULL && *display_name != '\0');
93 
94 	symlink_target =
95 		e_mail_signature_script_dialog_get_symlink_target (dialog);
96 
97 	if (symlink_target != NULL) {
98 		gboolean executable;
99 
100 		executable = g_file_test (
101 			symlink_target, G_FILE_TEST_IS_EXECUTABLE);
102 
103 		show_alert = !executable;
104 		sensitive &= executable;
105 	} else {
106 		sensitive = FALSE;
107 		show_alert = FALSE;
108 	}
109 
110 	if (show_alert)
111 		gtk_widget_show (dialog->priv->alert);
112 	else
113 		gtk_widget_hide (dialog->priv->alert);
114 
115 	gtk_dialog_set_response_sensitive (
116 		GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
117 }
118 
119 static void
mail_signature_script_dialog_file_set_cb(GtkFileChooserButton * button,EMailSignatureScriptDialog * dialog)120 mail_signature_script_dialog_file_set_cb (GtkFileChooserButton *button,
121                                           EMailSignatureScriptDialog *dialog)
122 {
123 	ESource *source;
124 	ESourceMailSignature *extension;
125 	GtkFileChooser *file_chooser;
126 	const gchar *extension_name;
127 	gchar *filename;
128 
129 	file_chooser = GTK_FILE_CHOOSER (button);
130 	filename = gtk_file_chooser_get_filename (file_chooser);
131 
132 	g_free (dialog->priv->symlink_target);
133 	dialog->priv->symlink_target = filename;  /* takes ownership */
134 
135 	/* Invalidate the saved MIME type. */
136 	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
137 	source = e_mail_signature_script_dialog_get_source (dialog);
138 	extension = e_source_get_extension (source, extension_name);
139 	e_source_mail_signature_set_mime_type (extension, NULL);
140 
141 	g_object_notify (G_OBJECT (dialog), "symlink-target");
142 
143 	mail_signature_script_dialog_update_status (dialog);
144 }
145 
146 static void
mail_signature_script_dialog_query_cb(GFile * file,GAsyncResult * result,EMailSignatureScriptDialog * dialog)147 mail_signature_script_dialog_query_cb (GFile *file,
148                                        GAsyncResult *result,
149                                        EMailSignatureScriptDialog *dialog)
150 {
151 	GFileInfo *file_info;
152 	const gchar *symlink_target;
153 	GError *error = NULL;
154 
155 	file_info = g_file_query_info_finish (file, result, &error);
156 
157 	/* Ignore cancellations. */
158 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
159 		g_warn_if_fail (file_info == NULL);
160 		g_object_unref (dialog);
161 		g_error_free (error);
162 		return;
163 
164 	} else if (error != NULL) {
165 		g_warn_if_fail (file_info == NULL);
166 		g_warning ("%s", error->message);
167 		g_object_unref (dialog);
168 		g_error_free (error);
169 		return;
170 	}
171 
172 	g_return_if_fail (G_IS_FILE_INFO (file_info));
173 
174 	symlink_target = g_file_info_get_symlink_target (file_info);
175 
176 	e_mail_signature_script_dialog_set_symlink_target (
177 		dialog, symlink_target);
178 
179 	g_object_unref (file_info);
180 	g_object_unref (dialog);
181 }
182 
183 static void
mail_signature_script_dialog_set_registry(EMailSignatureScriptDialog * dialog,ESourceRegistry * registry)184 mail_signature_script_dialog_set_registry (EMailSignatureScriptDialog *dialog,
185                                            ESourceRegistry *registry)
186 {
187 	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
188 	g_return_if_fail (dialog->priv->registry == NULL);
189 
190 	dialog->priv->registry = g_object_ref (registry);
191 }
192 
193 static void
mail_signature_script_dialog_set_source(EMailSignatureScriptDialog * dialog,ESource * source)194 mail_signature_script_dialog_set_source (EMailSignatureScriptDialog *dialog,
195                                          ESource *source)
196 {
197 	GDBusObject *dbus_object = NULL;
198 	const gchar *extension_name;
199 	GError *error = NULL;
200 
201 	g_return_if_fail (source == NULL || E_IS_SOURCE (source));
202 	g_return_if_fail (dialog->priv->source == NULL);
203 
204 	if (source != NULL)
205 		dbus_object = e_source_ref_dbus_object (source);
206 
207 	/* Clone the source so we can make changes to it freely. */
208 	dialog->priv->source = e_source_new (dbus_object, NULL, &error);
209 
210 	/* This should rarely fail.  If the file was loaded successfully
211 	 * once then it should load successfully here as well, unless an
212 	 * I/O error occurs. */
213 	if (error != NULL) {
214 		g_warning ("%s: %s", G_STRFUNC, error->message);
215 		g_error_free (error);
216 	}
217 
218 	/* Make sure the source has a mail signature extension. */
219 	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
220 	e_source_get_extension (dialog->priv->source, extension_name);
221 
222 	/* If we're editing an existing signature, query the symbolic
223 	 * link target of the signature file so we can initialize the
224 	 * file chooser button.  Note: The asynchronous callback will
225 	 * run after the dialog initialization is complete. */
226 	if (dbus_object != NULL) {
227 		ESourceMailSignature *extension;
228 		const gchar *extension_name;
229 		GFile *file;
230 
231 		extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
232 		extension = e_source_get_extension (source, extension_name);
233 		file = e_source_mail_signature_get_file (extension);
234 
235 		g_file_query_info_async (
236 			file, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
237 			G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
238 			NULL, (GAsyncReadyCallback)
239 			mail_signature_script_dialog_query_cb,
240 			g_object_ref (dialog));
241 
242 		g_object_unref (dbus_object);
243 	}
244 }
245 
246 static void
mail_signature_script_dialog_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)247 mail_signature_script_dialog_set_property (GObject *object,
248                                            guint property_id,
249                                            const GValue *value,
250                                            GParamSpec *pspec)
251 {
252 	switch (property_id) {
253 		case PROP_REGISTRY:
254 			mail_signature_script_dialog_set_registry (
255 				E_MAIL_SIGNATURE_SCRIPT_DIALOG (object),
256 				g_value_get_object (value));
257 			return;
258 
259 		case PROP_SOURCE:
260 			mail_signature_script_dialog_set_source (
261 				E_MAIL_SIGNATURE_SCRIPT_DIALOG (object),
262 				g_value_get_object (value));
263 			return;
264 
265 		case PROP_SYMLINK_TARGET:
266 			e_mail_signature_script_dialog_set_symlink_target (
267 				E_MAIL_SIGNATURE_SCRIPT_DIALOG (object),
268 				g_value_get_string (value));
269 			return;
270 	}
271 
272 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
273 }
274 
275 static void
mail_signature_script_dialog_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)276 mail_signature_script_dialog_get_property (GObject *object,
277                                            guint property_id,
278                                            GValue *value,
279                                            GParamSpec *pspec)
280 {
281 	switch (property_id) {
282 		case PROP_REGISTRY:
283 			g_value_set_object (
284 				value,
285 				e_mail_signature_script_dialog_get_registry (
286 				E_MAIL_SIGNATURE_SCRIPT_DIALOG (object)));
287 			return;
288 
289 		case PROP_SOURCE:
290 			g_value_set_object (
291 				value,
292 				e_mail_signature_script_dialog_get_source (
293 				E_MAIL_SIGNATURE_SCRIPT_DIALOG (object)));
294 			return;
295 
296 		case PROP_SYMLINK_TARGET:
297 			g_value_set_string (
298 				value,
299 				e_mail_signature_script_dialog_get_symlink_target (
300 				E_MAIL_SIGNATURE_SCRIPT_DIALOG (object)));
301 			return;
302 	}
303 
304 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
305 }
306 
307 static void
mail_signature_script_dialog_dispose(GObject * object)308 mail_signature_script_dialog_dispose (GObject *object)
309 {
310 	EMailSignatureScriptDialogPrivate *priv;
311 
312 	priv = E_MAIL_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (object);
313 	g_clear_object (&priv->registry);
314 	g_clear_object (&priv->source);
315 
316 	/* Chain up to parent's dispose() method. */
317 	G_OBJECT_CLASS (e_mail_signature_script_dialog_parent_class)->
318 		dispose (object);
319 }
320 
321 static void
mail_signature_script_dialog_finalize(GObject * object)322 mail_signature_script_dialog_finalize (GObject *object)
323 {
324 	EMailSignatureScriptDialogPrivate *priv;
325 
326 	priv = E_MAIL_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (object);
327 
328 	g_free (priv->symlink_target);
329 
330 	/* Chain up to parent's finalize() method. */
331 	G_OBJECT_CLASS (e_mail_signature_script_dialog_parent_class)->
332 		finalize (object);
333 }
334 
335 static void
mail_signature_script_dialog_constructed(GObject * object)336 mail_signature_script_dialog_constructed (GObject *object)
337 {
338 	EMailSignatureScriptDialog *dialog;
339 	GtkFileFilter *filter;
340 	GtkWidget *container;
341 	GtkWidget *widget;
342 	ESource *source;
343 	const gchar *display_name;
344 	gchar *markup;
345 
346 	/* Chain up to parent's constructed() method. */
347 	G_OBJECT_CLASS (e_mail_signature_script_dialog_parent_class)->constructed (object);
348 
349 	dialog = E_MAIL_SIGNATURE_SCRIPT_DIALOG (object);
350 
351 	source = e_mail_signature_script_dialog_get_source (dialog);
352 	display_name = e_source_get_display_name (source);
353 
354 	gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
355 
356 	gtk_dialog_add_button (
357 		GTK_DIALOG (dialog),
358 		_("_Cancel"), GTK_RESPONSE_CANCEL);
359 
360 	gtk_dialog_add_button (
361 		GTK_DIALOG (dialog),
362 		_("_Save"), GTK_RESPONSE_OK);
363 
364 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
365 
366 	container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
367 
368 	widget = gtk_table_new (4, 2, FALSE);
369 	gtk_table_set_col_spacings (GTK_TABLE (widget), 6);
370 	gtk_table_set_row_spacings (GTK_TABLE (widget), 6);
371 	gtk_table_set_row_spacing (GTK_TABLE (widget), 0, 12);
372 	gtk_container_set_border_width (GTK_CONTAINER (widget), 5);
373 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
374 	gtk_widget_show (widget);
375 
376 	container = widget;
377 
378 	widget = gtk_image_new_from_icon_name (
379 		"dialog-information", GTK_ICON_SIZE_DIALOG);
380 	gtk_table_attach (
381 		GTK_TABLE (container), widget,
382 		0, 1, 0, 1, 0, 0, 0, 0);
383 	gtk_widget_show (widget);
384 
385 	widget = gtk_label_new (_(
386 		"The output of this script will be used as your\n"
387 		"signature. The name you specify will be used\n"
388 		"for display purposes only."));
389 	gtk_table_attach (
390 		GTK_TABLE (container), widget,
391 		1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
392 	gtk_widget_show (widget);
393 
394 	widget = gtk_entry_new ();
395 	gtk_entry_set_text (GTK_ENTRY (widget), display_name);
396 	gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
397 	gtk_table_attach (
398 		GTK_TABLE (container), widget,
399 		1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
400 	dialog->priv->entry = widget;  /* not referenced */
401 	gtk_widget_show (widget);
402 
403 	e_binding_bind_property (
404 		widget, "text",
405 		source, "display-name",
406 		G_BINDING_DEFAULT);
407 
408 	widget = gtk_label_new_with_mnemonic (_("_Name:"));
409 	gtk_label_set_mnemonic_widget (
410 		GTK_LABEL (widget), dialog->priv->entry);
411 	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
412 	gtk_table_attach (
413 		GTK_TABLE (container), widget,
414 		0, 1, 1, 2, GTK_FILL, 0, 0, 0);
415 	gtk_widget_show (widget);
416 
417 	widget = gtk_file_chooser_button_new (
418 		NULL, GTK_FILE_CHOOSER_ACTION_OPEN);
419 	gtk_table_attach (
420 		GTK_TABLE (container), widget,
421 		1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
422 	dialog->priv->file_chooser = widget;  /* not referenced */
423 	gtk_widget_show (widget);
424 
425 	/* Restrict file selection to executable files. */
426 	filter = gtk_file_filter_new ();
427 	gtk_file_filter_add_custom (
428 		filter, GTK_FILE_FILTER_FILENAME,
429 		(GtkFileFilterFunc) mail_signature_script_dialog_filter_cb,
430 		NULL, NULL);
431 	gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), filter);
432 
433 	/* We create symbolic links to script files from the "signatures"
434 	 * directory, so restrict the selection to local files only. */
435 	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
436 
437 	widget = gtk_label_new_with_mnemonic (_("S_cript:"));
438 	gtk_label_set_mnemonic_widget (
439 		GTK_LABEL (widget), dialog->priv->file_chooser);
440 	gtk_table_attach (
441 		GTK_TABLE (container), widget,
442 		0, 1, 2, 3, GTK_FILL, 0, 0, 0);
443 	gtk_widget_show (widget);
444 
445 	/* This is just a placeholder. */
446 	widget = gtk_label_new (NULL);
447 	gtk_table_attach (
448 		GTK_TABLE (container), widget,
449 		0, 1, 3, 4, GTK_FILL, 0, 0, 0);
450 	gtk_widget_show (widget);
451 
452 	widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
453 	gtk_table_attach (
454 		GTK_TABLE (container), widget,
455 		1, 2, 3, 4, 0, 0, 0, 0);
456 	dialog->priv->alert = widget;  /* not referenced */
457 	gtk_widget_show (widget);
458 
459 	container = widget;
460 
461 	widget = gtk_image_new_from_icon_name (
462 		"dialog-warning", GTK_ICON_SIZE_MENU);
463 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
464 	gtk_widget_show (widget);
465 
466 	markup = g_markup_printf_escaped (
467 		"<small>%s</small>",
468 		_("Script file must be executable."));
469 	widget = gtk_label_new (markup);
470 	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
471 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
472 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
473 	gtk_widget_show (widget);
474 	g_free (markup);
475 
476 	g_signal_connect (
477 		dialog->priv->file_chooser, "file-set",
478 		G_CALLBACK (mail_signature_script_dialog_file_set_cb), dialog);
479 
480 	g_signal_connect_swapped (
481 		dialog->priv->entry, "changed",
482 		G_CALLBACK (mail_signature_script_dialog_update_status), dialog);
483 
484 	mail_signature_script_dialog_update_status (dialog);
485 }
486 
487 static void
e_mail_signature_script_dialog_class_init(EMailSignatureScriptDialogClass * class)488 e_mail_signature_script_dialog_class_init (EMailSignatureScriptDialogClass *class)
489 {
490 	GObjectClass *object_class;
491 
492 	g_type_class_add_private (
493 		class, sizeof (EMailSignatureScriptDialogPrivate));
494 
495 	object_class = G_OBJECT_CLASS (class);
496 	object_class->set_property = mail_signature_script_dialog_set_property;
497 	object_class->get_property = mail_signature_script_dialog_get_property;
498 	object_class->dispose = mail_signature_script_dialog_dispose;
499 	object_class->finalize = mail_signature_script_dialog_finalize;
500 	object_class->constructed = mail_signature_script_dialog_constructed;
501 
502 	g_object_class_install_property (
503 		object_class,
504 		PROP_REGISTRY,
505 		g_param_spec_object (
506 			"registry",
507 			"Registry",
508 			"Data source registry",
509 			E_TYPE_SOURCE_REGISTRY,
510 			G_PARAM_READWRITE |
511 			G_PARAM_CONSTRUCT_ONLY |
512 			G_PARAM_STATIC_STRINGS));
513 
514 	g_object_class_install_property (
515 		object_class,
516 		PROP_SOURCE,
517 		g_param_spec_object (
518 			"source",
519 			"Source",
520 			NULL,
521 			E_TYPE_SOURCE,
522 			G_PARAM_READWRITE |
523 			G_PARAM_CONSTRUCT_ONLY |
524 			G_PARAM_STATIC_STRINGS));
525 
526 	g_object_class_install_property (
527 		object_class,
528 		PROP_SYMLINK_TARGET,
529 		g_param_spec_string (
530 			"symlink-target",
531 			"Symlink Target",
532 			NULL,
533 			NULL,
534 			G_PARAM_READWRITE |
535 			G_PARAM_STATIC_STRINGS));
536 }
537 
538 static void
e_mail_signature_script_dialog_init(EMailSignatureScriptDialog * dialog)539 e_mail_signature_script_dialog_init (EMailSignatureScriptDialog *dialog)
540 {
541 	dialog->priv = E_MAIL_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (dialog);
542 }
543 
544 GtkWidget *
e_mail_signature_script_dialog_new(ESourceRegistry * registry,GtkWindow * parent,ESource * source)545 e_mail_signature_script_dialog_new (ESourceRegistry *registry,
546                                     GtkWindow *parent,
547                                     ESource *source)
548 {
549 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
550 
551 	if (source != NULL)
552 		g_return_val_if_fail (E_IS_SOURCE (source), NULL);
553 
554 	return g_object_new (
555 		E_TYPE_MAIL_SIGNATURE_SCRIPT_DIALOG,
556 		"registry", registry,
557 		"transient-for", parent,
558 		"source", source, NULL);
559 }
560 
561 ESourceRegistry *
e_mail_signature_script_dialog_get_registry(EMailSignatureScriptDialog * dialog)562 e_mail_signature_script_dialog_get_registry (EMailSignatureScriptDialog *dialog)
563 {
564 	g_return_val_if_fail (
565 		E_IS_MAIL_SIGNATURE_SCRIPT_DIALOG (dialog), NULL);
566 
567 	return dialog->priv->registry;
568 }
569 
570 ESource *
e_mail_signature_script_dialog_get_source(EMailSignatureScriptDialog * dialog)571 e_mail_signature_script_dialog_get_source (EMailSignatureScriptDialog *dialog)
572 {
573 	g_return_val_if_fail (
574 		E_IS_MAIL_SIGNATURE_SCRIPT_DIALOG (dialog), NULL);
575 
576 	return dialog->priv->source;
577 }
578 
579 const gchar *
e_mail_signature_script_dialog_get_symlink_target(EMailSignatureScriptDialog * dialog)580 e_mail_signature_script_dialog_get_symlink_target (EMailSignatureScriptDialog *dialog)
581 {
582 	g_return_val_if_fail (
583 		E_IS_MAIL_SIGNATURE_SCRIPT_DIALOG (dialog), NULL);
584 
585 	return dialog->priv->symlink_target;
586 }
587 
588 void
e_mail_signature_script_dialog_set_symlink_target(EMailSignatureScriptDialog * dialog,const gchar * symlink_target)589 e_mail_signature_script_dialog_set_symlink_target (EMailSignatureScriptDialog *dialog,
590                                                    const gchar *symlink_target)
591 {
592 	GtkFileChooser *file_chooser;
593 
594 	g_return_if_fail (E_IS_MAIL_SIGNATURE_SCRIPT_DIALOG (dialog));
595 	g_return_if_fail (symlink_target != NULL);
596 
597 	g_free (dialog->priv->symlink_target);
598 	dialog->priv->symlink_target = g_strdup (symlink_target);
599 
600 	file_chooser = GTK_FILE_CHOOSER (dialog->priv->file_chooser);
601 	gtk_file_chooser_set_filename (file_chooser, symlink_target);
602 
603 	g_object_notify (G_OBJECT (dialog), "symlink-target");
604 
605 	mail_signature_script_dialog_update_status (dialog);
606 }
607 
608 /****************** e_mail_signature_script_dialog_commit() ******************/
609 
610 static void
mail_signature_script_dialog_symlink_cb(GObject * object,GAsyncResult * result,gpointer user_data)611 mail_signature_script_dialog_symlink_cb (GObject *object,
612                                          GAsyncResult *result,
613                                          gpointer user_data)
614 {
615 	GSimpleAsyncResult *simple;
616 	GError *error = NULL;
617 
618 	simple = G_SIMPLE_ASYNC_RESULT (user_data);
619 
620 	e_source_mail_signature_symlink_finish (
621 		E_SOURCE (object), result, &error);
622 
623 	if (error != NULL)
624 		g_simple_async_result_take_error (simple, error);
625 
626 	g_simple_async_result_complete (simple);
627 
628 	g_object_unref (simple);
629 }
630 
631 static void
mail_signature_script_dialog_commit_cb(GObject * object,GAsyncResult * result,gpointer user_data)632 mail_signature_script_dialog_commit_cb (GObject *object,
633                                         GAsyncResult *result,
634                                         gpointer user_data)
635 {
636 	GSimpleAsyncResult *simple;
637 	AsyncContext *async_context;
638 	GError *error = NULL;
639 
640 	simple = G_SIMPLE_ASYNC_RESULT (user_data);
641 	async_context = g_simple_async_result_get_op_res_gpointer (simple);
642 
643 	e_source_registry_commit_source_finish (
644 		E_SOURCE_REGISTRY (object), result, &error);
645 
646 	if (error != NULL) {
647 		g_simple_async_result_take_error (simple, error);
648 		g_simple_async_result_complete (simple);
649 		g_object_unref (simple);
650 		return;
651 	}
652 
653 	/* We can call this on our scratch source because only its UID is
654 	 * really needed, which even a new scratch source already knows. */
655 	e_source_mail_signature_symlink (
656 		async_context->source,
657 		async_context->symlink_target,
658 		G_PRIORITY_DEFAULT,
659 		async_context->cancellable,
660 		mail_signature_script_dialog_symlink_cb,
661 		simple);
662 }
663 
664 void
e_mail_signature_script_dialog_commit(EMailSignatureScriptDialog * dialog,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)665 e_mail_signature_script_dialog_commit (EMailSignatureScriptDialog *dialog,
666                                        GCancellable *cancellable,
667                                        GAsyncReadyCallback callback,
668                                        gpointer user_data)
669 {
670 	GSimpleAsyncResult *simple;
671 	AsyncContext *async_context;
672 	ESourceRegistry *registry;
673 	ESource *source;
674 	const gchar *symlink_target;
675 
676 	g_return_if_fail (E_IS_MAIL_SIGNATURE_SCRIPT_DIALOG (dialog));
677 
678 	registry = e_mail_signature_script_dialog_get_registry (dialog);
679 	source = e_mail_signature_script_dialog_get_source (dialog);
680 
681 	symlink_target =
682 		e_mail_signature_script_dialog_get_symlink_target (dialog);
683 
684 	async_context = g_slice_new0 (AsyncContext);
685 	async_context->source = g_object_ref (source);
686 	async_context->symlink_target = g_strdup (symlink_target);
687 
688 	if (G_IS_CANCELLABLE (cancellable))
689 		async_context->cancellable = g_object_ref (cancellable);
690 
691 	simple = g_simple_async_result_new (
692 		G_OBJECT (dialog), callback, user_data,
693 		e_mail_signature_script_dialog_commit);
694 
695 	g_simple_async_result_set_op_res_gpointer (
696 		simple, async_context, (GDestroyNotify) async_context_free);
697 
698 	e_source_registry_commit_source (
699 		registry, source,
700 		async_context->cancellable,
701 		mail_signature_script_dialog_commit_cb,
702 		simple);
703 }
704 
705 gboolean
e_mail_signature_script_dialog_commit_finish(EMailSignatureScriptDialog * dialog,GAsyncResult * result,GError ** error)706 e_mail_signature_script_dialog_commit_finish (EMailSignatureScriptDialog *dialog,
707                                               GAsyncResult *result,
708                                               GError **error)
709 {
710 	GSimpleAsyncResult *simple;
711 
712 	g_return_val_if_fail (
713 		g_simple_async_result_is_valid (
714 		result, G_OBJECT (dialog),
715 		e_mail_signature_script_dialog_commit), FALSE);
716 
717 	simple = G_SIMPLE_ASYNC_RESULT (result);
718 
719 	/* Assume success unless a GError is set. */
720 	return !g_simple_async_result_propagate_error (simple, error);
721 }
722 
723