Branch data Line data Source code
1 : : /*
2 : : * gnome-keyring
3 : : *
4 : : * Copyright (C) 2011 Stefan Walter
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU Lesser General Public License as
8 : : * published by the Free Software Foundation; either version 2.1 of
9 : : * the License, or (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful, but
12 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Author: Stef Walter <stef@thewalter.net>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include "gcr-dbus-constants.h"
25 : : #include "gcr-internal.h"
26 : : #include "gcr-library.h"
27 : : #include "gcr-prompt.h"
28 : : #include "gcr-secret-exchange.h"
29 : : #include "gcr-system-prompt.h"
30 : :
31 : : #include "gcr/gcr-dbus-generated.h"
32 : :
33 : : #include "egg/egg-error.h"
34 : :
35 : : #include <glib/gi18n.h>
36 : :
37 : : /**
38 : : * GcrSystemPrompt:
39 : : *
40 : : * A [iface@Prompt] implementation which calls to the system prompter to
41 : : * display prompts in a system modal fashion.
42 : : *
43 : : * Since the system prompter usually only displays one prompt at a time, you
44 : : * may have to wait for the prompt to be displayed. Use [func@SystemPrompt.open]
45 : : * or a related function to open a prompt. Since this can take a long time, you
46 : : * should always check that the prompt is still needed after it is opened. A
47 : : * previous prompt may have already provided the information needed and you
48 : : * may no longer need to prompt.
49 : : *
50 : : * Use [method@SystemPrompt.close] to close the prompt when you're done with it.
51 : : */
52 : :
53 : : /**
54 : : * GCR_SYSTEM_PROMPT_ERROR:
55 : : *
56 : : * The domain for errors returned from GcrSystemPrompt methods.
57 : : */
58 : :
59 : : /**
60 : : * GcrSystemPromptError:
61 : : * @GCR_SYSTEM_PROMPT_IN_PROGRESS: another prompt is already in progress
62 : : *
63 : : * No error returned by the #GcrSystemPrompt is suitable for display or
64 : : * to the user.
65 : : *
66 : : * If the system prompter can only show one prompt at a time, and there is
67 : : * already a prompt being displayed, and the timeout waiting to open the
68 : : * prompt expires, then %GCR_SYSTEM_PROMPT_IN_PROGRESS is returned.
69 : : */
70 : :
71 : : enum {
72 : : PROP_0,
73 : : PROP_BUS_NAME,
74 : : PROP_SECRET_EXCHANGE,
75 : : PROP_TIMEOUT_SECONDS,
76 : :
77 : : PROP_TITLE,
78 : : PROP_MESSAGE,
79 : : PROP_DESCRIPTION,
80 : : PROP_WARNING,
81 : : PROP_PASSWORD_NEW,
82 : : PROP_PASSWORD_STRENGTH,
83 : : PROP_CHOICE_LABEL,
84 : : PROP_CHOICE_CHOSEN,
85 : : PROP_CALLER_WINDOW,
86 : : PROP_CONTINUE_LABEL,
87 : : PROP_CANCEL_LABEL
88 : : };
89 : :
90 : : struct _GcrSystemPromptPrivate {
91 : : gchar *prompter_bus_name;
92 : : GcrSecretExchange *exchange;
93 : : gboolean received;
94 : : GHashTable *properties;
95 : : GHashTable *dirty_properties;
96 : : gint timeout_seconds;
97 : :
98 : : GDBusConnection *connection;
99 : : gboolean begun_prompting;
100 : : gboolean closed;
101 : : guint prompt_registered;
102 : : gchar *prompt_path;
103 : : gchar *prompt_owner;
104 : :
105 : : GSimpleAsyncResult *pending;
106 : : gchar *last_response;
107 : : };
108 : :
109 : : static void gcr_system_prompt_prompt_iface (GcrPromptInterface *iface);
110 : :
111 : : static void gcr_system_prompt_initable_iface (GInitableIface *iface);
112 : :
113 : : static void gcr_system_prompt_async_initable_iface (GAsyncInitableIface *iface);
114 : :
115 : : static void perform_init_async (GcrSystemPrompt *self,
116 : : GSimpleAsyncResult *res);
117 : :
118 [ + + + - : 1009 : G_DEFINE_TYPE_WITH_CODE (GcrSystemPrompt, gcr_system_prompt, G_TYPE_OBJECT,
+ + ]
119 : : G_ADD_PRIVATE (GcrSystemPrompt);
120 : : G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, gcr_system_prompt_prompt_iface);
121 : : G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gcr_system_prompt_initable_iface);
122 : : G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, gcr_system_prompt_async_initable_iface);
123 : : );
124 : :
125 : : static gint unique_prompt_id = 0;
126 : :
127 : : typedef struct {
128 : : GSource *timeout;
129 : : GSource *waiting;
130 : : GMainContext *context;
131 : : GCancellable *cancellable;
132 : : guint watch_id;
133 : : } CallClosure;
134 : :
135 : : static void
136 : 43 : call_closure_free (gpointer data)
137 : : {
138 : 43 : CallClosure *closure = data;
139 [ + + ]: 43 : if (closure->timeout) {
140 : 4 : g_source_destroy (closure->timeout);
141 : 4 : g_source_unref (closure->timeout);
142 : : }
143 [ + + ]: 43 : if (closure->waiting) {
144 : 31 : g_source_destroy (closure->waiting);
145 : 31 : g_source_unref (closure->waiting);
146 : : }
147 [ + + ]: 43 : if (closure->watch_id)
148 : 34 : g_bus_unwatch_name (closure->watch_id);
149 : 43 : g_object_unref (closure->cancellable);
150 : 43 : g_free (data);
151 : 43 : }
152 : :
153 : : static void
154 : 0 : on_propagate_cancelled (GCancellable *cancellable,
155 : : gpointer user_data)
156 : : {
157 : : /* Propagate the cancelled signal */
158 : 0 : GCancellable *cancel = G_CANCELLABLE (user_data);
159 : 0 : g_cancellable_cancel (cancel);
160 : 0 : }
161 : :
162 : : static CallClosure *
163 : 47 : call_closure_new (GCancellable *cancellable)
164 : : {
165 : : CallClosure *call;
166 : :
167 : : /*
168 : : * We use our own cancellable object, since we cancel it it in
169 : : * situations other than when the caller cancels.
170 : : */
171 : :
172 : 47 : call = g_new0 (CallClosure, 1);
173 : 47 : call->cancellable = g_cancellable_new ();
174 : :
175 [ - + ]: 47 : if (cancellable) {
176 : 0 : g_cancellable_connect (cancellable, G_CALLBACK (on_propagate_cancelled),
177 : 0 : g_object_ref (call->cancellable), g_object_unref);
178 : : }
179 : :
180 : 47 : return call;
181 : : }
182 : :
183 : : static void
184 : 22 : gcr_system_prompt_init (GcrSystemPrompt *self)
185 : : {
186 : 22 : self->pv = gcr_system_prompt_get_instance_private (self);
187 : :
188 : 22 : self->pv->timeout_seconds = -1;
189 : 22 : self->pv->properties = g_hash_table_new_full (g_direct_hash, g_direct_equal,
190 : : NULL, (GDestroyNotify)g_variant_unref);
191 : 22 : self->pv->dirty_properties = g_hash_table_new (g_direct_hash, g_direct_equal);
192 : 22 : }
193 : :
194 : : static const gchar *
195 : 32 : prompt_get_string_property (GcrSystemPrompt *self,
196 : : const gchar *property_name,
197 : : gboolean collapse_empty_to_null)
198 : : {
199 : 32 : const gchar *value = NULL;
200 : : GVariant *variant;
201 : : gconstpointer key;
202 : :
203 [ - + + - : 32 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL);
+ - - + ]
204 : :
205 : 32 : key = g_intern_string (property_name);
206 : 32 : variant = g_hash_table_lookup (self->pv->properties, key);
207 [ + - ]: 32 : if (variant != NULL) {
208 : 32 : value = g_variant_get_string (variant, NULL);
209 [ + + + - : 32 : if (collapse_empty_to_null && value != NULL && value[0] == '\0')
+ + ]
210 : 6 : value = NULL;
211 : : }
212 : :
213 : 32 : return value;
214 : : }
215 : :
216 : : static void
217 : 208 : prompt_set_string_property (GcrSystemPrompt *self,
218 : : const gchar *property_name,
219 : : const gchar *value)
220 : : {
221 : : GVariant *variant;
222 : : gpointer key;
223 : :
224 [ - + + - : 208 : g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
+ - - + ]
225 : :
226 : 208 : key = (gpointer)g_intern_string (property_name);
227 [ + + ]: 208 : variant = g_variant_ref_sink (g_variant_new_string (value ? value : ""));
228 : 208 : g_hash_table_insert (self->pv->properties, key, variant);
229 : 208 : g_hash_table_insert (self->pv->dirty_properties, key, key);
230 : 208 : g_object_notify (G_OBJECT (self), property_name);
231 : : }
232 : :
233 : : static gint
234 : 3 : prompt_get_int_property (GcrSystemPrompt *self,
235 : : const gchar *property_name)
236 : : {
237 : : GVariant *variant;
238 : : gconstpointer key;
239 : :
240 [ - + + - : 3 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), 0);
+ - - + ]
241 : :
242 : 3 : key = g_intern_string (property_name);
243 : 3 : variant = g_hash_table_lookup (self->pv->properties, key);
244 [ - + ]: 3 : if (variant != NULL)
245 : 0 : return g_variant_get_int32 (variant);
246 : :
247 : 3 : return 0;
248 : : }
249 : :
250 : : static gboolean
251 : 9 : prompt_get_boolean_property (GcrSystemPrompt *self,
252 : : const gchar *property_name)
253 : : {
254 : : GVariant *variant;
255 : : gconstpointer key;
256 : :
257 [ - + + - : 9 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
+ - - + ]
258 : :
259 : 9 : key = g_intern_string (property_name);
260 : 9 : variant = g_hash_table_lookup (self->pv->properties, key);
261 [ + + ]: 9 : if (variant != NULL)
262 : 7 : return g_variant_get_boolean (variant);
263 : :
264 : 2 : return FALSE;
265 : : }
266 : :
267 : : static void
268 : 8 : prompt_set_boolean_property (GcrSystemPrompt *self,
269 : : const gchar *property_name,
270 : : gboolean value)
271 : : {
272 : : GVariant *variant;
273 : : gpointer key;
274 : :
275 [ - + + - : 8 : g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
+ - - + ]
276 : :
277 : 8 : key = (gpointer)g_intern_string (property_name);
278 : 8 : variant = g_variant_ref_sink (g_variant_new_boolean (value));
279 : 8 : g_hash_table_insert (self->pv->properties, key, variant);
280 : 8 : g_hash_table_insert (self->pv->dirty_properties, key, key);
281 : 8 : g_object_notify (G_OBJECT (self), property_name);
282 : : }
283 : :
284 : : static void
285 : 261 : gcr_system_prompt_set_property (GObject *obj,
286 : : guint prop_id,
287 : : const GValue *value,
288 : : GParamSpec *pspec)
289 : : {
290 : 261 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
291 : :
292 [ + + + + : 261 : switch (prop_id) {
+ + + + +
+ + + +
- ]
293 : 22 : case PROP_BUS_NAME:
294 [ - + ]: 22 : g_assert (self->pv->prompter_bus_name == NULL);
295 : 22 : self->pv->prompter_bus_name = g_value_dup_string (value);
296 : 22 : break;
297 : 1 : case PROP_SECRET_EXCHANGE:
298 [ - + ]: 1 : if (self->pv->exchange) {
299 : 0 : g_warning ("The secret exchange is already in use, and cannot be changed");
300 : 0 : return;
301 : : }
302 : 1 : self->pv->exchange = g_value_dup_object (value);
303 : 1 : g_object_notify (G_OBJECT (self), "secret-exchange");
304 : 1 : break;
305 : 22 : case PROP_TIMEOUT_SECONDS:
306 : 22 : self->pv->timeout_seconds = g_value_get_int (value);
307 : 22 : break;
308 : 26 : case PROP_TITLE:
309 : 26 : prompt_set_string_property (self, "title", g_value_get_string (value));
310 : 26 : break;
311 : 26 : case PROP_MESSAGE:
312 : 26 : prompt_set_string_property (self, "message", g_value_get_string (value));
313 : 26 : break;
314 : 26 : case PROP_DESCRIPTION:
315 : 26 : prompt_set_string_property (self, "description", g_value_get_string (value));
316 : 26 : break;
317 : 26 : case PROP_WARNING:
318 : 26 : prompt_set_string_property (self, "warning", g_value_get_string (value));
319 : 26 : break;
320 : 4 : case PROP_PASSWORD_NEW:
321 : 4 : prompt_set_boolean_property (self, "password-new", g_value_get_boolean (value));
322 : 4 : break;
323 : 26 : case PROP_CHOICE_LABEL:
324 : 26 : prompt_set_string_property (self, "choice-label", g_value_get_string (value));
325 : 26 : break;
326 : 4 : case PROP_CHOICE_CHOSEN:
327 : 4 : prompt_set_boolean_property (self, "choice-chosen", g_value_get_boolean (value));
328 : 4 : break;
329 : 26 : case PROP_CALLER_WINDOW:
330 : 26 : prompt_set_string_property (self, "caller-window", g_value_get_string (value));
331 : 26 : break;
332 : 26 : case PROP_CONTINUE_LABEL:
333 : 26 : prompt_set_string_property (self, "continue-label", g_value_get_string (value));
334 : 26 : break;
335 : 26 : case PROP_CANCEL_LABEL:
336 : 26 : prompt_set_string_property (self, "cancel-label", g_value_get_string (value));
337 : 26 : break;
338 : 0 : default:
339 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
340 : 0 : break;
341 : : }
342 : : }
343 : :
344 : : static void
345 : 46 : gcr_system_prompt_get_property (GObject *obj,
346 : : guint prop_id,
347 : : GValue *value,
348 : : GParamSpec *pspec)
349 : : {
350 : 46 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
351 : :
352 [ + + + + : 46 : switch (prop_id) {
+ + + + +
+ + + +
- ]
353 : 1 : case PROP_BUS_NAME:
354 : 1 : g_value_set_string (value, self->pv->prompter_bus_name);
355 : 1 : break;
356 : 1 : case PROP_SECRET_EXCHANGE:
357 : 1 : g_value_set_object (value, gcr_system_prompt_get_secret_exchange (self));
358 : 1 : break;
359 : 4 : case PROP_TITLE:
360 : 4 : g_value_set_string (value, prompt_get_string_property (self, "title", FALSE));
361 : 4 : break;
362 : 4 : case PROP_MESSAGE:
363 : 4 : g_value_set_string (value, prompt_get_string_property (self, "message", FALSE));
364 : 4 : break;
365 : 4 : case PROP_DESCRIPTION:
366 : 4 : g_value_set_string (value, prompt_get_string_property (self, "description", FALSE));
367 : 4 : break;
368 : 4 : case PROP_WARNING:
369 : 4 : g_value_set_string (value, prompt_get_string_property (self, "warning", TRUE));
370 : 4 : break;
371 : 4 : case PROP_PASSWORD_NEW:
372 : 4 : g_value_set_boolean (value, prompt_get_boolean_property (self, "password-new"));
373 : 4 : break;
374 : 3 : case PROP_PASSWORD_STRENGTH:
375 : 3 : g_value_set_int (value, prompt_get_int_property (self, "password-strength"));
376 : 3 : break;
377 : 4 : case PROP_CHOICE_LABEL:
378 : 4 : g_value_set_string (value, prompt_get_string_property (self, "choice-label", TRUE));
379 : 4 : break;
380 : 5 : case PROP_CHOICE_CHOSEN:
381 : 5 : g_value_set_boolean (value, prompt_get_boolean_property (self, "choice-chosen"));
382 : 5 : break;
383 : 4 : case PROP_CALLER_WINDOW:
384 : 4 : g_value_set_string (value, prompt_get_string_property (self, "caller-window", TRUE));
385 : 4 : break;
386 : 4 : case PROP_CONTINUE_LABEL:
387 : 4 : g_value_set_string (value, prompt_get_string_property (self, "continue-label", TRUE));
388 : 4 : break;
389 : 4 : case PROP_CANCEL_LABEL:
390 : 4 : g_value_set_string (value, prompt_get_string_property (self, "cancel-label", TRUE));
391 : 4 : break;
392 : 0 : default:
393 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
394 : 0 : break;
395 : : }
396 : 46 : }
397 : :
398 : : static void
399 : 22 : gcr_system_prompt_constructed (GObject *obj)
400 : : {
401 : 22 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
402 : : gint seed;
403 : :
404 : 22 : G_OBJECT_CLASS (gcr_system_prompt_parent_class)->constructed (obj);
405 : :
406 : 22 : seed = g_atomic_int_add (&unique_prompt_id, 1);
407 : :
408 : 22 : self->pv->prompt_path = g_strdup_printf ("%s/p%d", GCR_DBUS_PROMPT_OBJECT_PREFIX, seed);
409 : :
410 [ - + ]: 22 : if (self->pv->prompter_bus_name == NULL)
411 : 0 : self->pv->prompter_bus_name = g_strdup (GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME);
412 : 22 : }
413 : :
414 : : static void
415 : 16 : on_prompter_stop_prompting (GObject *source,
416 : : GAsyncResult *result,
417 : : gpointer user_data)
418 : : {
419 : 16 : GSimpleAsyncResult *async = NULL;
420 : 16 : GError *error = NULL;
421 : : GVariant *retval;
422 : :
423 : 16 : retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
424 [ + + ]: 16 : if (error != NULL) {
425 : 13 : g_debug ("failed to stop prompting: %s", egg_error_message (error));
426 : 13 : g_clear_error (&error);
427 : : }
428 : :
429 [ + + ]: 16 : if (retval)
430 : 3 : g_variant_unref (retval);
431 : :
432 [ + + ]: 16 : if (user_data) {
433 : 3 : async = G_SIMPLE_ASYNC_RESULT (user_data);
434 : 3 : g_simple_async_result_complete (async);
435 : 3 : g_object_unref (async);
436 : : }
437 : 16 : }
438 : :
439 : : static void
440 : 29 : perform_close (GcrSystemPrompt *self,
441 : : GSimpleAsyncResult *async,
442 : : GCancellable *cancellable)
443 : : {
444 : : GSimpleAsyncResult *res;
445 : : CallClosure *closure;
446 : 29 : gboolean called = FALSE;
447 : : gboolean closed;
448 : :
449 : 29 : closed = self->pv->closed;
450 : 29 : self->pv->closed = TRUE;
451 : :
452 [ + + ]: 29 : if (!closed)
453 : 21 : g_debug ("closing prompt");
454 : :
455 [ + + ]: 29 : if (self->pv->pending) {
456 : 5 : res = g_object_ref (self->pv->pending);
457 [ + - ]: 5 : g_clear_object (&self->pv->pending);
458 : 5 : closure = g_simple_async_result_get_op_res_gpointer (res);
459 : 5 : g_cancellable_cancel (closure->cancellable);
460 : 5 : g_simple_async_result_complete_in_idle (res);
461 : 5 : g_object_unref (res);
462 : : }
463 : :
464 [ + + ]: 29 : if (self->pv->prompt_registered) {
465 : 22 : g_dbus_connection_unregister_object (self->pv->connection,
466 : 22 : self->pv->prompt_registered);
467 : 22 : self->pv->prompt_registered = 0;
468 : : }
469 : :
470 [ + + ]: 29 : if (self->pv->begun_prompting) {
471 [ + - + - : 20 : if (self->pv->connection && self->pv->prompt_path && self->pv->prompt_owner) {
+ + ]
472 : 18 : g_debug ("Calling the prompter %s method", GCR_DBUS_PROMPTER_METHOD_STOP);
473 [ + + ]: 23 : g_dbus_connection_call (self->pv->connection,
474 : 18 : self->pv->prompter_bus_name,
475 : : GCR_DBUS_PROMPTER_OBJECT_PATH,
476 : : GCR_DBUS_PROMPTER_INTERFACE,
477 : : GCR_DBUS_PROMPTER_METHOD_STOP,
478 : 18 : g_variant_new ("(o)", self->pv->prompt_path),
479 : : G_VARIANT_TYPE ("()"),
480 : : G_DBUS_CALL_FLAGS_NO_AUTO_START,
481 : : -1, cancellable,
482 : : on_prompter_stop_prompting,
483 : 5 : async ? g_object_ref (async) : NULL);
484 : 18 : called = TRUE;
485 : : }
486 : 20 : self->pv->begun_prompting = FALSE;
487 : : }
488 : :
489 : 29 : g_free (self->pv->prompt_path);
490 : 29 : self->pv->prompt_path = NULL;
491 : :
492 [ + + ]: 29 : g_clear_object (&self->pv->connection);
493 : :
494 [ + + + + ]: 29 : if (!called && async)
495 : 2 : g_simple_async_result_complete_in_idle (async);
496 : :
497 : : /* Emit the signal if necessary, after closed */
498 [ + + ]: 29 : if (!closed)
499 : 21 : gcr_prompt_close (GCR_PROMPT (self));
500 : 29 : }
501 : :
502 : : static void
503 : 20 : gcr_system_prompt_dispose (GObject *obj)
504 : : {
505 : 20 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
506 : :
507 [ + + ]: 20 : g_clear_object (&self->pv->exchange);
508 : 20 : perform_close (self, NULL, NULL);
509 : :
510 : 20 : g_hash_table_remove_all (self->pv->properties);
511 : 20 : g_hash_table_remove_all (self->pv->dirty_properties);
512 : :
513 : 20 : G_OBJECT_CLASS (gcr_system_prompt_parent_class)->dispose (obj);
514 : 20 : }
515 : :
516 : : static void
517 : 20 : gcr_system_prompt_finalize (GObject *obj)
518 : : {
519 : 20 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
520 : :
521 : 20 : g_free (self->pv->prompter_bus_name);
522 : 20 : g_free (self->pv->prompt_owner);
523 : 20 : g_free (self->pv->last_response);
524 : 20 : g_hash_table_destroy (self->pv->properties);
525 : 20 : g_hash_table_destroy (self->pv->dirty_properties);
526 : :
527 : 20 : G_OBJECT_CLASS (gcr_system_prompt_parent_class)->finalize (obj);
528 : 20 : }
529 : :
530 : : static void
531 : 1 : gcr_system_prompt_class_init (GcrSystemPromptClass *klass)
532 : : {
533 : 1 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
534 : :
535 : 1 : gobject_class->constructed = gcr_system_prompt_constructed;
536 : 1 : gobject_class->get_property = gcr_system_prompt_get_property;
537 : 1 : gobject_class->set_property = gcr_system_prompt_set_property;
538 : 1 : gobject_class->dispose = gcr_system_prompt_dispose;
539 : 1 : gobject_class->finalize = gcr_system_prompt_finalize;
540 : :
541 : : /**
542 : : * GcrSystemPrompt:bus-name:
543 : : *
544 : : * The DBus bus name of the prompter to use for prompting, or %NULL
545 : : * for the default prompter.
546 : : */
547 : 1 : g_object_class_install_property (gobject_class, PROP_BUS_NAME,
548 : : g_param_spec_string ("bus-name", "Bus name", "Prompter bus name",
549 : : NULL,
550 : : G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
551 : :
552 : : /**
553 : : * GcrSystemPrompt:timeout-seconds:
554 : : *
555 : : * The timeout in seconds to wait when opening the prompt.
556 : : */
557 : 1 : g_object_class_install_property (gobject_class, PROP_TIMEOUT_SECONDS,
558 : : g_param_spec_int ("timeout-seconds", "Timeout seconds", "Timeout (in seconds) for opening prompt",
559 : : -1, G_MAXINT, -1,
560 : : G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
561 : :
562 : : /**
563 : : * GcrSystemPrompt:secret-exchange:
564 : : *
565 : : * The #GcrSecretExchange to use when transferring passwords. A default
566 : : * secret exchange will be used if this is not set.
567 : : */
568 : 1 : g_object_class_install_property (gobject_class, PROP_SECRET_EXCHANGE,
569 : : g_param_spec_object ("secret-exchange", "Secret exchange", "Secret exchange for passing passwords",
570 : : GCR_TYPE_SECRET_EXCHANGE,
571 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
572 : :
573 : 1 : g_object_class_override_property (gobject_class, PROP_TITLE, "title");
574 : 1 : g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
575 : 1 : g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
576 : 1 : g_object_class_override_property (gobject_class, PROP_WARNING, "warning");
577 : 1 : g_object_class_override_property (gobject_class, PROP_PASSWORD_NEW, "password-new");
578 : 1 : g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
579 : 1 : g_object_class_override_property (gobject_class, PROP_CHOICE_LABEL, "choice-label");
580 : 1 : g_object_class_override_property (gobject_class, PROP_CHOICE_CHOSEN, "choice-chosen");
581 : 1 : g_object_class_override_property (gobject_class, PROP_CALLER_WINDOW, "caller-window");
582 : 1 : g_object_class_override_property (gobject_class, PROP_CONTINUE_LABEL, "continue-label");
583 : 1 : g_object_class_override_property (gobject_class, PROP_CANCEL_LABEL, "cancel-label");
584 : 1 : }
585 : :
586 : : /**
587 : : * gcr_system_prompt_get_secret_exchange:
588 : : * @self: a prompter
589 : : *
590 : : * Get the current [class@SecretExchange] used to transfer secrets in this prompt.
591 : : *
592 : : * Returns: (transfer none): the secret exchange
593 : : */
594 : : GcrSecretExchange *
595 : 45 : gcr_system_prompt_get_secret_exchange (GcrSystemPrompt *self)
596 : : {
597 [ - + + - : 45 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL);
+ - - + ]
598 : :
599 [ + + ]: 45 : if (!self->pv->exchange) {
600 : 17 : g_debug ("creating new secret exchange");
601 : 17 : self->pv->exchange = gcr_secret_exchange_new (NULL);
602 : : }
603 : :
604 : 45 : return self->pv->exchange;
605 : : }
606 : :
607 : : static void
608 : 30 : update_properties_from_iter (GcrSystemPrompt *self,
609 : : GVariantIter *iter)
610 : : {
611 : 30 : GObject *obj = G_OBJECT (self);
612 : : GVariant *variant;
613 : : GVariant *value;
614 : : GVariant *already;
615 : : gpointer key;
616 : : gchar *name;
617 : :
618 : 30 : g_object_freeze_notify (obj);
619 [ + + ]: 132 : while (g_variant_iter_loop (iter, "{sv}", &name, &variant)) {
620 : 102 : key = (gpointer)g_intern_string (name);
621 : 102 : value = g_variant_get_variant (variant);
622 : 102 : already = g_hash_table_lookup (self->pv->properties, key);
623 [ + + - + ]: 102 : if (!already || !g_variant_equal (already, value)) {
624 : 4 : g_hash_table_replace (self->pv->properties, key, g_variant_ref (value));
625 : 4 : g_object_notify (obj, name);
626 : : }
627 : 102 : g_variant_unref (value);
628 : : }
629 : 30 : g_object_thaw_notify (obj);
630 : 30 : }
631 : :
632 : : static void
633 : 30 : prompt_method_ready (GcrSystemPrompt *self,
634 : : GDBusMethodInvocation *invocation,
635 : : GVariant *parameters)
636 : : {
637 : : GcrSecretExchange *exchange;
638 : : GSimpleAsyncResult *res;
639 : : GVariantIter *iter;
640 : : gchar *received;
641 : :
642 [ - + + - : 30 : g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (self->pv->pending));
+ - - + ]
643 : :
644 : 30 : g_free (self->pv->last_response);
645 : 30 : g_variant_get (parameters, "(sa{sv}s)",
646 : 30 : &self->pv->last_response,
647 : : &iter, &received);
648 : :
649 : 30 : g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
650 : :
651 : 30 : update_properties_from_iter (self, iter);
652 : 30 : g_variant_iter_free (iter);
653 : :
654 : 30 : exchange = gcr_system_prompt_get_secret_exchange (self);
655 [ + - ]: 30 : if (gcr_secret_exchange_receive (exchange, received))
656 : 30 : self->pv->received = TRUE;
657 : : else
658 : 0 : g_warning ("received invalid secret exchange string");
659 : 30 : g_free (received);
660 : :
661 : 30 : res = g_object_ref (self->pv->pending);
662 [ + - ]: 30 : g_clear_object (&self->pv->pending);
663 : 30 : g_simple_async_result_complete (res);
664 : 30 : g_object_unref (res);
665 : : }
666 : :
667 : : static void
668 : 1 : prompt_method_done (GcrSystemPrompt *self,
669 : : GDBusMethodInvocation *invocation,
670 : : GVariant *parameters)
671 : : {
672 : 1 : g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
673 : :
674 : : /*
675 : : * At this point we're done prompting, and calling StopPrompting
676 : : * on the prompter is no longer necessary. It may have already been
677 : : * called, or the prompter may have stopped on its own accord.
678 : : */
679 : 1 : self->pv->begun_prompting = FALSE;
680 : 1 : perform_close (self, NULL, NULL);
681 : 1 : }
682 : :
683 : : static void
684 : 31 : prompt_method_call (GDBusConnection *connection,
685 : : const gchar *sender,
686 : : const gchar *object_path,
687 : : const gchar *interface_name,
688 : : const gchar *method_name,
689 : : GVariant *parameters,
690 : : GDBusMethodInvocation *invocation,
691 : : gpointer user_data)
692 : : {
693 : 31 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (user_data);
694 : :
695 [ - + ]: 31 : g_return_if_fail (method_name != NULL);
696 : :
697 [ + + ]: 31 : if (g_str_equal (method_name, GCR_DBUS_CALLBACK_METHOD_READY)) {
698 : 30 : prompt_method_ready (self, invocation, parameters);
699 : :
700 [ + - ]: 1 : } else if (g_str_equal (method_name, GCR_DBUS_CALLBACK_METHOD_DONE)) {
701 : 1 : prompt_method_done (self, invocation, parameters);
702 : :
703 : : } else {
704 : 0 : g_return_if_reached ();
705 : : }
706 : : }
707 : :
708 : : static GVariant *
709 : 0 : prompt_get_property (GDBusConnection *connection,
710 : : const gchar *sender,
711 : : const gchar *object_path,
712 : : const gchar *interface_name,
713 : : const gchar *property_name,
714 : : GError **error,
715 : : gpointer user_data)
716 : : {
717 : 0 : g_return_val_if_reached (NULL);
718 : : }
719 : :
720 : : static gboolean
721 : 0 : prompt_set_property (GDBusConnection *connection,
722 : : const gchar *sender,
723 : : const gchar *object_path,
724 : : const gchar *interface_name,
725 : : const gchar *property_name,
726 : : GVariant *value,
727 : : GError **error,
728 : : gpointer user_data)
729 : : {
730 : 0 : g_return_val_if_reached (FALSE);
731 : : }
732 : :
733 : :
734 : : static GDBusInterfaceVTable prompt_dbus_vtable = {
735 : : prompt_method_call,
736 : : prompt_get_property,
737 : : prompt_set_property,
738 : : };
739 : :
740 : : static void
741 : 36 : register_prompt_object (GcrSystemPrompt *self,
742 : : GError **error)
743 : : {
744 : 36 : GError *lerror = NULL;
745 : : guint id;
746 : :
747 : : /*
748 : : * The unregister/reregister allows us to register this under a whatever
749 : : * GMainContext has been pushed as the thread default context.
750 : : */
751 : :
752 [ + + ]: 36 : if (self->pv->prompt_registered)
753 : 14 : g_dbus_connection_unregister_object (self->pv->connection,
754 : 14 : self->pv->prompt_registered);
755 : :
756 : 36 : id = g_dbus_connection_register_object (self->pv->connection,
757 : 36 : self->pv->prompt_path,
758 : : _gcr_dbus_prompter_callback_interface_info (),
759 : : &prompt_dbus_vtable,
760 : : self, NULL, &lerror);
761 : 36 : self->pv->prompt_registered = id;
762 : :
763 [ - + ]: 36 : if (lerror != NULL) {
764 : 0 : g_warning ("error registering prompter %s", egg_error_message (lerror));
765 : 0 : g_propagate_error (error, lerror);
766 : : }
767 : 36 : }
768 : :
769 : : static void
770 : 36 : on_prompter_present (GDBusConnection *connection,
771 : : const gchar *name,
772 : : const gchar *name_owner,
773 : : gpointer user_data)
774 : : {
775 : 36 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
776 : :
777 : 36 : g_free (self->pv->prompt_owner);
778 : 36 : self->pv->prompt_owner = g_strdup (name_owner);
779 : :
780 : 36 : g_object_unref (self);
781 : 36 : }
782 : :
783 : : static void
784 : 2 : on_prompter_vanished (GDBusConnection *connection,
785 : : const gchar *name,
786 : : gpointer user_data)
787 : : {
788 : 2 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
789 : 2 : CallClosure *call = g_simple_async_result_get_op_res_gpointer (user_data);
790 : :
791 [ + - ]: 2 : if (self->pv->prompt_owner) {
792 : 2 : g_free (self->pv->prompt_owner);
793 : 2 : self->pv->prompt_owner = NULL;
794 : 2 : g_debug ("prompter name owner has vanished: %s", name);
795 : 2 : g_cancellable_cancel (call->cancellable);
796 : : }
797 : :
798 : 2 : g_object_unref (self);
799 : 2 : }
800 : :
801 : : static void
802 : 22 : on_bus_connected (GObject *source,
803 : : GAsyncResult *result,
804 : : gpointer user_data)
805 : : {
806 : 22 : GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
807 : 22 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
808 : 22 : CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
809 : 22 : GError *error = NULL;
810 : :
811 [ - + ]: 22 : g_assert (self->pv->connection == NULL);
812 : 22 : self->pv->connection = g_bus_get_finish (result, &error);
813 : :
814 [ - + ]: 22 : if (error != NULL) {
815 : 0 : g_debug ("failed to connect to bus: %s", egg_error_message (error));
816 : :
817 : : } else {
818 [ - + ]: 22 : g_return_if_fail (self->pv->connection != NULL);
819 : 22 : g_debug ("connected to bus");
820 : :
821 : 22 : g_main_context_push_thread_default (closure->context);
822 : :
823 : 44 : closure->watch_id = g_bus_watch_name_on_connection (self->pv->connection,
824 : 22 : self->pv->prompter_bus_name,
825 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
826 : : on_prompter_present,
827 : : on_prompter_vanished,
828 : : res, NULL);
829 : :
830 : 22 : register_prompt_object (self, &error);
831 : :
832 : 22 : g_main_context_pop_thread_default (closure->context);
833 : : }
834 : :
835 [ + - ]: 22 : if (error == NULL) {
836 : 22 : perform_init_async (self, res);
837 : : } else {
838 : 0 : g_simple_async_result_take_error (res, error);
839 : 0 : g_simple_async_result_complete (res);
840 : : }
841 : :
842 : 22 : g_object_unref (self);
843 : 22 : g_object_unref (res);
844 : : }
845 : :
846 : : static void
847 : 22 : on_prompter_begin_prompting (GObject *source,
848 : : GAsyncResult *result,
849 : : gpointer user_data)
850 : : {
851 : 22 : GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
852 : 22 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
853 : 22 : GError *error = NULL;
854 : : GVariant *ret;
855 : :
856 : 22 : ret = g_dbus_connection_call_finish (self->pv->connection, result, &error);
857 : :
858 [ + + ]: 22 : if (error == NULL) {
859 : 21 : self->pv->begun_prompting = TRUE;
860 : 21 : g_variant_unref (ret);
861 : :
862 : 21 : g_debug ("registered prompt %s: %s",
863 : : self->pv->prompter_bus_name, self->pv->prompt_path);
864 : :
865 [ - + ]: 21 : g_return_if_fail (self->pv->prompt_path != NULL);
866 : 21 : perform_init_async (self, res);
867 : :
868 : : } else {
869 : 1 : g_debug ("failed to register prompt %s: %s",
870 : : self->pv->prompter_bus_name, egg_error_message (error));
871 : :
872 : 1 : g_simple_async_result_take_error (res, error);
873 : 1 : g_simple_async_result_complete (res);
874 : : }
875 : :
876 : 22 : g_object_unref (self);
877 : 22 : g_object_unref (res);
878 : : }
879 : :
880 : : static gboolean
881 : 2 : on_call_timeout (gpointer user_data)
882 : : {
883 : 2 : GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
884 : 2 : CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
885 : 2 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
886 : :
887 : 2 : g_source_destroy (closure->timeout);
888 : 2 : g_source_unref (closure->timeout);
889 : 2 : closure->timeout = NULL;
890 : :
891 : : /* Tell the prompter we're no longer interested */
892 : 2 : gcr_system_prompt_close_async (self, NULL, NULL, NULL);
893 : :
894 : 2 : g_simple_async_result_set_error (res, GCR_SYSTEM_PROMPT_ERROR,
895 : : GCR_SYSTEM_PROMPT_IN_PROGRESS,
896 : 2 : _("Another prompt is already in progress"));
897 : 2 : g_simple_async_result_complete (res);
898 : :
899 : 2 : g_object_unref (self);
900 : 2 : return FALSE; /* Don't call this function again */
901 : : }
902 : :
903 : : static gboolean
904 : 2 : on_call_cancelled (GCancellable *cancellable,
905 : : gpointer user_data)
906 : : {
907 : 2 : GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
908 : 2 : CallClosure *call = g_simple_async_result_get_op_res_gpointer (async);
909 : 2 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
910 : :
911 : 2 : g_source_destroy (call->waiting);
912 : 2 : g_source_unref (call->waiting);
913 : 2 : call->waiting = NULL;
914 : :
915 : 2 : g_simple_async_result_set_error (async, G_IO_ERROR, G_IO_ERROR_CANCELLED,
916 : 2 : _("The operation was cancelled"));
917 : :
918 : : /* Tell the prompter we're no longer interested */
919 : 2 : gcr_system_prompt_close_async (self, NULL, NULL, NULL);
920 : :
921 : 2 : g_object_unref (self);
922 : 2 : return FALSE; /* Don't call this function again */
923 : : }
924 : :
925 : : void
926 : 65 : perform_init_async (GcrSystemPrompt *self,
927 : : GSimpleAsyncResult *res)
928 : : {
929 : 65 : CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
930 : :
931 : 65 : g_main_context_push_thread_default (closure->context);
932 : :
933 : : /* 1. Connect to the session bus */
934 [ + + ]: 65 : if (!self->pv->connection) {
935 : 22 : g_debug ("connecting to bus");
936 : 22 : g_bus_get (G_BUS_TYPE_SESSION, closure->cancellable,
937 : : on_bus_connected, g_object_ref (res));
938 : :
939 : : /* 2. Export our object, BeginPrompting on prompter */
940 [ + + ]: 43 : } else if (!self->pv->begun_prompting) {
941 [ - + ]: 22 : g_assert (self->pv->prompt_path != NULL);
942 : :
943 : 22 : g_debug ("calling %s method on prompter", GCR_DBUS_PROMPTER_METHOD_BEGIN);
944 : 22 : g_dbus_connection_call (self->pv->connection,
945 : 22 : self->pv->prompter_bus_name,
946 : : GCR_DBUS_PROMPTER_OBJECT_PATH,
947 : : GCR_DBUS_PROMPTER_INTERFACE,
948 : : GCR_DBUS_PROMPTER_METHOD_BEGIN,
949 : 22 : g_variant_new ("(o)", self->pv->prompt_path),
950 : : G_VARIANT_TYPE ("()"),
951 : : G_DBUS_CALL_FLAGS_NONE,
952 : : -1, closure->cancellable,
953 : : on_prompter_begin_prompting,
954 : : g_object_ref (res));
955 : :
956 : : /* 3. Wait for iterate */
957 [ + - ]: 21 : } else if (!self->pv->pending) {
958 : 21 : self->pv->pending = g_object_ref (res);
959 [ + + ]: 21 : if (self->pv->timeout_seconds > 0) {
960 [ - + ]: 6 : g_assert (closure->timeout == NULL);
961 : 6 : closure->timeout = g_timeout_source_new_seconds (self->pv->timeout_seconds);
962 : 6 : g_source_set_callback (closure->timeout, on_call_timeout, res, NULL);
963 : 6 : g_source_attach (closure->timeout, closure->context);
964 : : }
965 : :
966 [ - + ]: 21 : g_assert (closure->waiting == NULL);
967 : 21 : closure->waiting = g_cancellable_source_new (closure->cancellable);
968 : 21 : g_source_set_callback (closure->waiting, (GSourceFunc)on_call_cancelled, res, NULL);
969 : 21 : g_source_attach (closure->waiting, closure->context);
970 : :
971 : : /* 4. All done */
972 : : } else {
973 : 0 : g_assert_not_reached ();
974 : : }
975 : :
976 : 65 : g_main_context_pop_thread_default (closure->context);
977 : 65 : }
978 : :
979 : : static void
980 : 22 : gcr_system_prompt_real_init_async (GAsyncInitable *initable,
981 : : int io_priority,
982 : : GCancellable *cancellable,
983 : : GAsyncReadyCallback callback,
984 : : gpointer user_data)
985 : : {
986 : 22 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (initable);
987 : : GSimpleAsyncResult *res;
988 : : CallClosure *closure;
989 : :
990 : 22 : res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
991 : : gcr_system_prompt_real_init_async);
992 : 22 : closure = call_closure_new (cancellable);
993 : 22 : closure->context = g_main_context_get_thread_default ();
994 [ + + ]: 22 : if (closure->context)
995 : 19 : g_main_context_ref (closure->context);
996 : 22 : g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
997 : :
998 : 22 : perform_init_async (self, res);
999 : :
1000 : 22 : g_object_unref (res);
1001 : :
1002 : 22 : }
1003 : :
1004 : : static gboolean
1005 : 21 : gcr_system_prompt_real_init_finish (GAsyncInitable *initable,
1006 : : GAsyncResult *result,
1007 : : GError **error)
1008 : : {
1009 : 21 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (initable);
1010 : :
1011 [ - + ]: 21 : g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1012 : : gcr_system_prompt_real_init_async), FALSE);
1013 : :
1014 [ + + ]: 21 : if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1015 : 3 : return FALSE;
1016 : :
1017 : 18 : return TRUE;
1018 : : }
1019 : :
1020 : : static void
1021 : 1 : gcr_system_prompt_async_initable_iface (GAsyncInitableIface *iface)
1022 : : {
1023 : 1 : iface->init_async = gcr_system_prompt_real_init_async;
1024 : 1 : iface->init_finish = gcr_system_prompt_real_init_finish;
1025 : 1 : }
1026 : :
1027 : : typedef struct {
1028 : : GAsyncResult *result;
1029 : : GMainContext *context;
1030 : : GMainLoop *loop;
1031 : : } SyncClosure;
1032 : :
1033 : : static SyncClosure *
1034 : 22 : sync_closure_new (void)
1035 : : {
1036 : : SyncClosure *closure;
1037 : :
1038 : 22 : closure = g_new0 (SyncClosure, 1);
1039 : :
1040 : 22 : closure->context = g_main_context_new ();
1041 : 22 : closure->loop = g_main_loop_new (closure->context, FALSE);
1042 : :
1043 : 22 : return closure;
1044 : : }
1045 : :
1046 : : static void
1047 : 22 : sync_closure_free (gpointer data)
1048 : : {
1049 : 22 : SyncClosure *closure = data;
1050 : :
1051 [ + - ]: 22 : g_clear_object (&closure->result);
1052 : 22 : g_main_loop_unref (closure->loop);
1053 : 22 : g_main_context_unref (closure->context);
1054 : 22 : g_free (closure);
1055 : 22 : }
1056 : :
1057 : : static void
1058 : 22 : on_sync_result (GObject *source,
1059 : : GAsyncResult *result,
1060 : : gpointer user_data)
1061 : : {
1062 : 22 : SyncClosure *closure = user_data;
1063 : 22 : closure->result = g_object_ref (result);
1064 : 22 : g_main_loop_quit (closure->loop);
1065 : 22 : }
1066 : :
1067 : : static gboolean
1068 : 19 : gcr_system_prompt_real_init (GInitable *initable,
1069 : : GCancellable *cancellable,
1070 : : GError **error)
1071 : : {
1072 : : SyncClosure *closure;
1073 : : gboolean result;
1074 : :
1075 : 19 : closure = sync_closure_new ();
1076 : 19 : g_main_context_push_thread_default (closure->context);
1077 : :
1078 : 19 : gcr_system_prompt_real_init_async (G_ASYNC_INITABLE (initable),
1079 : : G_PRIORITY_DEFAULT, cancellable,
1080 : : on_sync_result, closure);
1081 : :
1082 : 19 : g_main_loop_run (closure->loop);
1083 : :
1084 : 19 : result = gcr_system_prompt_real_init_finish (G_ASYNC_INITABLE (initable),
1085 : : closure->result, error);
1086 : :
1087 : 19 : g_main_context_pop_thread_default (closure->context);
1088 : 19 : sync_closure_free (closure);
1089 : :
1090 : 19 : return result;
1091 : : }
1092 : :
1093 : : static void
1094 : 1 : gcr_system_prompt_initable_iface (GInitableIface *iface)
1095 : : {
1096 : 1 : iface->init = gcr_system_prompt_real_init;
1097 : 1 : }
1098 : :
1099 : : static GVariantBuilder *
1100 : 14 : build_dirty_properties (GcrSystemPrompt *self)
1101 : : {
1102 : : GVariantBuilder *builder;
1103 : : GHashTableIter iter;
1104 : : GVariant *variant;
1105 : : gpointer key;
1106 : :
1107 : 14 : builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
1108 : :
1109 : 14 : g_hash_table_iter_init (&iter, self->pv->dirty_properties);
1110 [ + + ]: 128 : while (g_hash_table_iter_next (&iter, &key, NULL)) {
1111 : 114 : variant = g_hash_table_lookup (self->pv->properties, key);
1112 : 114 : g_variant_builder_add (builder, "{sv}", (const gchar *)key, variant);
1113 : : }
1114 : :
1115 : 14 : g_hash_table_remove_all (self->pv->dirty_properties);
1116 : 14 : return builder;
1117 : : }
1118 : :
1119 : : static void
1120 : 14 : on_perform_prompt_complete (GObject *source,
1121 : : GAsyncResult *result,
1122 : : gpointer user_data)
1123 : : {
1124 : 14 : GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1125 : 14 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
1126 : 14 : CallClosure *call = g_simple_async_result_get_op_res_gpointer (res);
1127 : 14 : GError *error = NULL;
1128 : : GVariant *retval;
1129 : :
1130 : 14 : retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
1131 [ - + ]: 14 : if (error != NULL) {
1132 : 0 : self->pv->pending = NULL;
1133 : 0 : g_simple_async_result_take_error (res, error);
1134 : 0 : g_simple_async_result_complete (res);
1135 : : } else {
1136 [ - + ]: 14 : g_assert (call->waiting == NULL);
1137 : 14 : call->waiting = g_cancellable_source_new (call->cancellable);
1138 : 14 : g_source_set_callback (call->waiting, (GSourceFunc)on_call_cancelled, res, NULL);
1139 : 14 : g_source_attach (call->waiting, call->context);
1140 : : }
1141 : :
1142 [ + - ]: 14 : if (retval)
1143 : 14 : g_variant_unref (retval);
1144 : :
1145 : 14 : g_object_unref (self);
1146 : 14 : g_object_unref (res);
1147 : 14 : }
1148 : :
1149 : : static void
1150 : 18 : perform_prompt_async (GcrSystemPrompt *self,
1151 : : const gchar *type,
1152 : : gpointer source_tag,
1153 : : GCancellable *cancellable,
1154 : : GAsyncReadyCallback callback,
1155 : : gpointer user_data)
1156 : : {
1157 : : GSimpleAsyncResult *res;
1158 : : GcrSecretExchange *exchange;
1159 : : GVariantBuilder *builder;
1160 : : CallClosure *closure;
1161 : : gchar *sent;
1162 : :
1163 [ - + + - : 18 : g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
+ - - + ]
1164 [ - + - - : 18 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - -
- ]
1165 : :
1166 [ - + ]: 18 : if (self->pv->pending != NULL) {
1167 : 0 : g_warning ("another operation is already pending on this prompt");
1168 : 0 : return;
1169 : : }
1170 : :
1171 : 18 : res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, source_tag);
1172 : 18 : closure = call_closure_new (cancellable);
1173 : 18 : g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
1174 : :
1175 [ + + ]: 18 : if (self->pv->closed) {
1176 : 4 : g_free (self->pv->last_response);
1177 : 4 : self->pv->last_response = g_strdup (GCR_DBUS_PROMPT_REPLY_NONE);
1178 : 4 : g_simple_async_result_complete_in_idle (res);
1179 : 4 : g_object_unref (res);
1180 : 4 : return;
1181 : : }
1182 : :
1183 : 14 : g_debug ("prompting for password");
1184 : :
1185 : 14 : exchange = gcr_system_prompt_get_secret_exchange (self);
1186 [ + - ]: 14 : if (self->pv->received)
1187 : 14 : sent = gcr_secret_exchange_send (exchange, NULL, 0);
1188 : : else
1189 : 0 : sent = gcr_secret_exchange_begin (exchange);
1190 : :
1191 : 28 : closure->watch_id = g_bus_watch_name_on_connection (self->pv->connection,
1192 : 14 : self->pv->prompter_bus_name,
1193 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
1194 : : on_prompter_present,
1195 : : on_prompter_vanished,
1196 : : res, NULL);
1197 : :
1198 : 14 : builder = build_dirty_properties (self);
1199 : :
1200 : : /* Reregister the prompt object in the current GMainContext */
1201 : 14 : register_prompt_object (self, NULL);
1202 : :
1203 : 14 : g_dbus_connection_call (self->pv->connection,
1204 : 14 : self->pv->prompter_bus_name,
1205 : : GCR_DBUS_PROMPTER_OBJECT_PATH,
1206 : : GCR_DBUS_PROMPTER_INTERFACE,
1207 : : GCR_DBUS_PROMPTER_METHOD_PERFORM,
1208 : 14 : g_variant_new ("(osa{sv}s)", self->pv->prompt_path,
1209 : : type, builder, sent),
1210 : : G_VARIANT_TYPE ("()"),
1211 : : G_DBUS_CALL_FLAGS_NO_AUTO_START,
1212 : : -1, cancellable,
1213 : : on_perform_prompt_complete,
1214 : : g_object_ref (res));
1215 : 14 : g_variant_builder_unref(builder);
1216 : :
1217 : 14 : self->pv->pending = res;
1218 : 14 : g_free (sent);
1219 : : }
1220 : :
1221 : : static GcrPromptReply
1222 : 17 : handle_last_response (GcrSystemPrompt *self)
1223 : : {
1224 : : GcrPromptReply response;
1225 : :
1226 [ - + ]: 17 : g_return_val_if_fail (self->pv->last_response != NULL,
1227 : : GCR_PROMPT_REPLY_CANCEL);
1228 : :
1229 [ + + ]: 17 : if (g_str_equal (self->pv->last_response, GCR_DBUS_PROMPT_REPLY_YES)) {
1230 : 9 : response = GCR_PROMPT_REPLY_CONTINUE;
1231 : :
1232 [ + + + - ]: 13 : } else if (g_str_equal (self->pv->last_response, GCR_DBUS_PROMPT_REPLY_NO) ||
1233 : 5 : g_str_equal (self->pv->last_response, GCR_DBUS_PROMPT_REPLY_NONE)) {
1234 : 8 : response = GCR_PROMPT_REPLY_CANCEL;
1235 : :
1236 : : } else {
1237 : 0 : g_warning ("unknown response from prompter: %s", self->pv->last_response);
1238 : 0 : response = GCR_PROMPT_REPLY_CANCEL;
1239 : : }
1240 : :
1241 : 17 : return response;
1242 : : }
1243 : :
1244 : : static void
1245 : 9 : gcr_system_prompt_password_async (GcrPrompt *prompt,
1246 : : GCancellable *cancellable,
1247 : : GAsyncReadyCallback callback,
1248 : : gpointer user_data)
1249 : : {
1250 : 9 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
1251 : 9 : perform_prompt_async (self, GCR_DBUS_PROMPT_TYPE_PASSWORD,
1252 : : gcr_system_prompt_password_async,
1253 : : cancellable, callback, user_data);
1254 : 9 : }
1255 : :
1256 : : static const gchar *
1257 : 9 : gcr_system_prompt_password_finish (GcrPrompt *prompt,
1258 : : GAsyncResult *result,
1259 : : GError **error)
1260 : : {
1261 : 9 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
1262 : : GSimpleAsyncResult *res;
1263 : :
1264 [ - + ]: 9 : g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1265 : : gcr_system_prompt_password_async), FALSE);
1266 : :
1267 : 9 : res = G_SIMPLE_ASYNC_RESULT (result);
1268 [ + + ]: 9 : if (g_simple_async_result_propagate_error (res, error))
1269 : 1 : return FALSE;
1270 : :
1271 [ + + ]: 8 : if (handle_last_response (self) == GCR_PROMPT_REPLY_CONTINUE)
1272 : 4 : return gcr_secret_exchange_get_secret (self->pv->exchange, NULL);
1273 : :
1274 : 4 : return NULL;
1275 : : }
1276 : :
1277 : : static void
1278 : 9 : gcr_system_prompt_confirm_async (GcrPrompt *prompt,
1279 : : GCancellable *cancellable,
1280 : : GAsyncReadyCallback callback,
1281 : : gpointer user_data)
1282 : : {
1283 : 9 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
1284 : 9 : perform_prompt_async (self, GCR_DBUS_PROMPT_TYPE_CONFIRM,
1285 : : gcr_system_prompt_confirm_async,
1286 : : cancellable, callback, user_data);
1287 : 9 : }
1288 : :
1289 : : static GcrPromptReply
1290 : 9 : gcr_system_prompt_confirm_finish (GcrPrompt *prompt,
1291 : : GAsyncResult *result,
1292 : : GError **error)
1293 : : {
1294 : 9 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
1295 : : GSimpleAsyncResult *res;
1296 : :
1297 [ - + + - : 9 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
+ - - + ]
1298 [ - + ]: 9 : g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1299 : : gcr_system_prompt_confirm_async), FALSE);
1300 : :
1301 : 9 : res = G_SIMPLE_ASYNC_RESULT (result);
1302 [ - + ]: 9 : if (g_simple_async_result_propagate_error (res, error))
1303 : 0 : return FALSE;
1304 : :
1305 : 9 : return handle_last_response (self);
1306 : : }
1307 : :
1308 : : static void
1309 : 22 : gcr_system_prompt_real_close (GcrPrompt *prompt)
1310 : : {
1311 : 22 : GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
1312 : :
1313 : : /*
1314 : : * Setting this before calling close_async allows us to prevent firing
1315 : : * this signal again in a loop.
1316 : : */
1317 : :
1318 [ + + ]: 22 : if (!self->pv->closed) {
1319 : 1 : self->pv->closed = TRUE;
1320 : 1 : perform_close (self, NULL, NULL);
1321 : : }
1322 : 22 : }
1323 : :
1324 : : static void
1325 : 1 : gcr_system_prompt_prompt_iface (GcrPromptInterface *iface)
1326 : : {
1327 : 1 : iface->prompt_password_async = gcr_system_prompt_password_async;
1328 : 1 : iface->prompt_password_finish = gcr_system_prompt_password_finish;
1329 : 1 : iface->prompt_confirm_async = gcr_system_prompt_confirm_async;
1330 : 1 : iface->prompt_confirm_finish = gcr_system_prompt_confirm_finish;
1331 : 1 : iface->prompt_close = gcr_system_prompt_real_close;
1332 : 1 : }
1333 : :
1334 : : /**
1335 : : * gcr_system_prompt_open_async:
1336 : : * @timeout_seconds: the number of seconds to wait to access the prompt, or -1
1337 : : * @cancellable: optional cancellation object
1338 : : * @callback: called when the operation completes
1339 : : * @user_data: data to pass the callback
1340 : : *
1341 : : * Asynchronously open a system prompt with the default system prompter.
1342 : : *
1343 : : * Most system prompters only allow showing one prompt at a time, and if
1344 : : * another prompt is shown then this method will block for up to
1345 : : * @timeout_seconds seconds. If @timeout_seconds is equal to -1, then this
1346 : : * will block indefinitely until the prompt can be opened. If @timeout_seconds
1347 : : * expires, then this operation will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
1348 : : * error.
1349 : : */
1350 : : void
1351 : 0 : gcr_system_prompt_open_async (gint timeout_seconds,
1352 : : GCancellable *cancellable,
1353 : : GAsyncReadyCallback callback,
1354 : : gpointer user_data)
1355 : : {
1356 [ # # ]: 0 : g_return_if_fail (timeout_seconds >= -1);
1357 [ # # # # ]: 0 : g_return_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable));
1358 : :
1359 : 0 : gcr_system_prompt_open_for_prompter_async (NULL, timeout_seconds,
1360 : : cancellable, callback,
1361 : : user_data);
1362 : : }
1363 : :
1364 : : /**
1365 : : * gcr_system_prompt_open_for_prompter_async:
1366 : : * @prompter_name: (nullable): the prompter D-Bus name
1367 : : * @timeout_seconds: the number of seconds to wait to access the prompt, or -1
1368 : : * @cancellable: (nullable): optional cancellation object
1369 : : * @callback: called when the operation completes
1370 : : * @user_data: data to pass the callback
1371 : : *
1372 : : * Opens a system prompt asynchronously. If prompter_name is %NULL, then the
1373 : : * default system prompter is used.
1374 : : *
1375 : : * Most system prompters only allow showing one prompt at a time, and if
1376 : : * another prompt is shown then this method will block for up to
1377 : : * @timeout_seconds seconds. If @timeout_seconds is equal to -1, then this
1378 : : * will block indefinitely until the prompt can be opened. If @timeout_seconds
1379 : : * expires, then this operation will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
1380 : : * error.
1381 : : */
1382 : : void
1383 : 3 : gcr_system_prompt_open_for_prompter_async (const gchar *prompter_name,
1384 : : gint timeout_seconds,
1385 : : GCancellable *cancellable,
1386 : : GAsyncReadyCallback callback,
1387 : : gpointer user_data)
1388 : : {
1389 [ - + ]: 3 : g_return_if_fail (timeout_seconds >= -1);
1390 [ - + - - ]: 3 : g_return_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable));
1391 : :
1392 [ - + ]: 3 : if (prompter_name == NULL)
1393 : 0 : g_debug ("opening prompt");
1394 : : else
1395 : 3 : g_debug ("opening prompt for prompter: %s", prompter_name);
1396 : :
1397 : 3 : g_async_initable_new_async (GCR_TYPE_SYSTEM_PROMPT,
1398 : : G_PRIORITY_DEFAULT,
1399 : : cancellable,
1400 : : callback,
1401 : : user_data,
1402 : : "timeout-seconds", timeout_seconds,
1403 : : "bus-name", prompter_name,
1404 : : NULL);
1405 : : }
1406 : :
1407 : : /**
1408 : : * gcr_system_prompt_open_finish:
1409 : : * @result: the asynchronous result
1410 : : * @error: location to place an error on failure
1411 : : *
1412 : : * Complete an operation to asynchronously open a system prompt.
1413 : : *
1414 : : * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
1415 : : * prompt could not be opened
1416 : : */
1417 : : GcrPrompt *
1418 : 3 : gcr_system_prompt_open_finish (GAsyncResult *result,
1419 : : GError **error)
1420 : : {
1421 : : GObject *object;
1422 : : GObject *source_object;
1423 : :
1424 [ - + + - : 3 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
- + - + ]
1425 [ + - - + ]: 3 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1426 : :
1427 : 3 : source_object = g_async_result_get_source_object (result);
1428 [ - + ]: 3 : g_assert (source_object != NULL);
1429 : :
1430 : 3 : object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
1431 : : result, error);
1432 : 3 : g_object_unref (source_object);
1433 : :
1434 [ + + ]: 3 : if (object != NULL)
1435 : 2 : return GCR_PROMPT (object);
1436 : : else
1437 : 1 : return NULL;
1438 : : }
1439 : :
1440 : : /**
1441 : : * gcr_system_prompt_open:
1442 : : * @timeout_seconds: the number of seconds to wait to access the prompt, or -1
1443 : : * @cancellable: (nullable): optional cancellation object
1444 : : * @error: location to place error on failure
1445 : : *
1446 : : * Opens a system prompt with the default prompter.
1447 : : *
1448 : : * Most system prompters only allow showing one prompt at a time, and if
1449 : : * another prompt is shown then this method will block for up to
1450 : : * @timeout_seconds seconds. If @timeout_seconds is equal to -1, then this
1451 : : * will block indefinitely until the prompt can be opened. If @timeout_seconds
1452 : : * expires, then this function will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
1453 : : * error.
1454 : : *
1455 : : * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
1456 : : * prompt could not be opened
1457 : : */
1458 : : GcrPrompt *
1459 : 0 : gcr_system_prompt_open (gint timeout_seconds,
1460 : : GCancellable *cancellable,
1461 : : GError **error)
1462 : : {
1463 [ # # ]: 0 : g_return_val_if_fail (timeout_seconds >= -1, NULL);
1464 [ # # # # : 0 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
# # # # #
# ]
1465 [ # # # # ]: 0 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1466 : :
1467 : 0 : return gcr_system_prompt_open_for_prompter (NULL, timeout_seconds,
1468 : : cancellable, error);
1469 : : }
1470 : :
1471 : : /**
1472 : : * gcr_system_prompt_open_for_prompter:
1473 : : * @prompter_name: (nullable): the prompter dbus name
1474 : : * @timeout_seconds: the number of seconds to wait to access the prompt, or -1
1475 : : * @cancellable: optional cancellation object
1476 : : * @error: location to place error on failure
1477 : : *
1478 : : * Opens a system prompt. If prompter_name is %NULL, then the default
1479 : : * system prompter is used.
1480 : : *
1481 : : * Most system prompters only allow showing one prompt at a time, and if
1482 : : * another prompt is shown then this method will block for up to
1483 : : * @timeout_seconds seconds. If @timeout_seconds is equal to -1, then this
1484 : : * will block indefinitely until the prompt can be opened. If @timeout_seconds
1485 : : * expires, then this function will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
1486 : : * error.
1487 : : *
1488 : : * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
1489 : : * prompt could not be opened
1490 : : */
1491 : : GcrPrompt *
1492 : 18 : gcr_system_prompt_open_for_prompter (const gchar *prompter_name,
1493 : : gint timeout_seconds,
1494 : : GCancellable *cancellable,
1495 : : GError **error)
1496 : : {
1497 [ - + ]: 18 : g_return_val_if_fail (timeout_seconds >= -1, NULL);
1498 [ - + - - : 18 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- - - - -
- ]
1499 [ + - - + ]: 18 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1500 : :
1501 [ - + ]: 18 : if (prompter_name == NULL)
1502 : 0 : g_debug ("opening prompt");
1503 : : else
1504 : 18 : g_debug ("opening prompt for prompter: %s", prompter_name);
1505 : :
1506 : 18 : return g_initable_new (GCR_TYPE_SYSTEM_PROMPT, cancellable, error,
1507 : : "timeout-seconds", timeout_seconds,
1508 : : "bus-name", prompter_name,
1509 : : NULL);
1510 : : }
1511 : :
1512 : : /**
1513 : : * gcr_system_prompt_close:
1514 : : * @self: the prompt
1515 : : * @cancellable: an optional cancellation object
1516 : : * @error: location to place an error on failure
1517 : : *
1518 : : * Close this prompt. After calling this function, no further prompts will
1519 : : * succeed on this object. The prompt object is not unreferenced by this
1520 : : * function, and you must unreference it once done.
1521 : : *
1522 : : * This call may block, use the gcr_system_prompt_close_async() to perform
1523 : : * this action indefinitely.
1524 : : *
1525 : : * Whether or not this function returns %TRUE, the system prompt object is
1526 : : * still closed and may not be further used.
1527 : : *
1528 : : * Returns: whether close was cleanly completed
1529 : : */
1530 : : gboolean
1531 : 3 : gcr_system_prompt_close (GcrSystemPrompt *self,
1532 : : GCancellable *cancellable,
1533 : : GError **error)
1534 : : {
1535 : : SyncClosure *closure;
1536 : : gboolean result;
1537 : :
1538 : 3 : closure = sync_closure_new ();
1539 : 3 : g_main_context_push_thread_default (closure->context);
1540 : :
1541 : 3 : gcr_system_prompt_close_async (self, cancellable,
1542 : : on_sync_result, closure);
1543 : :
1544 : 3 : g_main_loop_run (closure->loop);
1545 : :
1546 : 3 : result = gcr_system_prompt_close_finish (self, closure->result, error);
1547 : :
1548 : 3 : g_main_context_pop_thread_default (closure->context);
1549 : 3 : sync_closure_free (closure);
1550 : :
1551 : 3 : return result;
1552 : : }
1553 : :
1554 : : /**
1555 : : * gcr_system_prompt_close_async:
1556 : : * @self: the prompt
1557 : : * @cancellable: an optional cancellation object
1558 : : * @callback: called when the operation completes
1559 : : * @user_data: data to pass to the callback
1560 : : *
1561 : : * Close this prompt asynchronously. After calling this function, no further
1562 : : * methods may be called on this object. The prompt object is not unreferenced
1563 : : * by this function, and you must unreference it once done.
1564 : : *
1565 : : * This call returns immediately and completes asynchronously.
1566 : : */
1567 : : void
1568 : 7 : gcr_system_prompt_close_async (GcrSystemPrompt *self,
1569 : : GCancellable *cancellable,
1570 : : GAsyncReadyCallback callback,
1571 : : gpointer user_data)
1572 : : {
1573 : : GSimpleAsyncResult *res;
1574 : : CallClosure *closure;
1575 : :
1576 [ - + ]: 7 : g_return_if_fail (GCR_SYSTEM_PROMPT (self));
1577 [ - + - - : 7 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - -
- ]
1578 : :
1579 : 7 : res = g_simple_async_result_new (NULL, callback, user_data,
1580 : : gcr_system_prompt_close_async);
1581 : 7 : closure = call_closure_new (cancellable);
1582 : 7 : closure->context = g_main_context_get_thread_default ();
1583 [ + + ]: 7 : if (closure->context != NULL)
1584 : 5 : g_main_context_ref (closure->context);
1585 : 7 : g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
1586 : :
1587 : 7 : perform_close (self, res, closure->cancellable);
1588 : :
1589 : 7 : g_object_unref (res);
1590 : : }
1591 : :
1592 : : /**
1593 : : * gcr_system_prompt_close_finish:
1594 : : * @self: the prompt
1595 : : * @result: asynchronous operation result
1596 : : * @error: location to place an error on failure
1597 : : *
1598 : : * Complete operation to close this prompt.
1599 : : *
1600 : : * Whether or not this function returns %TRUE, the system prompt object is
1601 : : * still closed and may not be further used.
1602 : : *
1603 : : * Returns: whether close was cleanly completed
1604 : : */
1605 : : gboolean
1606 : 3 : gcr_system_prompt_close_finish (GcrSystemPrompt *self,
1607 : : GAsyncResult *result,
1608 : : GError **error)
1609 : : {
1610 [ - + + - : 3 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
+ - - + ]
1611 [ + - - + ]: 3 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1612 : :
1613 [ - + ]: 3 : g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
1614 : : gcr_system_prompt_close_async), FALSE);
1615 : :
1616 [ - + ]: 3 : if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1617 : 0 : return FALSE;
1618 : :
1619 : 3 : return TRUE;
1620 : : }
1621 : :
1622 : : static const GDBusErrorEntry SYSTEM_PROMPT_ERRORS[] = {
1623 : : { GCR_SYSTEM_PROMPT_IN_PROGRESS, GCR_DBUS_PROMPT_ERROR_IN_PROGRESS },
1624 : : };
1625 : :
1626 : : GQuark
1627 : 4 : gcr_system_prompt_error_get_domain (void)
1628 : : {
1629 : : static size_t quark_volatile = 0;
1630 : 4 : g_dbus_error_register_error_domain ("gcr-system-prompt-error-domain",
1631 : : &quark_volatile,
1632 : : SYSTEM_PROMPT_ERRORS,
1633 : : G_N_ELEMENTS (SYSTEM_PROMPT_ERRORS));
1634 : : G_STATIC_ASSERT (G_N_ELEMENTS (SYSTEM_PROMPT_ERRORS) == GCR_SYSTEM_PROMPT_IN_PROGRESS);
1635 : 4 : return (GQuark) quark_volatile;
1636 : : }
|