LCOV - code coverage report
Current view: top level - gcr - gcr-system-prompt.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 600 649 92.4 %
Date: 2022-09-04 10:20:22 Functions: 58 63 92.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 213 364 58.5 %

           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                 :            : }

Generated by: LCOV version 1.14