gnome-shell-3.6.3.1/src/shell-keyring-prompt.c

No issues found

  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 /*
  3  * Copyright 2012 Red Hat, Inc.
  4  *           2012 Stef Walter <stefw@gnome.org>
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License as published by
  8  * the Free Software Foundation; either version 2 of the License, or
  9  * (at your option) any later version.
 10  *
 11  * This program is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  * GNU General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU General Public License along
 17  * with this program; if not, write to the Free Software Foundation, Inc.,
 18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Author: Stef Walter <stefw@gnome.org>
 21  */
 22 
 23 #include "config.h"
 24 
 25 #include "shell-keyring-prompt.h"
 26 #include "shell-secure-text-buffer.h"
 27 
 28 #define GCR_API_SUBJECT_TO_CHANGE
 29 #include <gcr/gcr-base.h>
 30 
 31 #include <glib/gi18n.h>
 32 
 33 #include <string.h>
 34 
 35 typedef struct _ShellPasswordPromptClass    ShellPasswordPromptClass;
 36 typedef struct _ShellPasswordPromptPrivate  ShellPasswordPromptPrivate;
 37 
 38 typedef enum
 39 {
 40   PROMPTING_NONE,
 41   PROMPTING_FOR_CONFIRM,
 42   PROMPTING_FOR_PASSWORD
 43 } PromptingMode;
 44 
 45 struct _ShellKeyringPrompt
 46 {
 47   GObject parent;
 48 
 49   gchar *title;
 50   gchar *message;
 51   gchar *description;
 52   gchar *warning;
 53   gchar *choice_label;
 54   gboolean choice_chosen;
 55   gboolean password_new;
 56   guint password_strength;
 57   gchar *continue_label;
 58   gchar *cancel_label;
 59 
 60   GcrPromptReply last_reply;
 61   GSimpleAsyncResult *async_result;
 62   ClutterText *password_actor;
 63   ClutterText *confirm_actor;
 64   PromptingMode mode;
 65   gboolean shown;
 66 };
 67 
 68 typedef struct _ShellKeyringPromptClass
 69 {
 70   GObjectClass parent_class;
 71 } ShellKeyringPromptClass;
 72 
 73 enum {
 74   PROP_0,
 75   PROP_TITLE,
 76   PROP_MESSAGE,
 77   PROP_DESCRIPTION,
 78   PROP_WARNING,
 79   PROP_CHOICE_LABEL,
 80   PROP_CHOICE_CHOSEN,
 81   PROP_PASSWORD_NEW,
 82   PROP_PASSWORD_STRENGTH,
 83   PROP_CALLER_WINDOW,
 84   PROP_CONTINUE_LABEL,
 85   PROP_CANCEL_LABEL,
 86   PROP_PASSWORD_VISIBLE,
 87   PROP_CONFIRM_VISIBLE,
 88   PROP_WARNING_VISIBLE,
 89   PROP_CHOICE_VISIBLE,
 90   PROP_PASSWORD_ACTOR,
 91   PROP_CONFIRM_ACTOR
 92 };
 93 
 94 static void    shell_keyring_prompt_iface     (GcrPromptIface *iface);
 95 
 96 G_DEFINE_TYPE_WITH_CODE (ShellKeyringPrompt, shell_keyring_prompt, G_TYPE_OBJECT,
 97                          G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, shell_keyring_prompt_iface);
 98 );
 99 
