~x2go/x2go/pinentry-x2go_master

« back to all changes in this revision

Viewing changes to gtk+-2/pinentry-gtk-2.c

  • Committer: Mike Gabriel
  • Date: 2012-06-13 12:55:37 UTC
  • Revision ID: git-v1:d2060291d5cc7beb92f78168e48ececfe765d552
Strip code project down to its essentials, remove a lot of unneeded cruft. / Make code tree fully build with autotools, see README file for further info.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* pinentry-gtk-2.c
2
 
   Copyright (C) 1999 Robert Bihlmeyer <robbe@orcus.priv.at>
3
 
   Copyright (C) 2001, 2002, 2007 g10 Code GmbH
4
 
   Copyright (C) 2004 by Albrecht Dre� <albrecht.dress@arcor.de>
5
 
 
6
 
   pinentry-gtk-2 is a pinentry application for the Gtk+-2 widget set.
7
 
   It tries to follow the Gnome Human Interface Guide as close as
8
 
   possible.
9
 
 
10
 
   This program is free software; you can redistribute it and/or modify
11
 
   it under the terms of the GNU General Public License as published by
12
 
   the Free Software Foundation; either version 2 of the License, or
13
 
   (at your option) any later version.
14
 
  
15
 
   This program is distributed in the hope that it will be useful,
16
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
   GNU General Public License for more details.
19
 
  
20
 
   You should have received a copy of the GNU General Public License
21
 
   along with this program; if not, write to the Free Software
22
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
23
 
 
24
 
#ifdef HAVE_CONFIG_H
25
 
#include "config.h"
26
 
#endif
27
 
#include <gtk/gtk.h>
28
 
#include <assert.h>
29
 
#include <math.h>
30
 
#include <stdio.h>
31
 
#include <stdlib.h>
32
 
#include <string.h>
33
 
 
34
 
#ifdef HAVE_GETOPT_H
35
 
#include <getopt.h>
36
 
#else
37
 
#include "getopt.h"
38
 
#endif                          /* HAVE_GETOPT_H */
39
 
 
40
 
#include "gtksecentry.h"
41
 
#include "pinentry.h"
42
 
 
43
 
#ifdef FALLBACK_CURSES
44
 
#include "pinentry-curses.h"
45
 
#endif
46
 
 
47
 
 
48
 
#define PGMNAME "pinentry-gtk2"
49
 
 
50
 
#ifndef VERSION
51
 
#  define VERSION
52
 
#endif
53
 
 
54
 
static pinentry_t pinentry;
55
 
static int passphrase_ok;
56
 
static int confirm_yes;
57
 
 
58
 
static GtkWidget *entry;
59
 
static GtkWidget *qualitybar;
60
 
static GtkWidget *insure;
61
 
static GtkWidget *time_out;
62
 
static GtkTooltips *tooltips;
63
 
 
64
 
/* Gnome hig small and large space in pixels.  */
65
 
#define HIG_SMALL      6
66
 
#define HIG_LARGE     12
67
 
 
68
 
/* The text shown in the quality bar when no text is shown.  This is not
69
 
 * the empty string, becase because with an empty string the height of
70
 
 * the quality bar is less than with a non-empty string.  This results
71
 
 * in ugly layout changes when the text changes from non-empty to empty
72
 
 * and vice versa */
73
 
#define QUALITYBAR_EMPTY_TEXT " "
74
 
 
75
 
 
76
 
/* Constrain size of the window the window should not shrink beyond
77
 
   the requisition, and should not grow vertically.  */
78
 
static void
79
 
constrain_size (GtkWidget *win, GtkRequisition *req, gpointer data)
80
 
