~kroq-gar78/ubuntu/precise/gnome-control-center/fix-885947

« back to all changes in this revision

Viewing changes to panels/user-accounts/um-password-dialog.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Moya
  • Date: 2011-05-17 10:47:27 UTC
  • mfrom: (0.1.11 experimental) (1.1.45 upstream)
  • Revision ID: james.westby@ubuntu.com-20110517104727-lqel6m8vhfw5jby1
Tags: 1:3.0.1.1-1ubuntu1
* Rebase on Debian, remaining Ubuntu changes:
* debian/control:
  - Build-Depend on hardening-wrapper, dpkg-dev and dh-autoreconf
  - Add dependency on ubuntu-system-service
  - Remove dependency on gnome-icon-theme-symbolic
  - Move dependency on apg, gnome-icon-theme-symbolic and accountsservice to
    be a Recommends: until we get them in main
* debian/rules:
  - Use autoreconf
  - Add binary-post-install rule for gnome-control-center-data
  - Run dh-autoreconf
* debian/gnome-control-center.dirs:
* debian/gnome-control-center.links:
  - Add a link to the control center shell for indicators
* debian/patches/00_disable-nm.patch:
  - Temporary patch to disable building with NetworkManager until we get
    the new one in the archive
* debian/patches/01_git_remove_gettext_calls.patch:
  - Remove calls to AM_GNU_GETTEXT, IT_PROG_INTLTOOL should be enough
* debian/patches/01_git_kill_warning.patch:
  - Kill warning
* debian/patches/50_ubuntu_systemwide_prefs.patch:
  - Ubuntu specific proxy preferences
* debian/patches/51_ubuntu_system_keyboard.patch:
  - Implement the global keyboard spec at https://wiki.ubuntu.com/DefaultKeyboardSettings

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright 2009-2010  Red Hat, Inc,
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 3 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 *
 
19
 * Written by: Matthias Clasen <mclasen@redhat.com>
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <unistd.h>
 
25
#include <stdlib.h>
 
26
#include <sys/types.h>
 
27
#include <sys/wait.h>
 
28
 
 
29
#include <glib.h>
 
30
#include <glib/gi18n.h>
 
31
#include <gtk/gtk.h>
 
32
 
 
33
#include "um-password-dialog.h"
 
34
#include "um-user-manager.h"
 
35
#include "um-strength-bar.h"
 
36
#include "um-utils.h"
 
37
#include "run-passwd.h"
 
38
 
 
39
#define MIN_PASSWORD_LEN 6
 
40
 
 
41
struct _UmPasswordDialog {
 
42
        GtkWidget *dialog;
 
43
        GtkWidget *user_icon;
 
44
        GtkWidget *user_name;
 
45
        GtkWidget *action_label;
 
46
        GtkWidget *action_combo;
 
47
        GtkWidget *password_entry;
 
48
        GtkWidget *verify_entry;
 
49
        GtkWidget *strength_indicator;
 
50
        GtkWidget *strength_indicator_label;
 
51
        GtkWidget *normal_hint_entry;
 
52
        GtkWidget *normal_hint_label;
 
53
        GtkWidget *generate_button;
 
54
        GtkWidget *generate_menu;
 
55
        GtkWidget *show_password_button;
 
56
        GtkWidget *ok_button;
 
57
 
 
58
        UmUser *user;
 
59
 
 
60
        GtkWidget *old_password_label;
 
61
        GtkWidget *old_password_entry;
 
62
        gboolean   old_password_ok;
 
63
 
 
64
        PasswdHandler *passwd_handler;
 
65
};
 
66
 
 
67
static void
 
68
generate_clicked (GtkButton        *button,
 
69
                  UmPasswordDialog *um)
 
70
{
 
71
        gtk_menu_popup (GTK_MENU (um->generate_menu),
 
72
                        NULL, NULL,
 
73
                        (GtkMenuPositionFunc) popup_menu_below_button, um->generate_button,
 
74
                        0, gtk_get_current_event_time ());
 
75
 
 
76
        gtk_widget_set_has_tooltip (um->generate_button, FALSE);
 
77
}
 
78
 
 
79
static void
 
80
generate_draw (GtkWidget        *widget,
 
81
               cairo_t          *cr,
 
82
               UmPasswordDialog *um)
 