100 enum {
101   SIGNAL_SHOW_PASSWORD,
102   SIGNAL_SHOW_CONFIRM,
103   SIGNAL_HIDE_PROMPT,
104   SIGNAL_LAST
105 };
106 
107 static gint signals[SIGNAL_LAST];
108 
109 static void
110 shell_keyring_prompt_init (ShellKeyringPrompt *self)
111 {
112 
113 }
114 
115 static void
116 shell_keyring_prompt_set_property (GObject      *obj,
117                                    guint         prop_id,
118                                    const GValue *value,
119                                    GParamSpec   *pspec)
120 {
121   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (obj);
122 
123   switch (prop_id) {
124   case PROP_TITLE:
125     g_free (self->title);
126     self->title = g_value_dup_string (value);
127     g_object_notify (obj, "title");
128     break;
129   case PROP_MESSAGE:
130     g_free (self->message);
131     self->message = g_value_dup_string (value);
132     g_object_notify (obj, "message");
133     break;
134   case PROP_DESCRIPTION:
135     g_free (self->description);
136     self->description = g_value_dup_string (value);
137     g_object_notify (obj, "description");
138     break;
139   case PROP_WARNING:
140     g_free (self->warning);
141     self->warning = g_value_dup_string (value);
142     if (!self->warning)
143         self->warning = g_strdup ("");
144     g_object_notify (obj, "warning");
145     g_object_notify (obj, "warning-visible");
146     break;
147   case PROP_CHOICE_LABEL:
148     g_free (self->choice_label);
149     self->choice_label = g_value_dup_string (value);
150     if (!self->choice_label)
151         self->choice_label = g_strdup ("");
152     g_object_notify (obj, "choice-label");
153     g_object_notify (obj, "choice-visible");
154     break;
155   case PROP_CHOICE_CHOSEN:
156     self->choice_chosen = g_value_get_boolean (value);
157     g_object_notify (obj, "choice-chosen");
158     break;
159   case PROP_PASSWORD_NEW:
160     self->password_new = g_value_get_boolean (value);
161     g_object_notify (obj, "password-new");
162     g_object_notify (obj, "confirm-visible");
163     break;
164   case PROP_CALLER_WINDOW:
165     /* ignored */
166     break;
167   case PROP_CONTINUE_LABEL:
168     g_free (self->continue_label);
169     self->continue_label = g_value_dup_string (value);
170     g_object_notify (obj, "continue-label");
171     break;
172   case PROP_CANCEL_LABEL:
173     g_free (self->cancel_label);
174     self->cancel_label = g_value_dup_string (value);
175     g_object_notify (obj, "cancel-label");
176     break;
177   case PROP_PASSWORD_ACTOR:
178     shell_keyring_prompt_set_password_actor (self, g_value_get_object (value));
179     break;
180   case PROP_CONFIRM_ACTOR:
181     shell_keyring_prompt_set_confirm_actor (self, g_value_get_object (value));
182     break;
183   default:
184     G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
185     break;
186   }
187 }
188 
189 static void
190 shell_keyring_prompt_get_property (GObject    *obj,
191                                    guint       prop_id,
192                                    GValue     *value,
193                                    GParamSpec *pspec)
194 {
195   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (obj);
196 
197   switch (prop_id) {
198   case PROP_TITLE:
199     g_value_set_string (value, self->title ? self->title : "");
200     break;
201   case PROP_MESSAGE:
202     g_value_set_string (value, self->message ? self->message : "");
203     break;
204   case PROP_DESCRIPTION:
205     g_value_set_string (value, self->description ? self->description : "");
206     break;
207   case PROP_WARNING:
208     g_value_set_string (value, self->warning ? self->warning : "");
209     break;
210   case PROP_CHOICE_LABEL:
211     g_value_set_string (value, self->choice_label ? self->choice_label : "");
212     break;
213   case PROP_CHOICE_CHOSEN:
214     g_value_set_boolean (value, self->choice_chosen);
215     break;
216   case PROP_PASSWORD_NEW:
217     g_value_set_boolean (value, self->password_new);
218     break;
219   case PROP_PASSWORD_STRENGTH:
220     g_value_set_int (value, self->password_strength);
221     break;
222   case PROP_CALLER_WINDOW:
223     g_value_set_string (value, "");
224     break;
225   case PROP_CONTINUE_LABEL:
226     g_value_set_string (value, self->continue_label);
227     break;
228   case PROP_CANCEL_LABEL:
229     g_value_set_string (value, self->cancel_label);
230     break;
231   case PROP_PASSWORD_VISIBLE:
232     g_value_set_boolean (value, self->mode == PROMPTING_FOR_PASSWORD);
233     break;
234   case PROP_CONFIRM_VISIBLE:
235     g_value_set_boolean (value, self->password_new &&
236                                 self->mode == PROMPTING_FOR_PASSWORD);
237     break;
238   case PROP_WARNING_VISIBLE:
239     g_value_set_boolean (value, self->warning && self->warning[0]);
240     break;
241   case PROP_CHOICE_VISIBLE:
242     g_value_set_boolean (value, self->choice_label && self->choice_label[0]);
243     break;
244   case PROP_PASSWORD_ACTOR:
245     g_value_set_object (value, shell_keyring_prompt_get_password_actor (self));
246     break;
247   case PROP_CONFIRM_ACTOR:
248     g_value_set_object (value, shell_keyring_prompt_get_confirm_actor (self));
249     break;
250   default:
251     G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
252     break;
253   }
254 }
255 
256 static void
257 shell_keyring_prompt_dispose (GObject *obj)
258 {
259   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (obj);
260 
261   if (self->shown) {
262     self->shown = FALSE;
263     g_signal_emit (self, signals[SIGNAL_HIDE_PROMPT], 0);
264   }
265 
266   if (self->async_result)
267     shell_keyring_prompt_cancel (self);
268   g_assert (self->async_result == NULL);
269 
270   shell_keyring_prompt_set_password_actor (self, NULL);
271   shell_keyring_prompt_set_confirm_actor (self, NULL);
272 
273   G_OBJECT_CLASS (shell_keyring_prompt_parent_class)->dispose (obj);
274 }
275 
276 static void
277 shell_keyring_prompt_finalize (GObject *obj)
278 {
279   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (obj);
280 
281   g_free (self->title);
282   g_free (self->message);
283   g_free (self->description);
284   g_free (self->warning);
285   g_free (self->choice_label);
286   g_free (self->continue_label);
287   g_free (self->cancel_label);
288 
289   G_OBJECT_CLASS (shell_keyring_prompt_parent_class)->finalize (obj);
290 }
291 
292 static void
293 shell_keyring_prompt_class_init (ShellKeyringPromptClass *klass)
294 {
295   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
296 
297   gobject_class->get_property = shell_keyring_prompt_get_property;
298   gobject_class->set_property = shell_keyring_prompt_set_property;
299   gobject_class->dispose = shell_keyring_prompt_dispose;
300   gobject_class->finalize = shell_keyring_prompt_finalize;
301 
302   g_object_class_override_property (gobject_class, PROP_TITLE, "title");
303 
304   g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
305 
306   g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
307 
308   g_object_class_override_property (gobject_class, PROP_WARNING, "warning");
309 
310   g_object_class_override_property (gobject_class, PROP_PASSWORD_NEW, "password-new");
311 
312   g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
313 
314   g_object_class_override_property (gobject_class, PROP_CHOICE_LABEL, "choice-label");
315 
316   g_object_class_override_property (gobject_class, PROP_CHOICE_CHOSEN, "choice-chosen");
317 
318   g_object_class_override_property (gobject_class, PROP_CALLER_WINDOW, "caller-window");
319 
320   g_object_class_override_property (gobject_class, PROP_CONTINUE_LABEL, "continue-label");
321 
322   g_object_class_override_property (gobject_class, PROP_CANCEL_LABEL, "cancel-label");
323 
324   /**
325    * ShellKeyringPrompt:password-visible:
326    *
327    * Whether the password entry is visible or not.
328    */
329   g_object_class_install_property (gobject_class, PROP_PASSWORD_VISIBLE,
330              g_param_spec_boolean ("password-visible", "Password visible", "Password field is visible",
331                                    FALSE, G_PARAM_READABLE));
332 
333   /**
334     * ShellKeyringPrompt:confirm-visible:
335     *
336     * Whether the password confirm entry is visible or not.
337     */
338   g_object_class_install_property (gobject_class, PROP_CONFIRM_VISIBLE,
339              g_param_spec_boolean ("confirm-visible", "Confirm visible", "Confirm field is visible",
340                                    FALSE, G_PARAM_READABLE));
341 
342   /**
343    * ShellKeyringPrompt:warning-visible:
344    *
345    * Whether the warning label is visible or not.
346    */
347   g_object_class_install_property (gobject_class, PROP_WARNING_VISIBLE,
348              g_param_spec_boolean ("warning-visible", "Warning visible", "Warning is visible",
349                                    FALSE, G_PARAM_READABLE));
350 
351   /**
352    * ShellKeyringPrompt:choice-visible:
353    *
354    * Whether the choice check box is visible or not.
355    */
356   g_object_class_install_property (gobject_class, PROP_CHOICE_VISIBLE,
357              g_param_spec_boolean ("choice-visible", "Choice visible", "Choice is visible",
358                                    FALSE, G_PARAM_READABLE));
359 
360   /**
361    * ShellKeyringPrompt:password-actor:
362    *
363    * Text field for password
364    */
365   g_object_class_install_property (gobject_class, PROP_PASSWORD_ACTOR,
366               g_param_spec_object ("password-actor", "Password actor", "Text field for password",
367                                    CLUTTER_TYPE_TEXT, G_PARAM_READWRITE));
368 
369   /**
370    * ShellKeyringPrompt:confirm-actor:
371    *
372    * Text field for confirmation password
373    */
374   g_object_class_install_property (gobject_class, PROP_CONFIRM_ACTOR,
375               g_param_spec_object ("confirm-actor", "Confirm actor", "Text field for confirming password",
376                                    CLUTTER_TYPE_TEXT, G_PARAM_READWRITE));
377 
378   signals[SIGNAL_SHOW_PASSWORD] = g_signal_new ("show-password", G_TYPE_FROM_CLASS (klass),
379                                                 0, 0, NULL, NULL,
380                                                 g_cclosure_marshal_VOID__VOID,
381                                                 G_TYPE_NONE, 0);
382 
383   signals[SIGNAL_SHOW_CONFIRM] =  g_signal_new ("show-confirm", G_TYPE_FROM_CLASS (klass),
384                                                 0, 0, NULL, NULL,
385                                                 g_cclosure_marshal_VOID__VOID,
386                                                 G_TYPE_NONE, 0);
387 
388   signals[SIGNAL_HIDE_PROMPT] =  g_signal_new ("hide-prompt", G_TYPE_FROM_CLASS (klass),
389                                                0, 0, NULL, NULL,
390                                                g_cclosure_marshal_VOID__VOID,
391                                                G_TYPE_NONE, 0);
392 }
393 
394 static void
395 shell_keyring_prompt_password_async (GcrPrompt          *prompt,
396                                      GCancellable       *cancellable,
397                                      GAsyncReadyCallback callback,
398                                      gpointer            user_data)
399 {
400   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (prompt);
401   GObject *obj;
402 
403   if (self->async_result != NULL) {
404       g_warning ("this prompt can only show one prompt at a time");
405       return;
406   }
407 
408   self->mode = PROMPTING_FOR_PASSWORD;
409   self->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
410                                                   shell_keyring_prompt_password_async);
411 
412   obj = G_OBJECT (self);
413   g_object_notify (obj, "password-visible");
414   g_object_notify (obj, "confirm-visible");
415   g_object_notify (obj, "warning-visible");
416   g_object_notify (obj, "choice-visible");
417 
418   self->shown = TRUE;
419   g_signal_emit (self, signals[SIGNAL_SHOW_PASSWORD], 0);
420 }
421 
422 static const gchar *
423 shell_keyring_prompt_password_finish (GcrPrompt    *prompt,
424                                       GAsyncResult *result,
425                                       GError      **error)
426 {
427   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (prompt);
428 
429   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
430                         shell_keyring_prompt_password_async), NULL);
431 
432   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
433     return NULL;
434 
435   if (self->last_reply == GCR_PROMPT_REPLY_CONTINUE)
436     return clutter_text_get_text (self->password_actor);
437 
438   return NULL;
439 }
440 
441 static void
442 shell_keyring_prompt_confirm_async (GcrPrompt          *prompt,
443                                     GCancellable       *cancellable,
444                                     GAsyncReadyCallback callback,
445                                     gpointer            user_data)
446 {
447   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (prompt);
448   GObject *obj;
449 
450   if (self->async_result != NULL) {
451       g_warning ("this prompt is already prompting");
452       return;
453   }
454 
455   self->mode = PROMPTING_FOR_CONFIRM;
456   self->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
457                                                   shell_keyring_prompt_confirm_async);
458 
459   obj = G_OBJECT (self);
460   g_object_notify (obj, "password-visible");
461   g_object_notify (obj, "confirm-visible");
462   g_object_notify (obj, "warning-visible");
463   g_object_notify (obj, "choice-visible");
464 
465   self->shown = TRUE;
466   g_signal_emit (self, signals[SIGNAL_SHOW_CONFIRM], 0);
467 }
468 
469 static GcrPromptReply
470 shell_keyring_prompt_confirm_finish (GcrPrompt    *prompt,
471                                      GAsyncResult *result,
472                                      GError      **error)
473 {
474   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (prompt);
475 
476   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
477                         shell_keyring_prompt_confirm_async), GCR_PROMPT_REPLY_CANCEL);
478 
479   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
480     return GCR_PROMPT_REPLY_CANCEL;
481 
482   return self->last_reply;
483 }
484 
485 static void
486 shell_keyring_prompt_iface (GcrPromptIface *iface)
487 {
488   iface->prompt_password_async = shell_keyring_prompt_password_async;
489   iface->prompt_password_finish = shell_keyring_prompt_password_finish;
490   iface->prompt_confirm_async = shell_keyring_prompt_confirm_async;
491   iface->prompt_confirm_finish = shell_keyring_prompt_confirm_finish;
492 }
493 
494 /**
495  * shell_keyring_prompt_new:
496  *
497  * Create new internal prompt base
498  *
499  * Returns: (transfer full): new internal prompt
500  */
501 ShellKeyringPrompt *
502 shell_keyring_prompt_new (void)
503 {
504 	return g_object_new (SHELL_TYPE_KEYRING_PROMPT, NULL);
505 }
506 
507 /**
508  * shell_keyring_prompt_get_password_actor:
509  * @self: the internal prompt
510  *
511  * Get the prompt password text actor
512  *
513  * Returns: (transfer none) (allow-none): the password actor
514  */
515 ClutterText *
516 shell_keyring_prompt_get_password_actor (ShellKeyringPrompt *self)
517 {
518   g_return_val_if_fail (SHELL_IS_KEYRING_PROMPT (self), NULL);
519   return self->password_actor;
520 }
521 
522 /**
523  * shell_keyring_prompt_get_confirm_actor:
524  * @self: the internal prompt
525  *
526  * Get the prompt password text actor
527  *
528  * Returns: (transfer none) (allow-none): the password actor
529  */
530 ClutterText *
531 shell_keyring_prompt_get_confirm_actor (ShellKeyringPrompt *self)
532 {
533   g_return_val_if_fail (SHELL_IS_KEYRING_PROMPT (self), NULL);
534   return self->confirm_actor;
535 }
536 
537 static guint
538 calculate_password_strength (const gchar *password)
539 {
540   int upper, lower, digit, misc;
541   gdouble pwstrength;
542   int length, i;
543 
544   /*
545    * This code is based on the Master Password dialog in Firefox
546    * (pref-masterpass.js)
547    * Original code triple-licensed under the MPL, GPL, and LGPL
548    * so is license-compatible with this file
549    */
550 
551   length = strlen (password);
552 
553   /* Always return 0 for empty passwords */
554   if (length == 0)
555     return 0;
556 
557   upper = 0;
558   lower = 0;
559   digit = 0;
560   misc = 0;
561 
562   for (i = 0; i < length ; i++)
563     {
564       if (g_ascii_isdigit (password[i]))
565         digit++;
566       else if (g_ascii_islower (password[i]))
567         lower++;
568       else if (g_ascii_isupper (password[i]))
569         upper++;
570       else
571         misc++;
572     }
573 
574   if (length > 5)
575     length = 5;
576   if (digit > 3)
577     digit = 3;
578   if (upper > 3)
579     upper = 3;
580   if (misc > 3)
581     misc = 3;
582 
583   pwstrength = ((length * 1) - 2) +
584       (digit * 1) +
585       (misc * 1.5) +
586       (upper * 1);
587 
588   /* Always return 1+ for non-empty passwords */
589   if (pwstrength < 1.0)
590     pwstrength = 1.0;
591   if (pwstrength > 10.0)
592     pwstrength = 10.0;
593 
594   return (guint)pwstrength;
595 }
596 
597 static void
598 on_password_changed (ClutterText *text,
599                      gpointer user_data)
600 {
601   ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (user_data);
602   const gchar *password;
603 
604   password = clutter_text_get_text (self->password_actor);
605 
606   self->password_strength = calculate_password_strength (password);
607   g_object_notify (G_OBJECT (self), "password-strength");
608 }
609 
610 /**
611  * shell_keyring_prompt_set_password_actor:
612  * @self: the internal prompt
613  * @password_actor: (allow-none): the password actor
614  *
615  * Set the prompt password text actor
616  */
617 void
618 shell_keyring_prompt_set_password_actor (ShellKeyringPrompt *self,
619                                          ClutterText *password_actor)
620 {
621   ClutterTextBuffer *buffer;
622 
623   g_return_if_fail (SHELL_IS_KEYRING_PROMPT (self));
624   g_return_if_fail (password_actor == NULL || CLUTTER_IS_TEXT (password_actor));
625 
626   if (password_actor)
627     {
628       buffer = shell_secure_text_buffer_new ();
629       clutter_text_set_buffer (password_actor, buffer);
630       g_object_unref (buffer);
631 
632       g_signal_connect (password_actor, "text-changed", G_CALLBACK (on_password_changed), self);
633       g_object_ref (password_actor);
634     }
635   if (self->password_actor)
636     {
637       g_signal_handlers_disconnect_by_func (self->password_actor, on_password_changed, self);
638       g_object_unref (self->password_actor);
639     }
640 
641   self->password_actor = password_actor;
642   g_object_notify (G_OBJECT (self), "password-actor");
643 }
644 
645 /**
646  * shell_keyring_prompt_set_confirm_actor:
647  * @self: the internal prompt
648  * @confirm_actor: (allow-none): the confirm password actor
649  *
650  * Set the prompt password confirmation text actor
651  */
652 void
653 shell_keyring_prompt_set_confirm_actor (ShellKeyringPrompt *self,
654                                         ClutterText *confirm_actor)
655 {
656   ClutterTextBuffer *buffer;
657 
658   g_return_if_fail (SHELL_IS_KEYRING_PROMPT (self));
659   g_return_if_fail (confirm_actor == NULL || CLUTTER_IS_TEXT (confirm_actor));
660 
661   if (confirm_actor)
662     {
663       buffer = shell_secure_text_buffer_new ();
664       clutter_text_set_buffer (confirm_actor, buffer);
665       g_object_unref (buffer);
666 
667       g_object_ref (confirm_actor);
668     }
669   if (self->confirm_actor)
670     g_object_unref (self->confirm_actor);
671   self->confirm_actor = confirm_actor;
672   g_object_notify (G_OBJECT (self), "confirm-actor");
673 }
674 
675 /**
676  * shell_keyring_prompt_complete:
677  * @self: the internal prompt
678  *
679  * Called by the implementation when the prompt completes. There are various
680  * checks done. %TRUE is returned if the prompt actually should complete.
681  *
682  * Returns: whether the prompt completed
683  */
684 gboolean
685 shell_keyring_prompt_complete (ShellKeyringPrompt *self)
686 {
687   GSimpleAsyncResult *res;
688   const gchar *password;
689   const gchar *confirm;
690   const gchar *env;
691 
692   g_return_val_if_fail (SHELL_IS_KEYRING_PROMPT (self), FALSE);
693   g_return_val_if_fail (self->mode != PROMPTING_NONE, FALSE);
694   g_return_val_if_fail (self->async_result != NULL, FALSE);
695 
696   if (self->mode == PROMPTING_FOR_PASSWORD)
697     {
698       password = clutter_text_get_text (self->password_actor);
699 
700       /* Is it a new password? */
701       if (self->password_new)
702         {
703           confirm = clutter_text_get_text (self->confirm_actor);
704 
705           /* Do the passwords match? */
706           if (!g_str_equal (password, confirm))
707             {
708               gcr_prompt_set_warning (GCR_PROMPT (self), _("Passwords do not match."));
709               return FALSE;
710           }
711 
712           /* Don't allow blank passwords if in paranoid mode */
713           env = g_getenv ("GNOME_KEYRING_PARANOID");
714           if (env && *env)
715             {
716               gcr_prompt_set_warning (GCR_PROMPT (self), _("Password cannot be blank"));
717               return FALSE;
718             }
719         }
720 
721       self->password_strength = calculate_password_strength (password);
722       g_object_notify (G_OBJECT (self), "password-strength");
723     }
724 
725   self->last_reply = GCR_PROMPT_REPLY_CONTINUE;
726 
727   res = self->async_result;
728   self->async_result = NULL;
729   self->mode = PROMPTING_NONE;
730 
731   g_simple_async_result_complete (res);
732   g_object_unref (res);
733 
734   return TRUE;
735 }
736 
737 /**
738  * shell_keyring_prompt_cancel:
739  * @self: the internal prompt
740  *
741  * Called by implementation when the prompt is cancelled.
742  */
743 void
744 shell_keyring_prompt_cancel (ShellKeyringPrompt *self)
745 {
746   GSimpleAsyncResult *res;
747 
748   g_return_if_fail (SHELL_IS_KEYRING_PROMPT (self));
749   g_return_if_fail (self->mode != PROMPTING_NONE);
750   g_return_if_fail (self->async_result != NULL);
751 
752   self->last_reply = GCR_PROMPT_REPLY_CANCEL;
753 
754   res = self->async_result;
755   self->async_result = NULL;
756   self->mode = PROMPTING_NONE;
757 
758   g_simple_async_result_complete (res);
759   g_object_unref (res);
760 }