{
81
 
  static gint width, height;
82
 
  GdkGeometry geo;
83
 
 
84
 
  if (req->width == width && req->height == height)
85
 
    return;
86
 
  width = req->width;
87
 
  height = req->height;
88
 
  geo.min_width = width;
89
 
  /* This limit is arbitrary, but INT_MAX breaks other things */
90
 
  geo.max_width = 10000;
91
 
  geo.min_height = geo.max_height = height;
92
 
  gtk_window_set_geometry_hints (GTK_WINDOW (win), NULL, &geo,
93
 
                                 GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
94
 
}
95
 
 
96
 
 
97
 
/* Grab the keyboard for maximum security */
98
 
static void
99
 
grab_keyboard (GtkWidget *win, GdkEvent *event, gpointer data)
100
 
{
101
 
  if (!pinentry->grab)
102
 
    return;
103
 
 
104
 
  if (gdk_keyboard_grab (win->window, FALSE, gdk_event_get_time (event)))
105
 
    g_error ("could not grab keyboard");
106
 
}
107
 
 
108
 
/* Remove grab.  */
109
 
static void
110
 
ungrab_keyboard (GtkWidget *win, GdkEvent *event, gpointer data)
111
 
{
112
 
  gdk_keyboard_ungrab (gdk_event_get_time (event));
113
 
}
114
 
 
115
 
 
116
 
static int
117
 
delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
118
 
{
119
 
  gtk_main_quit ();
120
 
  return TRUE;
121
 
}
122
 
 
123
 
 
124
 
static void
125
 
button_clicked (GtkWidget *widget, gpointer data)
126
 
{
127
 
  if (data)
128
 
    {
129
 
      const char *s;
130
 
 
131
 
      /* Okay button or enter used in text field.  */
132
 
 
133
 
      if (pinentry->enhanced)
134
 
        printf ("Options: %s\nTimeout: %d\n\n",
135
 
                gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (insure))
136
 
                ? "insure" : "",
137
 
                gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (time_out)));
138
 
 
139
 
      s = gtk_secure_entry_get_text (GTK_SECURE_ENTRY (entry));
140
 
      if (!s)
141
 
        s = "";
142
 
      passphrase_ok = 1;
143
 
      pinentry_setbufferlen (pinentry, strlen (s) + 1);
144
 
      if (pinentry->pin)
145
 
        strcpy (pinentry->pin, s);
146
 
    }
147
 
  gtk_main_quit ();
148
 
}
149
 
 
150
 
 
151
 
static void
152
 
enter_callback (GtkWidget *widget, GtkWidget *anentry)
153
 
{
154
 
  button_clicked (widget, "ok");
155
 
}
156
 
 
157
 
 
158
 
static void
159
 
confirm_button_clicked (GtkWidget *widget, gpointer data)
160
 
{
161
 
  if (data)
162
 
    /* Okay button.  */
163
 
    confirm_yes = 1;
164
 
 
165
 
  gtk_main_quit ();
166
 
}
167
 
 
168
 
 
169
 
static gchar *
170
 
pinentry_utf8_validate (gchar *text)
171
 
{
172
 
  gchar *result;
173
 
 
174
 
  if (!text)
175
 
    return NULL;
176
 
 
177
 
  if (g_utf8_validate (text, -1, NULL))
178
 
    return g_strdup (text);
179
 
 
180
 
  result = g_locale_to_utf8 (text, -1, NULL, NULL, NULL);
181
 
  if (!result)
182
 
    {
183
 
      gchar *p;
184
 
 
185
 
      result = p = g_strdup (text);
186
 
      while (!g_utf8_validate (p, -1, (const gchar **) &p))
187
 
        *p = '?';
188
 
    }
189
 
  return result;
190
 
}
191
 
 
192
 
 
193
 
/* Handler called for "changed".   We use it to update the quality
194
 
   indicator.  */
195
 
static void
196
 
changed_text_handler (GtkWidget *widget)
197
 
{
198
 
  char textbuf[50];
199
 
  const char *s;
200
 
  int length;
201
 
  int percent;
202
 
  GdkColor color = { 0, 0, 0, 0};
203
 
 
204
 
  if (!qualitybar || !pinentry->quality_bar)
205
 
    return;
206
 
 
207
 
  s = gtk_secure_entry_get_text (GTK_SECURE_ENTRY (widget));
208
 
  if (!s)
209
 
    s = "";
210
 
  length = strlen (s);
211
 
  percent = length? pinentry_inq_quality (pinentry, s, length) : 0;
212
 
  if (!length)
213
 
    {
214
 
      strcpy(textbuf, QUALITYBAR_EMPTY_TEXT);
215
 
      color.red = 0xffff;
216
 
    }
217
 
  else if (percent < 0)
218
 
    {
219
 
      snprintf (textbuf, sizeof textbuf, "(%d%%)", -percent);
220
 
      color.red = 0xffff;
221
 
      percent = -percent;
222
 
    }
223
 
  else
224
 
    {
225
 
      snprintf (textbuf, sizeof textbuf, "%d%%", percent);
226
 
      color.green = 0xffff;
227
 
    }
228
 
  gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (qualitybar), 
229
 
                                 (double)percent/100.0);