83
{
 
84
        if (!gtk_widget_is_sensitive (widget))
 
85
                return;
 
86
 
 
87
        down_arrow (gtk_widget_get_style_context (widget),
 
88
                    cr,
 
89
                    gtk_widget_get_allocated_width (widget) - 12,
 
90
                    gtk_widget_get_allocated_height (widget) - 12,
 
91
                    12, 12);
 
92
}
 
93
 
 
94
static void
 
95
activate_password_item (GtkMenuItem      *item,
 
96
                        UmPasswordDialog *um)
 
97
{
 
98
        const char *password;
 
99
 
 
100
        password = gtk_menu_item_get_label (item);
 
101
 
 
102
        gtk_entry_set_text (GTK_ENTRY (um->password_entry), password);
 
103
        gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
 
104
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->show_password_button), TRUE);
 
105
        gtk_widget_grab_focus (um->verify_entry);
 
106
}
 
107
 
 
108
static void generate_passwords (UmPasswordDialog *um);
 
109
 
 
110
static void
 
111
activate_generate_item (GtkMenuItem      *item,
 
112
                        UmPasswordDialog *um)
 
113
{
 
114
        generate_passwords (um);
 
115
        generate_clicked (GTK_BUTTON (um->generate_button), um);
 
116
}
 
117
 
 
118
static void
 
119
on_generate_menu_unmap (GtkWidget        *menu,
 
120
                        UmPasswordDialog *um)
 
121
{
 
122
        gtk_widget_set_has_tooltip (um->generate_button, TRUE);
 
123
}
 
124
 
 
125
static void
 
126
generate_passwords (UmPasswordDialog *um)
 
127
{
 
128
        gint min_len, max_len;
 
129
        gchar *output, *err, *cmdline;
 
130
        gint status;
 
131
        GError *error;
 
132
        gint i;
 
133
        GtkWidget *item;
 
134
 
 
135
        min_len = 6;
 
136
        max_len = 12;
 
137
 
 
138
        if (um->generate_menu) {
 
139
                gtk_widget_destroy (um->generate_menu);
 
140
        }
 
141
 
 
142
        um->generate_menu = gtk_menu_new ();
 
143
        g_signal_connect (um->generate_menu, "unmap",
 
144
                          G_CALLBACK (on_generate_menu_unmap), um);
 
145
 
 
146
        cmdline = g_strdup_printf ("apg -n 6 -M SNC -m %d -x %d", min_len, max_len);
 
147
        error = NULL;
 
148
        output = NULL;
 
149
        err = NULL;
 
150
        if (!g_spawn_command_line_sync (cmdline, &output, &err, &status, &error)) {
 
151
                g_warning ("Failed to run apg: %s", error->message);
 
152
                g_error_free (error);
 
153
        } else if (WEXITSTATUS (status) == 0) {
 
154
                char **lines;
 
155
                lines = g_strsplit (output, "\n", 0);
 
156
                for (i = 0; lines[i]; i++) {
 
157
                        if (lines[i][0] == 0)
 
158
                                continue;
 
159
 
 
160
                        item = gtk_menu_item_new_with_label (lines[i]);
 
161
                        g_signal_connect (item, "activate",
 
162
                                          G_CALLBACK (activate_password_item), um);
 
163
                        gtk_widget_show (item);
 
164
                        gtk_menu_shell_append (GTK_MENU_SHELL (um->generate_menu), item);
 
165
                }
 
166
                g_strfreev (lines);
 
167
        } else {
 
168
                g_warning ("agp returned an error: %s", err);
 
169
        }
 
170
 
 
171
        g_free (cmdline);
 
172
        g_free (output);
 
173
        g_free (err);
 
174
 
 
175
        item = gtk_separator_menu_item_new ();
 
176
        gtk_widget_show (item);
 
177
        gtk_menu_shell_append (GTK_MENU_SHELL (um->generate_menu), item);
 
178
 
 
179
        item = gtk_menu_item_new_with_label (_("More choices..."));
 
180
        g_signal_connect (item, "activate",
 
181
                          G_CALLBACK (activate_generate_item), um);
 
182
        gtk_widget_show (item);
 
183
        gtk_menu_shell_append (GTK_MENU_SHELL (um->generate_menu), item);
 
184
}
 
185
 
 
186
/* This code is based on the Master Password dialog in Firefox
 
187
 * (pref-masterpass.js)
 
188
 * Original code triple-licensed under the MPL, GPL, and LGPL
 
189
 * so is license-compatible with this file
 
190
 */
 
191
static gdouble
 
192
compute_password_strength (const gchar *password)
 
