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-prompter.h"
30 : : #include "gcr-system-prompt.h"
31 : :
32 : : #include "gcr/gcr-dbus-generated.h"
33 : : #include "gcr/gcr-enum-types.h"
34 : : #include "gcr/gcr-marshal.h"
35 : :
36 : : #include "egg/egg-error.h"
37 : :
38 : : #include <string.h>
39 : :
40 : : /**
41 : : * GcrSystemPrompter:
42 : : *
43 : : * A prompter used by implementations of system prompts.
44 : : *
45 : : * This is a D-Bus service which is rarely implemented. Use [class@SystemPrompt]
46 : : * to display system prompts.
47 : : *
48 : : * The system prompter service responds to D-Bus requests to create system
49 : : * prompts and creates #GcrPrompt type objects to display those prompts.
50 : : *
51 : : * Pass the GType of the implementation of [iface@Prompt] to
52 : : * [ctor@SystemPrompter.new].
53 : : */
54 : :
55 : : /**
56 : : * GcrSystemPrompterClass:
57 : : * @parent_class: parent class
58 : : * @new_prompt: default handler for the #GcrSystemPrompter::new-prompt signal
59 : : *
60 : : * The class for #GcrSystemPrompter.
61 : : */
62 : :
63 : : /**
64 : : * GcrSystemPrompterMode:
65 : : * @GCR_SYSTEM_PROMPTER_SINGLE: only one prompt shown at a time
66 : : * @GCR_SYSTEM_PROMPTER_MULTIPLE: more than one prompt shown at a time
67 : : *
68 : : * The mode for the system prompter. Most system prompters can only show
69 : : * one prompt at a time and would use the %GCR_SYSTEM_PROMPTER_SINGLE mode.
70 : : */
71 : :
72 : : enum {
73 : : PROP_0,
74 : : PROP_MODE,
75 : : PROP_PROMPT_TYPE,
76 : : PROP_PROMPTING
77 : : };
78 : :
79 : : enum {
80 : : NEW_PROMPT,
81 : : LAST_SIGNAL,
82 : : };
83 : :
84 : : struct _GcrSystemPrompterPrivate {
85 : : GcrSystemPrompterMode mode;
86 : : GType prompt_type;
87 : :
88 : : guint prompter_registered;
89 : : GDBusConnection *connection;
90 : :
91 : : GHashTable *callbacks; /* Callback -> guint watch_id */
92 : : GHashTable *active; /* Callback -> active (ActivePrompt) */
93 : : GQueue waiting;
94 : : };
95 : :
96 : : static guint signals[LAST_SIGNAL] = { 0, };
97 : :
98 [ + + + - : 218 : G_DEFINE_TYPE_WITH_PRIVATE (GcrSystemPrompter, gcr_system_prompter, G_TYPE_OBJECT);
+ + ]
99 : :
100 : : typedef struct {
101 : : const gchar *path;
102 : : const gchar *name;
103 : : } Callback;
104 : :
105 : : typedef struct {
106 : : gint refs;
107 : : Callback *callback;
108 : : GcrSystemPrompter *prompter;
109 : : GCancellable *cancellable;
110 : : GcrPrompt *prompt;
111 : : gboolean ready;
112 : : guint notify_sig;
113 : : GHashTable *changed;
114 : : GcrSecretExchange *exchange;
115 : : gboolean received;
116 : : gboolean closed;
117 : : guint close_sig;
118 : : } ActivePrompt;
119 : :
120 : : static void prompt_send_ready (ActivePrompt *active,
121 : : const gchar *response,
122 : : const gchar *secret);
123 : :
124 : : static void prompt_next_ready (GcrSystemPrompter *self);
125 : :
126 : : static void prompt_stop_prompting (GcrSystemPrompter *self,
127 : : Callback *callback,
128 : : gboolean send_done_message,
129 : : gboolean wait_for_reply);
130 : :
131 : : static ActivePrompt *
132 : 62 : active_prompt_ref (ActivePrompt *active)
133 : : {
134 : 62 : g_atomic_int_inc (&active->refs);
135 : 62 : return active;
136 : : }
137 : :
138 : : static void
139 : 121 : on_prompt_notify (GObject *object,
140 : : GParamSpec *param,
141 : : gpointer user_data)
142 : : {
143 : 121 : ActivePrompt *active = user_data;
144 : 121 : gpointer key = (gpointer)g_intern_string (param->name);
145 : 121 : g_hash_table_replace (active->changed, key, key);
146 : 121 : }
147 : :
148 : : static void
149 : 19 : on_prompt_close (GcrPrompt *prompt,
150 : : gpointer user_data)
151 : : {
152 : 19 : ActivePrompt *active = user_data;
153 : 19 : prompt_stop_prompting (active->prompter, active->callback, TRUE, FALSE);
154 : 19 : }
155 : :
156 : : static Callback *
157 : 39 : callback_dup (Callback *original)
158 : : {
159 : 39 : Callback *callback = g_slice_new0 (Callback);
160 [ - + ]: 39 : g_assert (original != NULL);
161 [ - + ]: 39 : g_assert (original->path != NULL);
162 [ - + ]: 39 : g_assert (original->name != NULL);
163 : 39 : callback->path = g_strdup (original->path);
164 : 39 : callback->name = g_strdup (original->name);
165 : 39 : return callback;
166 : : }
167 : :
168 : : static void
169 : 37 : callback_free (gpointer data)
170 : : {
171 : 37 : Callback *callback = data;
172 : 37 : g_free ((gchar *)callback->path);
173 : 37 : g_free ((gchar *)callback->name);
174 : 37 : g_slice_free (Callback, callback);
175 : 37 : }
176 : :
177 : : static guint
178 : 191 : callback_hash (gconstpointer data)
179 : : {
180 : 191 : const Callback *callback = data;
181 : 191 : return g_str_hash (callback->name) ^ g_str_hash (callback->path);
182 : : }
183 : :
184 : : static gboolean
185 : 92 : callback_equal (gconstpointer one,
186 : : gconstpointer two)
187 : : {
188 : 92 : const Callback *cone = one;
189 : 92 : const Callback *ctwo = two;
190 [ + - + - ]: 184 : return g_str_equal (cone->name, ctwo->name) &&
191 : 92 : g_str_equal (cone->path, ctwo->path);
192 : : }
193 : :
194 : : static void
195 : 78 : active_prompt_unref (gpointer data)
196 : : {
197 : 78 : ActivePrompt *active = data;
198 : :
199 [ + + ]: 78 : if (g_atomic_int_dec_and_test (&active->refs)) {
200 : 16 : callback_free (active->callback);
201 : 16 : g_object_unref (active->prompter);
202 : 16 : g_object_unref (active->cancellable);
203 [ - + ]: 16 : if (g_signal_handler_is_connected (active->prompt, active->notify_sig))
204 : 0 : g_signal_handler_disconnect (active->prompt, active->notify_sig);
205 [ - + ]: 16 : if (g_signal_handler_is_connected (active->prompt, active->close_sig))
206 : 0 : g_signal_handler_disconnect (active->prompt, active->close_sig);
207 : 16 : g_object_unref (active->prompt);
208 : 16 : g_hash_table_destroy (active->changed);
209 [ + - ]: 16 : if (active->exchange)
210 : 16 : g_object_unref (active->exchange);
211 : 16 : g_slice_free (ActivePrompt, active);
212 : : }
213 : 78 : }
214 : :
215 : : static GcrSecretExchange *
216 : 44 : active_prompt_get_secret_exchange (ActivePrompt *active)
217 : : {
218 [ + + ]: 44 : if (active->exchange == NULL)
219 : 18 : active->exchange = gcr_secret_exchange_new (NULL);
220 : 44 : return active->exchange;
221 : : }
222 : :
223 : : static ActivePrompt *
224 : 18 : active_prompt_create (GcrSystemPrompter *self,
225 : : Callback *lookup)
226 : : {
227 : : ActivePrompt *active;
228 : :
229 : 18 : active = g_slice_new0 (ActivePrompt);
230 : 18 : active->refs = 1;
231 : 18 : active->callback = callback_dup (lookup);
232 : 18 : active->prompter = g_object_ref (self);
233 : 18 : active->cancellable = g_cancellable_new ();
234 : 18 : g_signal_emit (self, signals[NEW_PROMPT], 0, &active->prompt);
235 [ - + ]: 18 : g_return_val_if_fail (active->prompt != NULL, NULL);
236 : :
237 : 18 : active->notify_sig = g_signal_connect (active->prompt, "notify", G_CALLBACK (on_prompt_notify), active);
238 : 18 : active->close_sig = g_signal_connect (active->prompt, "prompt-close", G_CALLBACK (on_prompt_close), active);
239 : 18 : active->changed = g_hash_table_new (g_direct_hash, g_direct_equal);
240 : :
241 : : /* Insert us into the active hash table */
242 : 18 : g_hash_table_replace (self->pv->active, active->callback, active);
243 : 18 : return active;
244 : : }
245 : :
246 : : static void
247 : 21 : unwatch_name (gpointer data)
248 : : {
249 : 21 : g_bus_unwatch_name (GPOINTER_TO_UINT (data));
250 : 21 : }
251 : :
252 : : static void
253 : 18 : gcr_system_prompter_init (GcrSystemPrompter *self)
254 : : {
255 : 18 : self->pv = gcr_system_prompter_get_instance_private (self);
256 : 18 : self->pv->callbacks = g_hash_table_new_full (callback_hash, callback_equal, callback_free, unwatch_name);
257 : 18 : self->pv->active = g_hash_table_new_full (callback_hash, callback_equal, NULL, active_prompt_unref);
258 : 18 : }
259 : :
260 : : static void
261 : 36 : gcr_system_prompter_set_property (GObject *obj,
262 : : guint prop_id,
263 : : const GValue *value,
264 : : GParamSpec *pspec)
265 : : {
266 : 36 : GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj);
267 : :
268 [ + + - ]: 36 : switch (prop_id) {
269 : 18 : case PROP_MODE:
270 : 18 : self->pv->mode = g_value_get_enum (value);
271 : 18 : break;
272 : 18 : case PROP_PROMPT_TYPE:
273 : 18 : self->pv->prompt_type = g_value_get_gtype (value);
274 : 18 : break;
275 : 0 : default:
276 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
277 : 0 : break;
278 : : }
279 : 36 : }
280 : :
281 : : static void
282 : 0 : gcr_system_prompter_get_property (GObject *obj,
283 : : guint prop_id,
284 : : GValue *value,
285 : : GParamSpec *pspec)
286 : : {
287 : 0 : GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj);
288 : :
289 [ # # # # ]: 0 : switch (prop_id) {
290 : 0 : case PROP_MODE:
291 : 0 : g_value_set_enum (value, gcr_system_prompter_get_mode (self));
292 : 0 : break;
293 : 0 : case PROP_PROMPT_TYPE:
294 : 0 : g_value_set_gtype (value, gcr_system_prompter_get_prompt_type (self));
295 : 0 : break;
296 : 0 : case PROP_PROMPTING:
297 : 0 : g_value_set_boolean (value, gcr_system_prompter_get_prompting (self));
298 : 0 : break;
299 : 0 : default:
300 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
301 : 0 : break;
302 : : }
303 : 0 : }
304 : :
305 : : static void
306 : 16 : gcr_system_prompter_dispose (GObject *obj)
307 : : {
308 : 16 : GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj);
309 : :
310 : 16 : g_debug ("disposing prompter");
311 : :
312 [ - + ]: 16 : if (self->pv->prompter_registered)
313 : 0 : gcr_system_prompter_unregister (self, FALSE);
314 : :
315 : 16 : g_hash_table_remove_all (self->pv->callbacks);
316 : 16 : g_hash_table_remove_all (self->pv->active);
317 : 16 : g_object_notify (obj, "prompting");
318 : :
319 : 16 : G_OBJECT_CLASS (gcr_system_prompter_parent_class)->dispose (obj);
320 : 16 : }
321 : :
322 : : static void
323 : 16 : gcr_system_prompter_finalize (GObject *obj)
324 : : {
325 : 16 : GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj);
326 : :
327 : 16 : g_debug ("finalizing prompter");
328 : :
329 [ - + ]: 16 : g_assert (self->pv->connection == NULL);
330 [ - + ]: 16 : g_assert (self->pv->prompter_registered == 0);
331 : :
332 : 16 : g_hash_table_destroy (self->pv->callbacks);
333 : 16 : g_hash_table_destroy (self->pv->active);
334 : :
335 : 16 : G_OBJECT_CLASS (gcr_system_prompter_parent_class)->finalize (obj);
336 : 16 : }
337 : :
338 : : static GcrPrompt *
339 : 10 : gcr_system_prompter_new_prompt (GcrSystemPrompter *self)
340 : : {
341 [ - + ]: 10 : g_return_val_if_fail (self->pv->prompt_type != 0, NULL);
342 : :
343 : 10 : g_debug ("creating new %s prompt", g_type_name (self->pv->prompt_type));
344 : :
345 : 10 : return g_object_new (self->pv->prompt_type, NULL);
346 : : }
347 : :
348 : : static gboolean
349 : 26 : gcr_system_prompter_new_prompt_acculmulator (GSignalInvocationHint *ihint,
350 : : GValue *return_accu,
351 : : const GValue *handler_return,
352 : : gpointer user_data)
353 : : {
354 [ + + ]: 26 : if (g_value_get_object (handler_return) != NULL) {
355 : 18 : g_value_copy (handler_return, return_accu);
356 : 18 : return FALSE;
357 : : }
358 : :
359 : 8 : return TRUE;
360 : : }
361 : :
362 : : static void
363 : 1 : gcr_system_prompter_class_init (GcrSystemPrompterClass *klass)
364 : : {
365 : 1 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
366 : :
367 : 1 : gobject_class->get_property = gcr_system_prompter_get_property;
368 : 1 : gobject_class->set_property = gcr_system_prompter_set_property;
369 : 1 : gobject_class->dispose = gcr_system_prompter_dispose;
370 : 1 : gobject_class->finalize = gcr_system_prompter_finalize;
371 : :
372 : 1 : klass->new_prompt = gcr_system_prompter_new_prompt;
373 : :
374 : : /**
375 : : * GcrSystemPrompter:mode:
376 : : *
377 : : * The mode for this prompter.
378 : : *
379 : : * Most system prompters only display one prompt at a time and therefore
380 : : * return %GCR_SYSTEM_PROMPTER_SINGLE.
381 : : */
382 : 1 : g_object_class_install_property (gobject_class, PROP_MODE,
383 : : g_param_spec_enum ("mode", "Mode", "Prompting mode",
384 : : GCR_TYPE_SYSTEM_PROMPTER_MODE, GCR_SYSTEM_PROMPTER_SINGLE,
385 : : G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
386 : :
387 : : /**
388 : : * GcrSystemPrompter:prompt-type:
389 : : *
390 : : * The #GType for prompts created by this prompter. This must be a
391 : : * #GcrPrompt implementation.
392 : : */
393 : 1 : g_object_class_install_property (gobject_class, PROP_PROMPT_TYPE,
394 : : g_param_spec_gtype ("prompt-type", "Prompt GType", "GObject type of prompts",
395 : : GCR_TYPE_PROMPT,
396 : : G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
397 : :
398 : : /**
399 : : * GcrSystemPrompter:prompting:
400 : : *
401 : : * Whether the prompter is prompting or not.
402 : : */
403 : 1 : g_object_class_install_property (gobject_class, PROP_PROMPTING,
404 : : g_param_spec_boolean ("prompting", "Prompting", "Whether prompting or not",
405 : : FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
406 : :
407 : : /**
408 : : * GcrSystemPrompter::new-prompt:
409 : : *
410 : : * Signal emitted to create a new prompt when needed.
411 : : *
412 : : * The default implementation of this signal creates a prompt of the type
413 : : * gcr_system_prompter_get_prompt_type().
414 : : *
415 : : * Returns: (transfer full): the new prompt
416 : : */
417 : 1 : signals[NEW_PROMPT] = g_signal_new ("new-prompt", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
418 : : G_STRUCT_OFFSET (GcrSystemPrompterClass, new_prompt),
419 : : gcr_system_prompter_new_prompt_acculmulator, NULL,
420 : : _gcr_marshal_OBJECT__VOID,
421 : : GCR_TYPE_PROMPT, 0, G_TYPE_NONE);
422 : 1 : }
423 : :
424 : : static GVariantBuilder *
425 : 30 : prompt_build_properties (GcrPrompt *prompt,
426 : : GHashTable *changed)
427 : : {
428 : 30 : GObject *obj = G_OBJECT (prompt);
429 : : GVariantBuilder *builder;
430 : : const gchar *property_name;
431 : : GParamSpec *pspec;
432 : : GHashTableIter iter;
433 : : const GVariantType *type;
434 : : GVariant *variant;
435 : : GValue value;
436 : :
437 : 30 : builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
438 : 30 : g_hash_table_iter_init (&iter, changed);
439 [ + + ]: 132 : while (g_hash_table_iter_next (&iter, (gpointer *)&property_name, NULL)) {
440 : :
441 : : /* Make sure this property is on the prompt interface */
442 : 102 : pspec = g_object_interface_find_property (GCR_PROMPT_GET_IFACE (obj),
443 : : property_name);
444 [ - + ]: 102 : if (pspec == NULL)
445 : 0 : continue;
446 : :
447 : 102 : memset (&value, 0, sizeof (GValue));
448 : 102 : g_value_init (&value, pspec->value_type);
449 : 102 : g_object_get_property (obj, property_name, &value);
450 : :
451 [ + + + - ]: 102 : switch (pspec->value_type) {
452 : 96 : case G_TYPE_STRING:
453 : 96 : type = G_VARIANT_TYPE ("s");
454 : 96 : break;
455 : 4 : case G_TYPE_INT:
456 : 4 : type = G_VARIANT_TYPE ("i");
457 : 4 : break;
458 : 2 : case G_TYPE_BOOLEAN:
459 : 2 : type = G_VARIANT_TYPE ("b");
460 : 2 : break;
461 : 0 : default:
462 : 0 : g_critical ("encountered unsupported property type on GcrPrompt: %s",
463 : : g_type_name (pspec->value_type));
464 : 0 : continue;
465 : : }
466 : :
467 : 102 : variant = g_dbus_gvalue_to_gvariant (&value, type);
468 : 102 : g_variant_builder_add (builder, "{sv}", property_name,
469 : : g_variant_new_variant (variant));
470 : 102 : g_value_unset (&value);
471 : 102 : g_variant_unref (variant);
472 : : }
473 : 30 : g_hash_table_remove_all (changed);
474 : 30 : return builder;
475 : : }
476 : :
477 : : static void
478 : 39 : prompt_stop_prompting (GcrSystemPrompter *self,
479 : : Callback *callback,
480 : : gboolean send_done_message,
481 : : gboolean wait_for_reply)
482 : : {
483 : : ActivePrompt *active;
484 : : GVariant *retval;
485 : : gpointer watch;
486 : : Callback *orig_callback;
487 : :
488 : 39 : g_debug ("stopping prompting for operation %s@%s",
489 : : callback->path, callback->name);
490 : :
491 : : /* Get a pointer to our actual callback */
492 [ + + ]: 39 : if (!g_hash_table_lookup_extended (self->pv->callbacks, callback,
493 : : (gpointer *)&orig_callback, &watch)) {
494 : 18 : g_debug ("couldn't find the callback for prompting operation %s@%s",
495 : : callback->path, callback->name);
496 : 18 : return;
497 : : }
498 : 21 : callback = orig_callback;
499 : :
500 : : /*
501 : : * We remove these from the callbacks hash table so that we don't
502 : : * do this stuff more than once. However we still need the callback
503 : : * to be valid.
504 : : */
505 [ - + ]: 21 : if (!g_hash_table_steal (self->pv->callbacks, callback))
506 : 0 : g_assert_not_reached ();
507 : :
508 : : /* Removed from the waiting queue */
509 : 21 : g_queue_remove (&self->pv->waiting, callback);
510 : :
511 : : /* Close any active prompt */
512 : 21 : active = g_hash_table_lookup (self->pv->active, callback);
513 [ + + ]: 21 : if (active != NULL) {
514 : 18 : active_prompt_ref (active);
515 : 18 : g_hash_table_remove (self->pv->active, callback);
516 : :
517 [ + + ]: 18 : if (!active->ready) {
518 : 8 : g_debug ("cancelling active prompting operation for %s@%s",
519 : : callback->path, callback->name);
520 : 8 : g_cancellable_cancel (active->cancellable);
521 : : }
522 : :
523 : 18 : g_debug ("closing the prompt");
524 : 18 : gcr_prompt_close (active->prompt);
525 : 18 : g_object_run_dispose (G_OBJECT (active->prompt));
526 : 18 : active_prompt_unref (active);
527 : : }
528 : :
529 : : /* Notify the caller */
530 [ + + + + ]: 21 : if (send_done_message && wait_for_reply) {
531 : 13 : g_debug ("calling the %s method on %s@%s, and waiting for reply",
532 : : GCR_DBUS_CALLBACK_METHOD_DONE, callback->path, callback->name);
533 : :
534 : 13 : retval = g_dbus_connection_call_sync (self->pv->connection,
535 : : callback->name,
536 : : callback->path,
537 : : GCR_DBUS_CALLBACK_INTERFACE,
538 : : GCR_DBUS_CALLBACK_METHOD_DONE,
539 : : g_variant_new ("()"),
540 : : G_VARIANT_TYPE ("()"),
541 : : G_DBUS_CALL_FLAGS_NO_AUTO_START,
542 : : -1, NULL, NULL);
543 [ - + ]: 13 : if (retval)
544 : 0 : g_variant_unref (retval);
545 : :
546 : 13 : g_debug ("returned from %s on %s@%s",
547 : : GCR_DBUS_CALLBACK_METHOD_DONE, callback->path, callback->name);
548 : :
549 [ + + ]: 8 : } else if (send_done_message) {
550 : 6 : g_debug ("calling the %s method on %s@%s, and ignoring reply",
551 : : GCR_DBUS_CALLBACK_METHOD_DONE, callback->path, callback->name);
552 : :
553 : 6 : g_dbus_connection_call (self->pv->connection,
554 : : callback->name,
555 : : callback->path,
556 : : GCR_DBUS_CALLBACK_INTERFACE,
557 : : GCR_DBUS_CALLBACK_METHOD_DONE,
558 : : g_variant_new ("()"),
559 : : G_VARIANT_TYPE ("()"),
560 : : G_DBUS_CALL_FLAGS_NO_AUTO_START,
561 : : -1, NULL, NULL, NULL);
562 : : }
563 : :
564 : : /*
565 : : * And all traces gone, including watch. We stole these values from
566 : : * the callbacks hashtable above. Now free them
567 : : */
568 : :
569 : 21 : callback_free (callback);
570 : 21 : unwatch_name (watch);
571 : :
572 : 21 : g_object_notify (G_OBJECT (self), "prompting");
573 : : }
574 : :
575 : : static void
576 : 30 : on_prompt_ready_complete (GObject *source,
577 : : GAsyncResult *result,
578 : : gpointer user_data)
579 : : {
580 : 30 : ActivePrompt *active = user_data;
581 : 30 : GcrSystemPrompter *self = g_object_ref (active->prompter);
582 : 30 : GError *error = NULL;
583 : : GVariant *retval;
584 : :
585 [ - + ]: 30 : g_assert (active->ready == FALSE);
586 : :
587 : 30 : g_debug ("returned from the %s method on %s@%s",
588 : : GCR_DBUS_CALLBACK_METHOD_READY, active->callback->path, active->callback->name);
589 : :
590 : 30 : active->ready = TRUE;
591 : 30 : retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
592 : :
593 : : /* Was cancelled, prompter probably unregistered */
594 [ + + + - ]: 36 : if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
595 : 6 : g_cancellable_is_cancelled (active->cancellable)) {
596 : 6 : g_error_free (error);
597 : :
598 : : /* The ready call failed, */
599 [ - + ]: 24 : } else if (error != NULL) {
600 [ # # ]: 0 : if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
601 : 0 : g_debug ("prompt %s@%s disappeared or does not exist",
602 : : active->callback->path, active->callback->name);
603 : : else
604 : 0 : g_message ("received an error from the prompt callback: %s", error->message);
605 : 0 : g_error_free (error);
606 : :
607 : 0 : prompt_stop_prompting (self, active->callback, FALSE, FALSE);
608 : :
609 : : /* Another new prompt may be ready to go active? */
610 : 0 : prompt_next_ready (self);
611 : : }
612 : :
613 [ + + ]: 30 : if (retval != NULL)
614 : 24 : g_variant_unref (retval);
615 : :
616 : 30 : active_prompt_unref (active);
617 : 30 : g_object_unref (self);
618 : 30 : }
619 : :
620 : : static void
621 : 30 : prompt_send_ready (ActivePrompt *active,
622 : : const gchar *response,
623 : : const gchar *secret)
624 : : {
625 : : GcrSystemPrompter *self;
626 : : GVariantBuilder *builder;
627 : : GcrSecretExchange *exchange;
628 : : gchar *sent;
629 : :
630 [ - + ]: 30 : g_assert (active->ready == FALSE);
631 : :
632 : 30 : exchange = active_prompt_get_secret_exchange (active);
633 [ + + ]: 30 : if (!active->received) {
634 [ - + ]: 18 : g_return_if_fail (secret == NULL);
635 : 18 : sent = gcr_secret_exchange_begin (exchange);
636 : : } else {
637 : 12 : sent = gcr_secret_exchange_send (exchange, secret, -1);
638 : : }
639 : :
640 : 30 : self = active->prompter;
641 : 30 : builder = prompt_build_properties (active->prompt, active->changed);
642 : :
643 : 30 : g_debug ("calling the %s method on %s@%s",
644 : : GCR_DBUS_CALLBACK_METHOD_READY, active->callback->path, active->callback->name);
645 : :
646 : 30 : g_dbus_connection_call (self->pv->connection,
647 : 30 : active->callback->name,
648 : 30 : active->callback->path,
649 : : GCR_DBUS_CALLBACK_INTERFACE,
650 : : GCR_DBUS_CALLBACK_METHOD_READY,
651 : : g_variant_new ("(sa{sv}s)", response, builder, sent),
652 : : G_VARIANT_TYPE ("()"),
653 : : G_DBUS_CALL_FLAGS_NO_AUTO_START,
654 : : -1, active->cancellable,
655 : : on_prompt_ready_complete,
656 : 30 : active_prompt_ref (active));
657 : :
658 : 30 : g_variant_builder_unref (builder);
659 : 30 : g_free (sent);
660 : : }
661 : :
662 : : static void
663 : 26 : prompt_next_ready (GcrSystemPrompter *self)
664 : : {
665 : : ActivePrompt *active;
666 : : Callback *callback;
667 : :
668 [ + - + + ]: 52 : if (self->pv->mode == GCR_SYSTEM_PROMPTER_SINGLE &&
669 : 26 : g_hash_table_size (self->pv->active) > 0)
670 : 5 : return;
671 : :
672 : 21 : callback = g_queue_pop_head (&self->pv->waiting);
673 [ + + ]: 21 : if (callback == NULL)
674 : 3 : return;
675 : :
676 : 18 : g_debug ("preparing a prompt for callback %s@%s",
677 : : callback->path, callback->name);
678 : :
679 : 18 : active = g_hash_table_lookup (self->pv->active, callback);
680 [ - + ]: 18 : g_assert (active == NULL);
681 : :
682 : 18 : active = active_prompt_create (self, callback);
683 [ - + ]: 18 : g_return_if_fail (active != NULL);
684 : :
685 : 18 : prompt_send_ready (active, GCR_DBUS_PROMPT_REPLY_NONE, NULL);
686 : : }
687 : :
688 : : static void
689 : 14 : prompt_update_properties (GcrPrompt *prompt,
690 : : GVariantIter *iter)
691 : : {
692 : 14 : GObject *obj = G_OBJECT (prompt);
693 : : gchar *property_name;
694 : : GVariant *variant;
695 : : GValue value;
696 : :
697 : 14 : g_object_freeze_notify (obj);
698 [ + + ]: 128 : while (g_variant_iter_loop (iter, "{&sv}", &property_name, &variant)) {
699 : 114 : memset (&value, 0, sizeof (GValue));
700 : 114 : g_dbus_gvariant_to_gvalue (variant, &value);
701 : 114 : g_object_set_property (obj, property_name, &value);
702 : 114 : g_value_unset (&value);
703 : : }
704 : 14 : g_object_thaw_notify (obj);
705 : 14 : }
706 : :
707 : : static GVariant *
708 : 0 : prompter_get_property (GDBusConnection *connection,
709 : : const gchar *sender,
710 : : const gchar *object_path,
711 : : const gchar *interface_name,
712 : : const gchar *property_name,
713 : : GError **error,
714 : : gpointer user_data)
715 : : {
716 : 0 : g_return_val_if_reached (NULL);
717 : : }
718 : :
719 : : static gboolean
720 : 0 : prompter_set_property (GDBusConnection *connection,
721 : : const gchar *sender,
722 : : const gchar *object_path,
723 : : const gchar *interface_name,
724 : : const gchar *property_name,
725 : : GVariant *value,
726 : : GError **error,
727 : : gpointer user_data)
728 : : {
729 : 0 : g_return_val_if_reached (FALSE);
730 : : }
731 : :
732 : : static void
733 : 1 : on_caller_vanished (GDBusConnection *connection,
734 : : const gchar *name,
735 : : gpointer user_data)
736 : : {
737 : 1 : GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (user_data);
738 : 1 : GQueue queue = G_QUEUE_INIT;
739 : : Callback *callback;
740 : : GHashTableIter iter;
741 : :
742 : 1 : g_hash_table_iter_init (&iter, self->pv->callbacks);
743 [ + + ]: 4 : while (g_hash_table_iter_next (&iter, (gpointer *)&callback, NULL)) {
744 [ + - ]: 2 : if (g_strcmp0 (name, callback->name) == 0)
745 : 2 : g_queue_push_tail (&queue, callback);
746 : : }
747 : :
748 [ + + ]: 3 : while ((callback = g_queue_pop_head (&queue)) != NULL) {
749 : 2 : g_debug ("caller vanished for callback %s@%s",
750 : : callback->path, callback->name);
751 : 2 : prompt_stop_prompting (self, callback, FALSE, FALSE);
752 : : }
753 : 1 : }
754 : :
755 : : static void
756 : 21 : prompter_method_begin_prompting (GcrSystemPrompter *self,
757 : : GDBusMethodInvocation *invocation,
758 : : GVariant *parameters)
759 : : {
760 : : Callback lookup;
761 : : Callback *callback;
762 : : const gchar *caller;
763 : : guint watch_id;
764 : :
765 : 21 : lookup.name = caller = g_dbus_method_invocation_get_sender (invocation);
766 : 21 : g_variant_get (parameters, "(&o)", &lookup.path);
767 : :
768 : 21 : g_debug ("received %s call from callback %s@%s",
769 : : GCR_DBUS_PROMPTER_METHOD_BEGIN,
770 : : lookup.path, lookup.name);
771 : :
772 [ - + ]: 21 : if (g_hash_table_lookup (self->pv->callbacks, &lookup)) {
773 : 0 : g_debug ("already begun prompting for callback %s@%s",
774 : : lookup.path, lookup.name);
775 : 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
776 : : "Already begun prompting for this prompt callback");
777 : 0 : return;
778 : : }
779 : :
780 : 21 : callback = callback_dup (&lookup);
781 : 21 : watch_id = g_bus_watch_name_on_connection (self->pv->connection, caller,
782 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
783 : : NULL, on_caller_vanished,
784 : : self, NULL);
785 : 21 : g_hash_table_insert (self->pv->callbacks, callback, GUINT_TO_POINTER (watch_id));
786 : :
787 : 21 : g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
788 : :
789 : 21 : g_queue_push_tail (&self->pv->waiting, callback);
790 : 21 : g_object_notify (G_OBJECT (self), "prompting");
791 : :
792 : 21 : prompt_next_ready (self);
793 : : }
794 : :
795 : : static void
796 : 5 : on_prompt_password (GObject *source,
797 : : GAsyncResult *result,
798 : : gpointer user_data)
799 : : {
800 : 5 : ActivePrompt *active = user_data;
801 : : const gchar *reply;
802 : 5 : GError *error = NULL;
803 : : const gchar *response;
804 : :
805 [ - + ]: 5 : g_assert (active->ready == FALSE);
806 [ - + ]: 5 : g_assert (active->callback != NULL);
807 : :
808 : 5 : g_debug ("completed password prompt for callback %s@%s",
809 : : active->callback->name, active->callback->path);
810 : :
811 : 5 : reply = gcr_prompt_password_finish (GCR_PROMPT (source), result, &error);
812 [ - + ]: 5 : if (error != NULL) {
813 [ # # ]: 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
814 : 0 : g_warning ("prompting failed: %s", error->message);
815 : 0 : g_clear_error (&error);
816 : : }
817 : :
818 [ + + ]: 5 : if (reply == NULL)
819 : 1 : response = "no";
820 : : else
821 : 4 : response = "yes";
822 : :
823 : 5 : prompt_send_ready (active, response, reply);
824 : 5 : active_prompt_unref (active);
825 : 5 : }
826 : :
827 : : static void
828 : 7 : on_prompt_confirm (GObject *source,
829 : : GAsyncResult *result,
830 : : gpointer user_data)
831 : : {
832 : 7 : ActivePrompt *active = user_data;
833 : : GcrPromptReply reply;
834 : 7 : GError *error = NULL;
835 : : const gchar *response;
836 : :
837 [ - + ]: 7 : g_assert (active->ready == FALSE);
838 [ - + ]: 7 : g_assert (active->callback != NULL);
839 : :
840 : 7 : g_debug ("completed confirm prompt for callback %s@%s",
841 : : active->callback->name, active->callback->path);
842 : :
843 : 7 : reply = gcr_prompt_confirm_finish (GCR_PROMPT (source), result, &error);
844 [ - + ]: 7 : if (error != NULL) {
845 [ # # ]: 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
846 : 0 : g_warning ("prompting failed: %s", error->message);
847 : 0 : g_clear_error (&error);
848 : : }
849 : :
850 [ + + - ]: 7 : switch (reply) {
851 : 5 : case GCR_PROMPT_REPLY_CONTINUE:
852 : 5 : response = GCR_DBUS_PROMPT_REPLY_YES;
853 : 5 : break;
854 : 2 : case GCR_PROMPT_REPLY_CANCEL:
855 : 2 : response = GCR_DBUS_PROMPT_REPLY_NO;
856 : 2 : break;
857 : 0 : default:
858 : 0 : response = GCR_DBUS_PROMPT_REPLY_NONE;
859 : 0 : g_warn_if_reached ();
860 : 0 : break;
861 : : }
862 : :
863 : 7 : prompt_send_ready (active, response, NULL);
864 : 7 : active_prompt_unref (active);
865 : 7 : }
866 : :
867 : : static void
868 : 14 : prompter_method_perform_prompt (GcrSystemPrompter *self,
869 : : GDBusMethodInvocation *invocation,
870 : : GVariant *parameters)
871 : : {
872 : : GcrSecretExchange *exchange;
873 : 14 : GError *error = NULL;
874 : : ActivePrompt *active;
875 : : Callback lookup;
876 : : const gchar *type;
877 : : GVariantIter *iter;
878 : : const gchar *received;
879 : :
880 : 14 : lookup.name = g_dbus_method_invocation_get_sender (invocation);
881 : 14 : g_variant_get (parameters, "(&o&sa{sv}&s)",
882 : : &lookup.path, &type, &iter, &received);
883 : :
884 : 14 : g_debug ("received %s call from callback %s@%s",
885 : : GCR_DBUS_PROMPTER_METHOD_PERFORM,
886 : : lookup.path, lookup.name);
887 : :
888 : 14 : active = g_hash_table_lookup (self->pv->active, &lookup);
889 [ - + ]: 14 : if (active == NULL) {
890 : 0 : g_debug ("not begun prompting for this callback %s@%s",
891 : : lookup.path, lookup.name);
892 : 0 : error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
893 : : "Not begun prompting for this prompt callback");
894 : :
895 [ - + ]: 14 : } else if (!active->ready) {
896 : 0 : g_debug ("already performing prompt for this callback %s@%s",
897 : : lookup.path, lookup.name);
898 : 0 : error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
899 : : "Already performing a prompt for this prompt callback");
900 : : }
901 : :
902 [ - + ]: 14 : if (error != NULL) {
903 : 0 : g_dbus_method_invocation_take_error (invocation, error);
904 : 0 : g_variant_iter_free (iter);
905 : 0 : return;
906 : : }
907 : :
908 [ - + ]: 14 : g_assert (active != NULL);
909 : 14 : prompt_update_properties (active->prompt, iter);
910 : 14 : g_variant_iter_free (iter);
911 : :
912 : 14 : exchange = active_prompt_get_secret_exchange (active);
913 [ - + ]: 14 : if (!gcr_secret_exchange_receive (exchange, received)) {
914 : 0 : g_debug ("received invalid secret exchange from callback %s@%s",
915 : : lookup.path, lookup.name);
916 : 0 : g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
917 : : "Invalid secret exchange received");
918 : 0 : return;
919 : : }
920 : :
921 : 14 : active->received = TRUE;
922 : :
923 [ + + ]: 14 : if (g_strcmp0 (type, GCR_DBUS_PROMPT_TYPE_CONFIRM) == 0) {
924 : 7 : active->ready = FALSE;
925 : 7 : g_debug ("starting confirm prompt for callback %s@%s",
926 : : lookup.path, lookup.name);
927 : 7 : gcr_prompt_confirm_async (active->prompt, active->cancellable,
928 : 7 : on_prompt_confirm, active_prompt_ref (active));
929 : :
930 [ + - ]: 7 : } else if (g_strcmp0 (type, GCR_DBUS_PROMPT_TYPE_PASSWORD) == 0) {
931 : 7 : active->ready = FALSE;
932 : 7 : g_debug ("starting password prompt for callback %s@%s",
933 : : lookup.path, lookup.name);
934 : 7 : gcr_prompt_password_async (active->prompt, active->cancellable,
935 : 7 : on_prompt_password, active_prompt_ref (active));
936 : :
937 : : } else {
938 : 0 : g_debug ("invalid type of prompt from callback %s@%s",
939 : : lookup.path, lookup.name);
940 : 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
941 : : "Invalid type argument");
942 : 0 : return;
943 : : }
944 : :
945 : 14 : g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
946 : : }
947 : :
948 : : static void
949 : 5 : prompter_method_stop_prompting (GcrSystemPrompter *self,
950 : : GDBusMethodInvocation *invocation,
951 : : GVariant *parameters)
952 : : {
953 : : Callback lookup;
954 : :
955 : 5 : lookup.name = g_dbus_method_invocation_get_sender (invocation);
956 : 5 : g_variant_get (parameters, "(&o)", &lookup.path);
957 : :
958 : 5 : g_debug ("received %s call from callback %s@%s",
959 : : GCR_DBUS_PROMPTER_METHOD_PERFORM,
960 : : lookup.path, lookup.name);
961 : :
962 : 5 : prompt_stop_prompting (self, &lookup, TRUE, FALSE);
963 : :
964 : 5 : g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
965 : 5 : prompt_next_ready (self);
966 : 5 : }
967 : :
968 : : static void
969 : 40 : prompter_method_call (GDBusConnection *connection,
970 : : const gchar *sender,
971 : : const gchar *object_path,
972 : : const gchar *interface_name,
973 : : const gchar *method_name,
974 : : GVariant *parameters,
975 : : GDBusMethodInvocation *invocation,
976 : : gpointer user_data)
977 : : {
978 : 40 : GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (user_data);
979 : :
980 [ - + ]: 40 : g_return_if_fail (method_name != NULL);
981 : :
982 [ + + ]: 40 : if (g_str_equal (method_name, GCR_DBUS_PROMPTER_METHOD_BEGIN)) {
983 : 21 : prompter_method_begin_prompting (self, invocation, parameters);
984 : :
985 [ + + ]: 19 : } else if (g_str_equal (method_name, GCR_DBUS_PROMPTER_METHOD_PERFORM)) {
986 : 14 : prompter_method_perform_prompt (self, invocation, parameters);
987 : :
988 [ + - ]: 5 : } else if (g_str_equal (method_name, GCR_DBUS_PROMPTER_METHOD_STOP)) {
989 : 5 : prompter_method_stop_prompting (self, invocation, parameters);
990 : :
991 : : } else {
992 : 0 : g_return_if_reached ();
993 : : }
994 : : }
995 : :
996 : : static GDBusInterfaceVTable prompter_dbus_vtable = {
997 : : prompter_method_call,
998 : : prompter_get_property,
999 : : prompter_set_property,
1000 : : };
1001 : :
1002 : : /**
1003 : : * gcr_system_prompter_register:
1004 : : * @self: the system prompter
1005 : : * @connection: a DBus connection
1006 : : *
1007 : : * Register this system prompter on the DBus @connection.
1008 : : *
1009 : : * This makes the prompter available for clients to call. The prompter will
1010 : : * remain registered until gcr_system_prompter_unregister() is called, or the
1011 : : * prompter is unreferenced.
1012 : : */
1013 : : void
1014 : 18 : gcr_system_prompter_register (GcrSystemPrompter *self,
1015 : : GDBusConnection *connection)
1016 : : {
1017 : 18 : GError *error = NULL;
1018 : :
1019 [ - + + - : 18 : g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
+ - - + ]
1020 [ - + ]: 18 : g_return_if_fail (G_DBUS_CONNECTION (connection));
1021 [ - + ]: 18 : g_return_if_fail (self->pv->prompter_registered == 0);
1022 [ - + ]: 18 : g_return_if_fail (self->pv->connection == NULL);
1023 : :
1024 : 18 : g_debug ("registering prompter");
1025 : :
1026 : 18 : self->pv->connection = g_object_ref (connection);
1027 : :
1028 : 18 : self->pv->prompter_registered = g_dbus_connection_register_object (connection,
1029 : : GCR_DBUS_PROMPTER_OBJECT_PATH,
1030 : : _gcr_dbus_prompter_interface_info (),
1031 : : &prompter_dbus_vtable,
1032 : : self, NULL, &error);
1033 [ - + ]: 18 : if (error != NULL) {
1034 : 0 : g_warning ("error registering prompter %s", egg_error_message (error));
1035 : 0 : g_clear_error (&error);
1036 : : }
1037 : : }
1038 : :
1039 : : /**
1040 : : * gcr_system_prompter_unregister:
1041 : : * @self: the system prompter
1042 : : * @wait: whether to wait for closing prompts
1043 : : *
1044 : : * Unregister this system prompter on the DBus @connection.
1045 : : *
1046 : : * The prompter must have previously been registered with gcr_system_prompter_register().
1047 : : *
1048 : : * If @wait is set then this function will wait until all prompts have been closed
1049 : : * or cancelled. This is usually only used by tests.
1050 : : */
1051 : : void
1052 : 18 : gcr_system_prompter_unregister (GcrSystemPrompter *self,
1053 : : gboolean wait)
1054 : : {
1055 : : GList *callbacks;
1056 : : GList *l;
1057 : :
1058 [ - + + - : 18 : g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
+ - - + ]
1059 [ - + ]: 18 : g_return_if_fail (self->pv->prompter_registered != 0);
1060 : :
1061 : 18 : g_debug ("unregistering prompter");
1062 : :
1063 : 18 : callbacks = g_hash_table_get_keys (self->pv->callbacks);
1064 [ + - + + ]: 31 : for (l = callbacks; l != NULL; l = g_list_next (l))
1065 : 13 : prompt_stop_prompting (self, l->data, TRUE, wait);
1066 : 18 : g_list_free (callbacks);
1067 : :
1068 [ - + ]: 18 : g_assert (g_hash_table_size (self->pv->active) == 0);
1069 [ - + ]: 18 : g_assert (g_hash_table_size (self->pv->callbacks) == 0);
1070 [ - + ]: 18 : g_assert (g_queue_is_empty (&self->pv->waiting));
1071 : :
1072 [ - + ]: 18 : if (!g_dbus_connection_unregister_object (self->pv->connection, self->pv->prompter_registered))
1073 : 0 : g_assert_not_reached ();
1074 : 18 : self->pv->prompter_registered = 0;
1075 : :
1076 [ + - ]: 18 : g_clear_object (&self->pv->connection);
1077 : : }
1078 : :
1079 : : /**
1080 : : * gcr_system_prompter_new:
1081 : : * @mode: the mode for the prompt
1082 : : * @prompt_type: the gobject type for prompts created by this prompter
1083 : : *
1084 : : * Create a new system prompter service. This prompter won't do anything unless
1085 : : * you connect to its signals and show appropriate prompts.
1086 : : *
1087 : : * If @prompt_type is zero, then the new-prompt signal must be handled and
1088 : : * return a valid prompt object implementing the #GcrPrompt interface.
1089 : : *
1090 : : * If @prompt_type is non-zero then the #GType must implement the #GcrPrompt
1091 : : * interface.
1092 : : *
1093 : : * Returns: (transfer full): a new prompter service
1094 : : */
1095 : : GcrSystemPrompter *
1096 : 18 : gcr_system_prompter_new (GcrSystemPrompterMode mode,
1097 : : GType prompt_type)
1098 : : {
1099 [ + + ]: 18 : if (prompt_type == 0) {
1100 : 8 : return g_object_new (GCR_TYPE_SYSTEM_PROMPTER,
1101 : : "mode", mode,
1102 : : NULL);
1103 : :
1104 : : } else {
1105 : 10 : return g_object_new (GCR_TYPE_SYSTEM_PROMPTER,
1106 : : "mode", mode,
1107 : : "prompt-type", prompt_type,
1108 : : NULL);
1109 : : }
1110 : : }
1111 : :
1112 : : /**
1113 : : * gcr_system_prompter_get_mode:
1114 : : * @self: the prompter
1115 : : *
1116 : : * Get the mode for this prompter.
1117 : : *
1118 : : * Most system prompters only display one prompt at a time and therefore
1119 : : * return %GCR_SYSTEM_PROMPTER_SINGLE.
1120 : : *
1121 : : * Returns: the prompter mode
1122 : : */
1123 : : GcrSystemPrompterMode
1124 : 0 : gcr_system_prompter_get_mode (GcrSystemPrompter *self)
1125 : : {
1126 [ # # # # : 0 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), GCR_SYSTEM_PROMPTER_SINGLE);
# # # # ]
1127 : 0 : return self->pv->mode;
1128 : : }
1129 : :
1130 : : /**
1131 : : * gcr_system_prompter_get_prompt_type:
1132 : : * @self: the prompter
1133 : : *
1134 : : * Get the #GType for prompts created by this prompter.
1135 : : *
1136 : : * The returned #GType will be a #GcrPrompt implementation.
1137 : : *
1138 : : * Returns: the prompt #GType
1139 : : */
1140 : : GType
1141 : 0 : gcr_system_prompter_get_prompt_type (GcrSystemPrompter *self)
1142 : : {
1143 [ # # # # : 0 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), 0);
# # # # ]
1144 : 0 : return self->pv->prompt_type;
1145 : : }
1146 : :
1147 : : /**
1148 : : * gcr_system_prompter_get_prompting:
1149 : : * @self: the prompter
1150 : : *
1151 : : * Get whether prompting or not.
1152 : : *
1153 : : * Returns: whether prompting or not
1154 : : */
1155 : : gboolean
1156 : 0 : gcr_system_prompter_get_prompting (GcrSystemPrompter *self)
1157 : : {
1158 [ # # # # : 0 : g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), FALSE);
# # # # ]
1159 : 0 : return g_hash_table_size (self->pv->callbacks);
1160 : : }
|