230
 
  gtk_progress_bar_set_text (GTK_PROGRESS_BAR (qualitybar), textbuf);
231
 
  gtk_widget_modify_bg (qualitybar, GTK_STATE_PRELIGHT, &color);
232
 
}
233
 
 
234
 
 
235
 
 
236
 
static GtkWidget *
237
 
create_window (int confirm_mode)
238
 
{
239
 
  GtkWidget *w;
240
 
  GtkWidget *win, *box;
241
 
  GtkWidget *wvbox, *chbox, *bbox;
242
 
  GtkAccelGroup *acc;
243
 
  gchar *msg;
244
 
 
245
 
  tooltips = gtk_tooltips_new ();
246
 
 
247
 
  /* FIXME: check the grabbing code against the one we used with the
248
 
     old gpg-agent */
249
 
  win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
250
 
  acc = gtk_accel_group_new ();
251
 
 
252
 
  g_signal_connect (G_OBJECT (win), "delete_event",
253
 
                    G_CALLBACK (delete_event), NULL);
254
 
 
255
 
#if 0
256
 
  g_signal_connect (G_OBJECT (win), "destroy", G_CALLBACK (gtk_main_quit),
257
 
                    NULL);
258
 
#endif
259
 
  g_signal_connect (G_OBJECT (win), "size-request",
260
 
                    G_CALLBACK (constrain_size), NULL);
261
 
  if (!confirm_mode)
262
 
    {
263
 
        //we need to grab the keyboard when its visible! not when its mapped (there is a difference)
264
 
        g_object_set(G_OBJECT(win), "events", GDK_VISIBILITY_NOTIFY_MASK | GDK_STRUCTURE_MASK, NULL);
265
 
 
266
 
      g_signal_connect (G_OBJECT (win),
267
 
                        pinentry->grab ? "visibility-notify-event" : "focus-in-event",
268
 
                        G_CALLBACK (grab_keyboard), NULL);
269
 
      g_signal_connect (G_OBJECT (win),
270
 
                        pinentry->grab ? "unmap-event" : "focus-out-event",
271
 
                        G_CALLBACK (ungrab_keyboard), NULL);
272
 
    }
273
 
  gtk_window_add_accel_group (GTK_WINDOW (win), acc);
274
 
  
275
 
  wvbox = gtk_vbox_new (FALSE, HIG_LARGE * 2);
276
 
  gtk_container_add (GTK_CONTAINER (win), wvbox);
277
 
  gtk_container_set_border_width (GTK_CONTAINER (wvbox), HIG_LARGE);
278
 
 
279
 
  chbox = gtk_hbox_new (FALSE, HIG_LARGE);
280
 
  gtk_box_pack_start (GTK_BOX (wvbox), chbox, FALSE, FALSE, 0);
281
 
 
282
 
  w = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION,
283
 
                                               GTK_ICON_SIZE_DIALOG);
284
 
  gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0);
285
 
  gtk_box_pack_start (GTK_BOX (chbox), w, FALSE, FALSE, 0);
286
 
 
287
 
  box = gtk_vbox_new (FALSE, HIG_SMALL);
288
 
  gtk_box_pack_start (GTK_BOX (chbox), box, TRUE, TRUE, 0);
289
 
 
290
 
  if (pinentry->description)
291
 
    {
292
 
      msg = pinentry_utf8_validate (pinentry->description);
293
 
      w = gtk_label_new (msg);
294
 
      g_free (msg);
295
 
      gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
296
 
      gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
297
 
      gtk_box_pack_start (GTK_BOX (box), w, TRUE, FALSE, 0);
298
 
    }
299
 
  if (pinentry->error && !confirm_mode)