193
{
 
194
        gint length;
 
195
        gint upper, lower, digit, misc;
 
196
        gint i;
 
197
        gdouble strength;
 
198
 
 
199
        length = strlen (password);
 
200
        upper = 0;
 
201
        lower = 0;
 
202
        digit = 0;
 
203
        misc = 0;
 
204
 
 
205
        for (i = 0; i < length ; i++) {
 
206
                if (g_ascii_isdigit (password[i]))
 
207
                        digit++;
 
208
                else if (g_ascii_islower (password[i]))
 
209
                        lower++;
 
210
                else if (g_ascii_isupper (password[i]))
 
211
                        upper++;
 
212
                else
 
213
                        misc++;
 
214
        }
 
215
 
 
216
        if (length > 5)
 
217
                length = 5;
 
218
 
 
219
        if (digit > 3)
 
220
                digit = 3;
 
221
 
 
222
        if (upper > 3)
 
223
                upper = 3;
 
224
 
 
225
        if (misc > 3)
 
226
                misc = 3;
 
227
 
 
228
        strength = ((length * 0.1) - 0.2) +
 
229
                    (digit * 0.1) +
 
230
                    (misc * 0.15) +
 
231
                    (upper * 0.1);
 
232
 
 
233
        strength = CLAMP (strength, 0.0, 1.0);
 
234
 
 
235
        return strength;
 
236
}
 
237
 
 
238
static void
 
239
finish_password_change (UmPasswordDialog *um)
 
240
{
 
241
        gtk_widget_hide (um->dialog);
 
242
 
 
243
        gtk_entry_set_text (GTK_ENTRY (um->password_entry), " ");
 
244
        gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
 
245
        gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), "");
 
246
        gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
 
247
 
 
248
        um_password_dialog_set_user (um, NULL);
 
249
}
 
250
 
 
251
static void
 
252
cancel_password_dialog (GtkButton        *button,
 
253
                        UmPasswordDialog *um)
 
254
{
 
255
        finish_password_change (um);
 
256
}
 
257
 
 
258
static void
 
259
dialog_closed (GtkWidget        *dialog,
 
260
               gint              response_id,
 
261
               UmPasswordDialog *um)
 
262
{
 
263
        gtk_widget_destroy (dialog);
 
264
}
 
265
 
 
266
static void
 
267
password_changed_cb (PasswdHandler    *handler,
 
268
                     GError           *error,
 
269
                     UmPasswordDialog *um)
 
270
{
 
271
        GtkWidget *dialog;
 
272
        const gchar *primary_text;
 
273
        const gchar *secondary_text;
 
274
 
 
275
        gtk_widget_set_sensitive (um->dialog, TRUE);
 
276
        gdk_window_set_cursor (gtk_widget_get_window (um->dialog), NULL);
 
277
 
 
278
        if (!error) {
 
279
                finish_password_change (um);
 
280
                return;
 
281
        }
 
282
 
 
283
        if (error->code == PASSWD_ERROR_REJECTED) {
 
284
                primary_text = error->message;
 
285
                secondary_text = _("Please choose another password.");
 
286
 
 
287
                gtk_entry_set_text (GTK_ENTRY (um->password_entry), "");
 
288
                gtk_widget_grab_focus (um->password_entry);
 
289
 
 
290
                gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
 
291
        }
 
292
        else if (error->code == PASSWD_ERROR_AUTH_FAILED) {
 
293
                primary_text = error->message;
 
294
                secondary_text = _("Please type your current password again.");
 
295
 
 
296
                gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
 
297
                gtk_widget_grab_focus (um->old_password_entry);
 
298
        }
 
299
        else {
 
300
                primary_text = _("Password could not be changed");
 
301
                secondary_text = error->message;
 
302
        }
 
303
 
 
304
        dialog = gtk_message_dialog_new (GTK_WINDOW (um->dialog),
 
305
                                         GTK_DIALOG_MODAL,
 
306
                                         GTK_MESSAGE_ERROR,
 
307
                                         GTK_BUTTONS_CLOSE,
 
308
                                         "%s", primary_text);
 
309
        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 
310
                                                  "%s", secondary_text);
 
311
        g_signal_connect (dialog, "response",
 
312
                          G_CALLBACK (dialog_closed), um);
 
313
        gtk_window_present (GTK_WINDOW (dialog));
 
314
 
 
315
}
 
316
 
 
317
static void
 
318
accept_password_dialog (GtkButton        *button,
 
319
                        UmPasswordDialog *um)
 
320
{
 
321
        GtkTreeModel *model;
 
322
        GtkTreeIter iter;
 
323
        gint mode;
 
324
        const gchar *hint;
 
325
        const gchar *password;
 
326
 
 
327
        model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo));
 
328
        gtk_combo_box_get_active_iter (GTK_COMBO_BOX (um->action_combo), &iter);
 
329
        gtk_tree_model_get (model, &iter, 1, &mode, -1);
 
330
 
 
331
        password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
 
332
        hint = gtk_entry_get_text (GTK_ENTRY (um->normal_hint_entry));
 
333
 
 
334
        if (mode == 0 && um_user_get_uid (um->user) == getuid ()) {
 
335
                GdkDisplay *display;
 
336
                GdkCursor *cursor;
 
337
 
 
338
                /* When setting a password for the current user,
 
339
                 * use passwd directly, to preserve the audit trail
 
340
                 * and to e.g. update the keyring password.
 
341
                 */
 
342
                passwd_change_password (um->passwd_handler, password, (PasswdCallback) password_changed_cb, um);
 
343
                gtk_widget_set_sensitive (um->dialog, FALSE);
 
344
                display = gtk_widget_get_display (um->dialog);
 
345
                cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
 
346
                gdk_window_set_cursor (gtk_widget_get_window (um->dialog), cursor);
 
347
                gdk_display_flush (display);
 
348
                g_object_unref (cursor);
 
349
        }
 
350
        else {
 
351
                um_user_set_password (um->user, mode, password, hint);
 
352
                finish_password_change (um);
 
353
        }
 
354
}
 
355
 
 
356
static void
 
357
update_sensitivity (UmPasswordDialog *um)
 
358
{
 
359
        const gchar *password, *verify;
 
360
        const gchar *old_password;
 
361
        const gchar *tooltip;
 
362
        gboolean can_change;
 
363
 
 
364
        password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
 
365
        verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry));
 
366
        old_password = gtk_entry_get_text (GTK_ENTRY (um->old_password_entry));
 
367
 
 
368
        /* TODO: configurable policies for acceptable passwords */
 
369
        if (strlen (password) < MIN_PASSWORD_LEN) {
 
370
                can_change = FALSE;
 
371
                if (password[0] == '\0') {
 
372
                        tooltip = _("You need to enter a new password");
 
373
                }
 
374
                else {
 
375
                        tooltip = _("The new password is too short");
 
376
                }
 
377
        }
 
378
        else if (strcmp (password, verify) != 0) {
 
379
                can_change = FALSE;
 
380
                if (verify[0] == '\0') {
 
381
                        tooltip = _("You need to confirm the password");
 
382
                }
 
383
                else {
 
384
                        tooltip = _("The passwords do not match");
 
385
                }
 
386
        }
 
387
        else if (!um->old_password_ok) {
 
388
                can_change = FALSE;
 
389
                if (old_password[0] == '\0') {
 
390
                        tooltip = _("You need to enter your current password");
 
391
                }
 
392
                else {
 
393
                        tooltip = _("The current password is not correct");
 
394
                }
 
395
        }
 
396
        else {
 
397
                can_change = TRUE;
 
398
                tooltip = NULL;
 
399
        }
 
400
 
 
401
        gtk_widget_set_sensitive (um->ok_button, can_change);
 
402
        gtk_widget_set_tooltip_text (um->ok_button, tooltip);
 
403
}
 
404
 
 
405
static void
 
406
action_changed (GtkComboBox      *combo,
 
407
                UmPasswordDialog *um)
 