300
 
    {
301
 
      GdkColor color = { 0, 0xffff, 0, 0 };
302
 
 
303
 
      msg = pinentry_utf8_validate (pinentry->error);
304
 
      w = gtk_label_new (msg);
305
 
      g_free (msg);
306
 
      gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
307
 
      gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
308
 
      gtk_box_pack_start (GTK_BOX (box), w, TRUE, FALSE, 0);
309
 
      gtk_widget_modify_fg (w, GTK_STATE_NORMAL, &color);
310
 
    }
311
 
 
312
 
  qualitybar = NULL;
313
 
 
314
 
  if (!confirm_mode)
315
 
    {
316
 
      GtkWidget* table = gtk_table_new (pinentry->quality_bar ? 2 : 1, 2,
317
 
                                        FALSE);
318
 
      gtk_box_pack_start (GTK_BOX (box), table, FALSE, FALSE, 0);
319
 
 
320
 
      if (pinentry->prompt)
321
 
        {
322
 
          msg = pinentry_utf8_validate (pinentry->prompt);
323
 
          w = gtk_label_new (msg);
324
 
          g_free (msg);
325
 
          gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
326
 
          gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1,
327
 
                            GTK_FILL, GTK_FILL, 4, 0);
328
 
        }
329
 
 
330
 
      entry = gtk_secure_entry_new ();
331
 
      gtk_widget_set_size_request (entry, 200, -1);
332
 
      g_signal_connect (G_OBJECT (entry), "activate",
333
 
                        G_CALLBACK (enter_callback), entry);
334
 
      g_signal_connect (G_OBJECT (entry), "changed",
335
 
                        G_CALLBACK (changed_text_handler), entry);
336
 
      gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1,
337
 
                        GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
338
 
      gtk_widget_grab_focus (entry);
339
 
      gtk_widget_show (entry);
340
 
 
341
 
      if (pinentry->quality_bar)
342
 
        {
343
 
          msg = pinentry_utf8_validate (pinentry->quality_bar);
344
 
          w = gtk_label_new (msg);
345
 
          g_free (msg);
346
 
          gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
347
 
          gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2,
348
 
                            GTK_FILL, GTK_FILL, 4, 0);
349
 
          qualitybar = gtk_progress_bar_new();
350
 
          gtk_widget_add_events (qualitybar,
351
 
                                 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
352
 
          gtk_progress_bar_set_text (GTK_PROGRESS_BAR (qualitybar),
353
 
                                     QUALITYBAR_EMPTY_TEXT);
354
 
          gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (qualitybar), 0.0);
355
 
          if (pinentry->quality_bar_tt)
356
 
            gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), qualitybar,
357
 
                                  pinentry->quality_bar_tt, "");
358
 
          gtk_table_attach (GTK_TABLE (table), qualitybar, 1, 2, 1, 2,
359
 
                            GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
360
 
        }
361
 
 
362
 
      if (pinentry->enhanced)
363
 
        {
364
 
          GtkWidget *sbox = gtk_hbox_new (FALSE, HIG_SMALL);
365
 
          gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
366
 
 
367
 
          w = gtk_label_new ("Forget secret after");
368
 
          gtk_box_pack_start (GTK_BOX (sbox), w, FALSE, FALSE, 0);
369
 
          gtk_widget_show (w);
370
 
 
371
 
          time_out = gtk_spin_button_new
372
 
            (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, HUGE_VAL, 1, 60, 60)),
373
 
             2, 0);
374
 
          gtk_box_pack_start (GTK_BOX (sbox), time_out, FALSE, FALSE, 0);
375
 
          gtk_widget_show (time_out);
376
 
          
377
 
          w = gtk_label_new ("seconds");
378
 
          gtk_box_pack_start (GTK_BOX (sbox), w, FALSE, FALSE, 0);
379
 
          gtk_widget_show (w);
380
 
          gtk_widget_show (sbox);
381
 
 
382
 
          insure = gtk_check_button_new_with_label ("ask before giving out "
383
 
                                                    "secret");
384
 
          gtk_box_pack_start (GTK_BOX (box), insure, FALSE, FALSE, 0);
385
 
          gtk_widget_show (insure);
386
 
        }
387
 
    }
388
 
 
389
 
  bbox = gtk_hbutton_box_new ();