408
{
 
409
        gint active;
 
410
 
 
411
        active = gtk_combo_box_get_active (combo);
 
412
        if (active == 0) {
 
413
                gtk_widget_set_sensitive (um->password_entry, TRUE);
 
414
                gtk_widget_set_sensitive (um->generate_button, TRUE);
 
415
                gtk_widget_set_has_tooltip (um->generate_button, TRUE);
 
416
                gtk_widget_set_sensitive (um->verify_entry, TRUE);
 
417
                gtk_widget_set_sensitive (um->old_password_entry, TRUE);
 
418
                gtk_widget_set_sensitive (um->normal_hint_entry, TRUE);
 
419
                gtk_widget_set_sensitive (um->normal_hint_label, TRUE);
 
420
                gtk_widget_set_sensitive (um->strength_indicator_label, TRUE);
 
421
                gtk_widget_set_sensitive (um->show_password_button, TRUE);
 
422
 
 
423
                update_sensitivity (um);
 
424
        }
 
425
        else {
 
426
                gtk_widget_set_sensitive (um->password_entry, FALSE);
 
427
                gtk_widget_set_sensitive (um->generate_button, FALSE);
 
428
                gtk_widget_set_has_tooltip (um->generate_button, FALSE);
 
429
                gtk_widget_set_sensitive (um->verify_entry, FALSE);
 
430
                gtk_widget_set_sensitive (um->old_password_entry, FALSE);
 
431
                gtk_widget_set_sensitive (um->normal_hint_entry, FALSE);
 
432
                gtk_widget_set_sensitive (um->normal_hint_label, FALSE);
 
433
                gtk_widget_set_sensitive (um->strength_indicator_label, FALSE);
 
434
                gtk_widget_set_sensitive (um->show_password_button, FALSE);
 
435
                gtk_widget_set_sensitive (um->ok_button, TRUE);
 
436
        }
 
437
}
 
438
 
 
439
static void
 
440
show_password_toggled (GtkToggleButton  *button,
 
441
                       UmPasswordDialog *um)
 
442
{
 
443
        gboolean active;
 
444
 
 
445
        active = gtk_toggle_button_get_active (button);
 
446
        gtk_entry_set_visibility (GTK_ENTRY (um->password_entry), active);
 
447
        gtk_entry_set_visibility (GTK_ENTRY (um->verify_entry), active);
 
448
}
 
449
 
 
450
static void
 
451
update_password_strength (UmPasswordDialog *um)
 
452
{
 
453
        const gchar *password;
 
454
        gdouble strength;
 
455
        const gchar *hint;
 
456
 
 
457
        password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
 
458
 
 
459
        strength = compute_password_strength (password);
 
460
 
 
461
        if (strlen (password) < MIN_PASSWORD_LEN) {
 
462
                strength = 0.0;
 
463
                if (password[0] == '\0')
 
464
                        hint = "";
 
465
                else
 
466
                        hint = C_("Password strength", "Too short");
 
467
        }
 
468
        else if (strength < 0.50)
 
469
                hint = C_("Password strength", "Weak");
 
470
        else if (strength < 0.75)
 
471
                hint = C_("Password strength", "Fair");
 
472
        else if (strength < 0.90)
 
473
                hint = C_("Password strength", "Good");
 
474
        else
 
475
                hint = C_("Password strength", "Strong");
 
476
 
 
477
        um_strength_bar_set_strength (UM_STRENGTH_BAR (um->strength_indicator), strength);
 
478
        gtk_label_set_label (GTK_LABEL (um->strength_indicator_label), hint);
 
479
}
 
480
 
 
481
static void
 
482
password_entry_changed (GtkEntry         *entry,
 
483
                        GParamSpec       *pspec,
 
484
                        UmPasswordDialog *um)
 
485
{
 
486
        update_password_strength (um);
 
487
        update_sensitivity (um);
 
488
}
 
489
 
 
490
static void
 
491
verify_entry_changed (GtkEntry         *entry,
 
492
                      GParamSpec       *pspec,
 
493
                      UmPasswordDialog *um)
 
494
{
 
495
        clear_entry_validation_error (GTK_ENTRY (entry));
 
496
        update_password_strength (um);
 
497
        update_sensitivity (um);
 
498
}
 
499
 
 
500
static gboolean
 
501
verify_entry_focus_out (GtkWidget        *entry,
 
502
                        GdkEventFocus    *event,
 
503
                        UmPasswordDialog *um)
 
504
{
 
505
        const char *password;
 
506
        const char *verify;
 
507
 
 
508
        password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
 
509
        verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry));
 
510
 
 
511
        if (strlen (password) > 0 && strlen (verify) > 0) {
 
512
                if (strcmp (password, verify) != 0) {
 
513
                        set_entry_validation_error (GTK_ENTRY (um->verify_entry),
 
514
                                                    _("Passwords do not match"));
 
515
                }
 
516
                else {
 
517
                        clear_entry_validation_error (GTK_ENTRY (um->verify_entry));
 
518
                }
 
519
        }
 
520
 
 
521
        return FALSE;
 
522
}
 
523
 
 
524
static void
 
525
entry_size_changed (GtkWidget     *entry,
 
526
                    GtkAllocation *allocation,
 
527
                    GtkWidget     *label)
 
528
{
 
529
        gtk_widget_set_size_request (label, allocation->width, -1);
 
530
}
 
531
 
 
532
static void
 
533
auth_cb (PasswdHandler    *handler,
 
534
         GError           *error,
 
535
         UmPasswordDialog *um)
 
536
{
 
537
        if (error) {
 
538
                um->old_password_ok = FALSE;
 
539
                set_entry_validation_error (GTK_ENTRY (um->old_password_entry),
 
540
                                            _("Wrong password"));
 
541
        }
 
542
        else {
 
543
                um->old_password_ok = TRUE;
 
544
                clear_entry_validation_error (GTK_ENTRY (um->old_password_entry));
 
545
        }
 
546
 
 
547
        update_sensitivity (um);
 
548
}
 
549
 
 
550
static gboolean
 
551
old_password_entry_focus_out (GtkWidget        *entry,
 
552
                              GdkEventFocus    *event,
 
553
                              UmPasswordDialog *um)
 
554
{
 
555
        const char *text;
 
556
 
 
557
        text = gtk_entry_get_text (GTK_ENTRY (entry));
 
558
        if (strlen (text) > 0) {
 
559
                passwd_authenticate (um->passwd_handler, text,
 
560
                                     (PasswdCallback)auth_cb, um);
 
561
        }
 
562
 
 
563
        return FALSE;
 
564
}
 
565
 
 
566
static void
 
567
old_password_entry_activate (GtkWidget        *entry,
 
568
                             UmPasswordDialog *um)
 
569
{
 
570
        const char *text;
 
571
 
 
572
        text = gtk_entry_get_text (GTK_ENTRY (entry));
 
573
        if (strlen (text) > 0) {
 
574
                passwd_authenticate (um->passwd_handler, text,
 
575
                                     (PasswdCallback)auth_cb, um);
 
576
        }
 
577
}
 
578
 
 
579
 
 
580
static void
 
581
old_password_entry_changed (GtkEntry         *entry,
 
582
                            GParamSpec       *pspec,
 
583
                            UmPasswordDialog *um)
 
584
{
 
585
        clear_entry_validation_error (GTK_ENTRY (entry));
 
586
        um->old_password_ok = FALSE;
 
587
        update_sensitivity (um);
 
588
}
 
589
 
 
590
void
 
591
um_password_dialog_set_privileged (UmPasswordDialog *um,
 
592
                                   gboolean          privileged)
 
593
{
 
594
        if (privileged) {
 
595
                gtk_widget_set_visible (um->action_label, TRUE);
 
596
                gtk_widget_set_visible (um->action_combo, TRUE);
 
597
        }
 
598
        else {
 
599
                gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0);
 
600
                gtk_widget_set_visible (um->action_label, FALSE);
 
601
                gtk_widget_set_visible (um->action_combo, FALSE);
 
602
        }
 
603
}
 
604
 
 
605
UmPasswordDialog *
 
606
um_password_dialog_new (void)
 