390
 
  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
391
 
  gtk_box_set_spacing (GTK_BOX (bbox), 6);
392
 
  gtk_box_pack_start (GTK_BOX (wvbox), bbox, TRUE, FALSE, 0);
393
 
 
394
 
  if (!pinentry->one_button)
395
 
    {
396
 
      if (pinentry->cancel)
397
 
        {
398
 
          msg = pinentry_utf8_validate (pinentry->cancel);
399
 
          w = gtk_button_new_with_label (msg);
400
 
          g_free (msg);
401
 
        }
402
 
      else
403
 
        w = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
404
 
      gtk_container_add (GTK_CONTAINER (bbox), w);
405
 
      g_signal_connect (G_OBJECT (w), "clicked",
406
 
                        G_CALLBACK (confirm_mode ? confirm_button_clicked
407
 
                                    : button_clicked), NULL);
408
 
      GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
409
 
    }
410
 
  
411
 
  if (pinentry->ok)
412
 
    {
413
 
      msg = pinentry_utf8_validate (pinentry->ok);
414
 
      w = gtk_button_new_with_label (msg);
415
 
      g_free (msg);
416
 
    }
417
 
  else
418
 
    w = gtk_button_new_from_stock (GTK_STOCK_OK);
419
 
  gtk_container_add (GTK_CONTAINER(bbox), w);
420
 
  if (!confirm_mode)
421
 
    {
422
 
      g_signal_connect (G_OBJECT (w), "clicked",
423
 
                        G_CALLBACK (button_clicked), "ok");
424
 
      GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
425
 
      gtk_widget_grab_default (w);
426
 
      g_signal_connect_object (G_OBJECT (entry), "focus_in_event",
427
 
                                G_CALLBACK (gtk_widget_grab_default),
428
 
                               G_OBJECT (w), 0);
429
 
    }
430
 
  else
431
 
    {
432
 
      g_signal_connect (G_OBJECT (w), "clicked",
433
 
                        G_CALLBACK(confirm_button_clicked), "ok");
434
 
      GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
435
 
    }
436
 
 
437
 
  gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_CENTER);
438
 
  
439
 
  gtk_widget_show_all(win);
440
 
  
441
 
  return win;
442
 
}
443
 
 
444
 
 
445
 
static int
446
 
gtk_cmd_handler (pinentry_t pe)
447
 
{
448
 
  GtkWidget *w;
449
 
  int want_pass = !!pe->pin;
450
 
 
451
 
  pinentry = pe;
452
 
  confirm_yes = 0;
453
 
  passphrase_ok = 0;
454
 
  w = create_window (want_pass ? 0 : 1);
455
 
  gtk_main ();
456
 
  gtk_widget_destroy (w);
457
 
  while (gtk_events_pending ())
458
 
    gtk_main_iteration ();
459
 
 
460
 
  pinentry = NULL;
461
 
  if (want_pass)
462
 
    {
463
 
      if (passphrase_ok && pe->pin)
464
 
        return strlen (pe->pin);
465
 
      else
466
 
        return -1;
467
 
    }
468
 
  else
469
 
    return confirm_yes;
470
 
}
471
 
 
472
 
 
473
 
pinentry_cmd_handler_t pinentry_cmd_handler = gtk_cmd_handler;
474
 
 
475
 
 
476
 
int
477
 
main (int argc, char *argv[])
478
 
{
479
 
  pinentry_init (PGMNAME);
480
 
    
481
 
#ifdef FALLBACK_CURSES
482
 
  if (pinentry_have_display (argc, argv))
483
 
    gtk_init (&argc, &argv);
484
 
  else
485
 
    pinentry_cmd_handler = curses_cmd_handler;
486
 
#else
487
 
  gtk_init (&argc, &argv);
488
 
#endif
489
 
 
490
 
  /* Consumes all arguments.  */
491
 
  if (pinentry_parse_opts (argc, argv))
492
 
    {
493
 
      printf(PGMNAME " " VERSION "\n");
494
 
      exit(EXIT_SUCCESS);
495
 
    }
496
 
  
497
 
  if (pinentry_loop ())
498
 
    return 1;
499
 
  
500
 
  return 0;
501
 
}