607
{
 
608
        GtkBuilder *builder;
 
609
        GError *error;
 
610
        const gchar *filename;
 
611
        UmPasswordDialog *um;
 
612
        GtkWidget *widget;
 
613
        const char *old_label;
 
614
        char *label;
 
615
        gint len;
 
616
 
 
617
        builder = gtk_builder_new ();
 
618
 
 
619
        error = NULL;
 
620
        filename = UIDIR "/password-dialog.ui";
 
621
        if (!g_file_test (filename, G_FILE_TEST_EXISTS))
 
622
                filename = "data/password-dialog.ui";
 
623
        if (!gtk_builder_add_from_file (builder, filename, &error)) {
 
624
                g_error ("%s", error->message);
 
625
                g_error_free (error);
 
626
                return NULL;
 
627
        }
 
628
 
 
629
        um = g_new0 (UmPasswordDialog, 1);
 
630
 
 
631
        um->action_label = (GtkWidget *) gtk_builder_get_object (builder, "action-label");
 
632
        widget = (GtkWidget *) gtk_builder_get_object (builder, "action-combo");
 
633
        g_signal_connect (widget, "changed",
 
634
                          G_CALLBACK (action_changed), um);
 
635
        um->action_combo = widget;
 
636
 
 
637
        widget = (GtkWidget *) gtk_builder_get_object (builder, "dialog");
 
638
        g_signal_connect (widget, "delete-event",
 
639
                          G_CALLBACK (gtk_widget_hide_on_delete), NULL);
 
640
        um->dialog = widget;
 
641
 
 
642
        um->user_icon = (GtkWidget *) gtk_builder_get_object (builder, "user-icon");
 
643
        um->user_name = (GtkWidget *) gtk_builder_get_object (builder, "user-name");
 
644
 
 
645
        widget = (GtkWidget *) gtk_builder_get_object (builder, "cancel-button");
 
646
        g_signal_connect (widget, "clicked",
 
647
                          G_CALLBACK (cancel_password_dialog), um);
 
648
 
 
649
        widget = (GtkWidget *) gtk_builder_get_object (builder, "ok-button");
 
650
        g_signal_connect (widget, "clicked",
 
651
                          G_CALLBACK (accept_password_dialog), um);
 
652
        gtk_widget_grab_default (widget);
 
653
        um->ok_button = widget;
 
654
 
 
655
        widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-strength-hints-label");
 
656
        old_label = gtk_label_get_label (GTK_LABEL (widget));
 
657
        label = g_strdup_printf ("<a href=\"%s\">%s</a>",
 
658
                                 "ghelp:gnome-help?user-goodpassword",
 
659
                                 old_label);
 
660
        gtk_label_set_markup (GTK_LABEL (widget), label);
 
661
        g_free (label);
 
662
 
 
663
        widget = (GtkWidget *) gtk_builder_get_object (builder, "show-password-checkbutton");
 
664
        g_signal_connect (widget, "toggled",
 
665
                          G_CALLBACK (show_password_toggled), um);
 
666
        um->show_password_button = widget;
 
667
 
 
668
        widget = (GtkWidget *) gtk_builder_get_object (builder, "password-entry");
 
669
        g_signal_connect (widget, "notify::text",
 
670
                          G_CALLBACK (password_entry_changed), um);
 
671
        gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
 
672
 
 
673
        um->password_entry = widget;
 
674
 
 
675
        widget = (GtkWidget *) gtk_builder_get_object (builder, "old-password-entry");
 
676
        g_signal_connect_after (widget, "focus-out-event",
 
677
                                G_CALLBACK (old_password_entry_focus_out), um);
 
678
        g_signal_connect (widget, "notify::text",
 
679
                          G_CALLBACK (old_password_entry_changed), um);
 
680
        g_signal_connect (widget, "activate",
 
681
                          G_CALLBACK (old_password_entry_activate), um);
 
682
        um->old_password_entry = widget;
 
683
        um->old_password_label = (GtkWidget *) gtk_builder_get_object (builder, "old-password-label");
 
684
 
 
685
        widget = (GtkWidget *) gtk_builder_get_object (builder, "verify-entry");
 
686
        g_signal_connect (widget, "notify::text",
 
687
                          G_CALLBACK (verify_entry_changed), um);
 
688
        g_signal_connect_after (widget, "focus-out-event",
 
689
                                G_CALLBACK (verify_entry_focus_out), um);
 
690
        um->verify_entry = widget;
 
691
 
 
692
        len = 0;
 
693
        len = MAX (len, strlen (C_("Password strength", "Too short")));
 
694
        len = MAX (len, strlen (C_("Password strength", "Weak")));
 
695
        len = MAX (len, strlen (C_("Password strength", "Fair")));
 
696
        len = MAX (len, strlen (C_("Password strength", "Good")));
 
697
        len = MAX (len, strlen (C_("Password strength", "Strong")));
 
698
        len += 2;
 
699
 
 
700
        widget = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label");
 
701
        gtk_label_set_width_chars (GTK_LABEL (widget), len);
 
702
 
 
703
 
 
704
        widget = (GtkWidget *) gtk_builder_get_object (builder, "generate-again-button");
 
705
        g_signal_connect (widget, "clicked",
 
706
                          G_CALLBACK (generate_clicked), um);
 
707
#if 0
 
708
        g_signal_connect (widget, "state-changed",
 
709
                          G_CALLBACK (generate_state_changed), um);
 
710
#endif
 
711
        um->generate_button = widget;
 
712
        g_signal_connect_after (widget, "draw",
 
713
                                G_CALLBACK (generate_draw), um);
 
714
 
 
715
        um->normal_hint_entry = (GtkWidget *) gtk_builder_get_object (builder, "normal-hint-entry");
 
716
 
 
717
        /* Label size hack.
 
718
         * This only sort-of works because the dialog is non-resizable.
 
719
         */
 
720
        widget = (GtkWidget *)gtk_builder_get_object (builder, "password-normal-hint-description-label");
 
721
        g_signal_connect (um->normal_hint_entry, "size-allocate",
 
722
                          G_CALLBACK (entry_size_changed), widget);
 
723
        um->normal_hint_label = widget;
 
724
 
 
725
        um->strength_indicator = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator");
 
726
 
 
727
        um->strength_indicator_label = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label");
 
728
 
 
729
        g_object_unref (builder);
 
730
 
 
731
        generate_passwords (um);
 
732
 
 
733
        return um;
 
734
}
 
735
 
 
736
void
 
737
um_password_dialog_free (UmPasswordDialog *um)
 
738
{
 
739
        gtk_widget_destroy (um->dialog);
 
740
 
 
741
        if (um->user)
 
742
                g_object_unref (um->user);
 
743
 
 
744
        if (um->passwd_handler)
 
745
                passwd_destroy (um->passwd_handler);
 
746
 
 
747
        g_free (um);
 
748
}
 
749
 
 
750
static gboolean
 
751
visible_func (GtkTreeModel     *model,
 
752
              GtkTreeIter      *iter,
 
753
              UmPasswordDialog *um)
 
754
{
 
755
        if (um->user) {
 
756
                gint mode; 
 
757
                gboolean locked = um_user_get_locked (um->user);
 
758
 
 
759
                gtk_tree_model_get (model, iter, 1, &mode, -1);
 
760
 
 
761
                if (mode == 3 && locked)
 
762
                        return FALSE;
 
763
 
 
764
                if (mode == 4 && !locked)
 
765
                        return FALSE;
 
766
 
 
767
                return TRUE;
 
768
        }
 
769
 
 
770
        return TRUE;
 
771
}
 
772
 
 
773
void
 
774
um_password_dialog_set_user (UmPasswordDialog *um,
 
775
                             UmUser           *user)
 
776
{
 
777
        GdkPixbuf *pixbuf;
 
778
        GtkTreeModel *model;
 
779
 
 
780
        if (um->user) {
 
781
                g_object_unref (um->user);
 
782
                um->user = NULL;
 
783
        }
 
784
        if (user) {
 
785
                um->user = g_object_ref (user);
 
786
 
 
787
                pixbuf = um_user_render_icon (user, FALSE, 48);
 
788
                gtk_image_set_from_pixbuf (GTK_IMAGE (um->user_icon), pixbuf);
 
789
                g_object_unref (pixbuf);
 
790
 
 
791
                gtk_label_set_label (GTK_LABEL (um->user_name),
 
792
                                     um_user_get_real_name (user));
 
793
 
 
794
                gtk_entry_set_text (GTK_ENTRY (um->password_entry), "");
 
795
                gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
 
796
                gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), "");
 
797
                gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
 
798
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->show_password_button), FALSE);
 
799
                if (um_user_get_uid (um->user) == getuid()) {
 
800
                        gtk_widget_show (um->old_password_label);
 
801
                        gtk_widget_show (um->old_password_entry);
 
802
                        if (um->passwd_handler != NULL)
 
803
                                passwd_destroy (um->passwd_handler);
 
804
                        um->passwd_handler = passwd_init ();
 
805
                        um->old_password_ok = FALSE;
 
806
                }
 
807
                else {
 
808
                        gtk_widget_hide (um->old_password_label);
 
809
                        gtk_widget_hide (um->old_password_entry);
 
810
                        um->old_password_ok = TRUE;
 
811
                }
 
812
        }
 
813
 
 
814
        model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo));
 
815
        if (!GTK_IS_TREE_MODEL_FILTER (model)) {
 
816
                model = gtk_tree_model_filter_new (model, NULL);
 
817
                gtk_combo_box_set_model (GTK_COMBO_BOX (um->action_combo), model);
 
818
                gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
 
819
                                                        (GtkTreeModelFilterVisibleFunc) visible_func,
 
820
                                                        um, NULL);
 
821
        }
 
822
 
 
823
        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
 
824
        gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0);
 
825
}
 
826
 
 
827
void
 
828
um_password_dialog_show (UmPasswordDialog *um,
 
829
                         GtkWindow        *parent)
 
830
{
 
831
        gtk_window_set_transient_for (GTK_WINDOW (um->dialog), parent);
 
832
        gtk_window_present (GTK_WINDOW (um->dialog));
 
833
        gtk_widget_grab_focus (um->password_entry);
 
834
}
 
835