source: trunk/third/ssh/ssh-askpass.c @ 12646

Revision 12646, 15.3 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12645, which included commits to RCS files with non-trunk default branches.
Line 
1#include <X11/X.h>
2#include <X11/Xlib.h>
3#include <X11/Xutil.h>
4#include <X11/Xresource.h>
5#include <X11/Xatom.h>
6#include <stdarg.h>
7#include <stdlib.h>
8#include <stdio.h>
9#include <string.h>
10#include <X11/keysym.h>
11#include <X11/cursorfont.h>
12#include "xmalloc.h"
13
14#define DISPLAY_VARIABLE "DISPLAY"
15#define RESOURCES_MAX_LENGTH 20000L
16#define CANCEL_STRING "Cancel"
17
18/* 'none' must be the last one in this enum, starting from zero */
19
20typedef enum { background, hilight, shadow, text,
21               dark_led, light_led, none } color_type;
22
23/* X data structures */
24
25Display *display;
26Window main_window, cancel_button;
27XrmDatabase database;
28XModifierKeymap *modifiers;
29XFontStruct *font_struct;
30Colormap map;
31Font font;
32
33/* Default values for some resources */
34
35char *font_spec = "-*-times-bold-r-*-*-*-140-*-*-*-*-iso8859-1";
36char *font_fall_back = "-*-*-*-r-*-*-*-*-*-*-*-*-iso8859-1";
37char *background_color_name = "gray80";
38char *foreground_color_name = "black";
39char *prompt = "Please enter your authentication passphrase:";
40
41/* Color tables */
42
43long color[none];
44GC gc[none];
45
46/* Geometry */
47
48int w_width, w_height, w_x, w_y;
49int led_width = 20;
50int led_height = 10;
51int led_i_height = 8;
52int led_i_width = 18;
53int relief = 4;
54int margin = 4;
55int leds;
56int b_width, b_height;
57
58/* User interfacing */
59
60char phrase[256];
61char *ppointer = phrase;
62int cancel_pressed = 0;
63int exiting = 0;
64int next_led = 0;
65int leds_x, leds_y;
66int *led_state;
67
68void fatal(char *fmt, ...)
69{
70  va_list args;
71  va_start(args, fmt);
72  vfprintf(stderr, fmt, args);
73  va_end(args);
74  fprintf(stderr, "\n");
75  exit(1);
76}
77
78/* Open connection to the X display. */
79
80void open_display(void)
81{
82  char *display_name;
83
84  display_name = getenv(DISPLAY_VARIABLE);
85  if (!display_name)
86    fatal("Display not set, cannot open display.");
87
88  display = XOpenDisplay(display_name);
89
90  if (!display)
91    fatal("Cannot open display \"%s\".\n", display_name);
92}
93
94/* Close the display after freeing data structures. */
95
96void close_display(void)
97{
98  XFreeModifiermap(modifiers);
99  XUnloadFont(display, font);
100  xfree(led_state);
101  XCloseDisplay(display);
102}
103
104/* Create the graphics contexts. Color version. */
105
106void create_GCs(void)
107{
108  int i;
109  XGCValues values;
110  values.function = GXcopy;
111  values.font = font;
112  values.fill_style = FillSolid;
113  values.background = color[0];
114  for (i = 0; i < none; i++)
115    {
116      values.foreground = color[i];
117      gc[i] = XCreateGC(display, main_window, GCForeground | GCBackground |
118                        GCFillStyle | GCFunction | GCFont,
119                        &values);
120    }
121}
122
123/* Create the graphics contexts. B/W version. */
124
125void create_GCs_bw(void)
126{
127  int i;
128  XGCValues values;
129  values.function = GXcopy;
130  values.font = font;
131  values.fill_style = FillSolid;
132  values.background = WhitePixel(display, DefaultScreen(display));
133  for (i = 0; i < none; i++)
134    {
135      values.foreground = ((i == text || i == shadow || i == dark_led)
136                           ? BlackPixel(display, DefaultScreen(display))
137                           : WhitePixel(display, DefaultScreen(display)));
138      gc[i] = XCreateGC(display, main_window, GCForeground | GCBackground |
139                        GCFillStyle | GCFunction | GCFont,
140                        &values);
141    }
142}
143
144/* Try to allocate the colors we would like to use.
145   If any of the allocations fails, revert to black'n'white mode. */
146
147void allocate_colors(void)
148{
149  XColor xcolor, exact_color;
150  int red, green, blue;
151
152  map = DefaultColormap(display, DefaultScreen(display));
153  if(!XAllocNamedColor(display, map, background_color_name,
154                       &xcolor, &exact_color))
155    goto revert;
156
157  color[background] = xcolor.pixel;
158  exact_color.flags = DoRed | DoGreen | DoBlue;
159  red = exact_color.red;
160  blue = exact_color.blue;
161  green = exact_color.green;
162 
163  red += 16384;
164  if (red > 65535) red = 65535;
165  blue += 16384;
166  if (blue > 65535) blue = 65535;
167  green += 16384;
168  if (green > 65535) green = 65535;
169 
170  exact_color.red = red;
171  exact_color.blue = blue;
172  exact_color.green = green;
173 
174  if(!XAllocColor(display, map, &exact_color))
175    goto revert;
176
177  color[hilight] = exact_color.pixel;
178 
179  red -= 32768;
180  if (red < 0) red = 0;
181  blue -= 32768;
182  if (blue < 0) blue = 0;
183  green -= 32768;
184  if (green < 0) green = 0;
185 
186  exact_color.red = red;
187  exact_color.blue = blue;
188  exact_color.green = green;
189 
190  if (!XAllocColor(display, map, &exact_color))
191    goto revert;
192
193  color[shadow] = exact_color.pixel;
194 
195  if (!XAllocNamedColor(display, map, foreground_color_name,
196                   &xcolor, &exact_color))
197    goto revert;
198
199  color[text] = xcolor.pixel;
200
201  exact_color.red = 0x9000;
202  exact_color.green = 0xd000;
203  exact_color.blue = 0x9000;
204  if(!XAllocColor(display, map, &exact_color))
205    goto revert;
206
207  color[light_led] = exact_color.pixel;
208
209  exact_color.red = 0x0;
210  exact_color.green = 0x0;
211  exact_color.blue = 0x8000;
212  if(!XAllocColor(display, map, &exact_color))
213    goto revert;
214
215  color[dark_led] = exact_color.pixel;
216  XSetWindowColormap(display, main_window, map);
217  create_GCs();
218  return;
219
220revert:
221  /* switch to black'n'white mode */
222  create_GCs_bw();
223}
224
225/* Calculate dimensions of a button containing 'string' inside it. */
226
227void button_dimensions(char *string, int *width, int *height)
228{
229  XCharStruct overall;
230  int dir, asc, desc;
231  XTextExtents(font_struct, string, strlen(string),
232               &dir, &asc, &desc, &overall);
233  *width = overall.width + 4 + 2 * margin;
234  *height = overall.ascent + overall.descent + 1 + 4 + 2*margin;
235}
236
237/* Open windows (the dialog box and the cancel button). */
238
239void open_windows(void)
240{
241  int i; int scrap;
242  XSetWindowAttributes attributes;
243  XSizeHints *hints = XAllocSizeHints();
244
245  attributes.backing_store = WhenMapped;
246  attributes.cursor = XCreateFontCursor(display, XC_X_cursor);
247
248  main_window = XCreateWindow(display, DefaultRootWindow(display),
249                              w_x, w_y, w_width, w_height, 0,
250                              CopyFromParent, InputOutput,
251                              CopyFromParent, CWCursor | CWBackingStore,
252                              &attributes);
253
254  hints->flags = PPosition | PSize | PMinSize | PMaxSize | PWinGravity;
255  hints->x = w_x; hints->y = w_y;
256  hints->width = w_width; hints->height = w_height;
257  hints->min_width = hints->max_width = w_width;
258  hints->min_height = hints->max_height = w_height;
259  hints->win_gravity = CenterGravity;
260  XSetWMNormalHints(display, main_window, hints);
261
262  XStoreName(display, main_window, "SSH Authentication Passphrase Request");
263
264  /* This is a dialog box, I think. */
265  XSetTransientForHint(display, main_window,
266                       DefaultRootWindow(display));
267  XFree(hints);
268
269  cancel_button = XCreateWindow(display, main_window,
270                                w_width - relief - margin - b_width,
271                                w_height - relief - margin - b_height,
272                                b_width, b_height,
273                                0,
274                                CopyFromParent, InputOutput,
275                                CopyFromParent, CWCursor |
276                                CWBackingStore,
277                                &attributes);
278 
279  leds = (w_width - relief * 2 - margin * 2 + (led_width - led_i_width)) /
280    led_width;
281  scrap = (w_width - relief * 2 - margin * 2 + (led_width - led_i_width)) %
282    led_width;
283  leds_x = relief + margin + scrap/2;
284
285  led_state = xmalloc(sizeof(int) * leds);
286  for (i = 0; i < leds; i++) led_state[i] = 0;
287 
288  attributes.cursor = XCreateFontCursor(display, XC_top_left_arrow);
289  XChangeWindowAttributes(display, cancel_button, CWCursor | CWBackingStore,
290                          &attributes);
291}
292
293/* Map the windows. */
294
295void map_windows(void)
296{
297  XMapRaised(display, main_window);
298  XMapWindow(display, cancel_button);
299}
300
301/* Load the font wanted. */
302
303void get_font(void)
304{
305  font_struct = XLoadQueryFont(display, font_spec);
306  if (!font_struct)
307    {
308      font_struct = XLoadQueryFont(display, font_fall_back);
309      if (!font_struct)
310        fatal ("Cannot load any font.");
311    }
312  font = font_struct->fid;
313}
314
315/* Calculate correct geometry for the main window. */
316
317void compute_dimensions(void)
318{
319  Status status;
320  Window root;
321  int dummy, d_width, d_height;
322  int dir, asc, desc;
323  XCharStruct overall;
324
325  XTextExtents(font_struct, prompt, strlen(prompt),
326               &dir, &asc, &desc, &overall);
327
328  button_dimensions(CANCEL_STRING, &b_width, &b_height);
329
330  w_width = XTextWidth(font_struct, prompt, strlen(prompt));
331  if (b_width > w_width) w_width = b_width;
332  w_width += relief * 2 + margin * 2;
333
334  w_height = asc + desc - 1 + margin * 2 + b_height + led_height;
335
336  w_height += relief * 2 + margin * 2;
337  status = XGetGeometry(display, DefaultRootWindow(display),
338                        &root, &dummy, &dummy, (unsigned int *)&d_width,
339                        (unsigned int *)&d_height, (unsigned int *)&dummy,
340                        (unsigned int *)&dummy);
341  w_x = (d_width - w_width) / 2;
342  w_y = (d_height - w_height) / 2;
343}
344
345/* An auxiliary function for getting a resource from the xrm. */
346
347void get_resource(char *name, char *class, char **where)
348{
349  char *type;
350  XrmValue value;
351  if (XrmGetResource(database, name, class, &type, &value) == True)
352    *where = value.addr;
353}
354
355/* Read and get some resources. */
356
357void read_resources(void)
358{
359  Status err;
360  unsigned char *prop_return;
361  unsigned long nitems_return, bytes_return;
362  int format_return;
363  Atom atom_return;
364
365  /* Read the current database in. */
366  database = NULL;
367  XrmInitialize();
368
369  err = XGetWindowProperty(display,
370                           DefaultRootWindow(display),
371                           XA_RESOURCE_MANAGER,
372                           0L, RESOURCES_MAX_LENGTH,
373                           False,
374                           XA_STRING,
375                           &atom_return,
376                           &format_return,
377                           &nitems_return,
378                           &bytes_return,
379                           &prop_return);
380
381  if (err == Success)
382    {
383      if (prop_return != NULL)
384        {
385          database = XrmGetStringDatabase((char *) prop_return);
386          XFree(prop_return);
387        }
388    }
389  else
390    {
391      fatal("XGetWindowProperty failed.");
392    }
393
394  if (!database) return;
395
396  get_resource("ssh.askpass.font", "SSH.AskPass.Font", &font_spec);
397  get_resource("ssh.askpass.background","SSH.AskPass.Background",
398               &background_color_name);
399  get_resource("ssh.askpass.foreground","SSH.AskPass.Foreground",
400               &foreground_color_name);
401  get_resource("ssh.askpass.prompt","SSH.AskPass.Prompt",
402               &prompt);
403}
404
405/* A function to print a string. Return the y-coordinate of the bottom
406   of the string's bounding box. */
407
408int put_string(int x, int y, char *string, int color, Window window)
409{
410  XCharStruct overall;
411  int dir, asc, desc;
412  XTextExtents(font_struct, string, strlen(string),
413               &dir, &asc, &desc, &overall);
414  y += overall.ascent;
415  XDrawString(display, window, gc[color],
416              x, y, string, strlen(string));
417  return (y + overall.descent);
418}
419
420/* Draw a raised/sunken box. */
421
422void relief_box(int x, int y, int a, int b, int left, int right, int depth,
423                int fill, Window window)
424{
425  int i;
426  for (i = 0; i < depth; i++)
427    {
428      XDrawLine(display, window, gc[left],
429                i + x, i + y, i + x, b - i);
430      XDrawLine(display, window, gc[left],
431                i + x, i + y, a - i, i + y);
432      XDrawLine(display, window, gc[right],
433                a - i, b - i,
434                i + x, b - i);
435      XDrawLine(display, window, gc[right],
436                a - i, b - i,
437                a - i, i + y);
438    }
439  if (fill != none)
440    XFillRectangle(display, window,
441                   gc[fill], i + x, i + y, a - x - 2*i + 1, b - y - 2*i + 1);
442}
443
444/* Draw a specific led. */
445
446void draw_led(int no, int on)
447{
448  relief_box(leds_x + led_width * no, leds_y,
449             leds_x + led_width * no + led_i_width,
450             leds_y + led_height, shadow, hilight, 2,
451             on ? light_led : dark_led, main_window);
452}
453
454/* Draw a button with certain string inside. */
455
456void draw_button(char *string, Window window, int width, int height,
457                 int pushed)
458{
459  if (!pushed)
460    {
461      relief_box(0, 0, width - 1, height - 1, hilight, shadow,
462                 2, background, window);
463      put_string(1 + margin, 1 + margin, string, text, window);
464    }
465  else
466    {
467      relief_box(2, 2, width - 1, height - 1, shadow, hilight,
468                 2, background, window);
469      relief_box(0, 0, width - 1, height - 1, shadow, hilight,
470                 2, none, window);
471      put_string(3 + margin, 3 + margin, string, text, window);
472    }
473}
474
475/* Draw the dialog box and the cancel button. */
476
477void draw_it(void)
478{
479  int y; int i;
480  relief_box(0, 0, w_width - 1, w_height - 1, hilight, shadow, relief,
481             background, main_window);
482  y = put_string(relief + margin, relief + margin, prompt, text, main_window);
483
484  leds_y = y + margin;
485
486  for (i = 0; i < leds; i ++)
487    {
488      draw_led(i, led_state[i]);
489    }
490  draw_button(CANCEL_STRING, cancel_button, b_width, b_height, 0);
491}
492
493/* Handle different X events. */
494
495void button_press(XButtonEvent *event)
496{
497  if (event->subwindow != cancel_button)
498    return;
499  draw_button(CANCEL_STRING, cancel_button, b_width, b_height, 1);
500  cancel_pressed = 1;
501}
502
503void button_release(XButtonEvent *event)
504{
505  if (event->subwindow != cancel_button)
506    {
507      if (cancel_pressed)
508        {
509          draw_button(CANCEL_STRING, cancel_button, b_width, b_height, 0);
510          cancel_pressed = 0;
511        }
512    }
513  else
514    {
515      if (cancel_pressed)
516        exiting = 2;
517    }
518}
519
520void advance_leds(void)
521{
522  led_state[next_led] ^= 1;
523  draw_led(next_led, led_state[next_led]);
524  next_led = (next_led + 1) % leds;
525}
526
527void backward_leds(void)
528{
529  next_led--; if (next_led == -1) next_led += leds;
530  led_state[next_led] ^= 1;
531  draw_led(next_led, led_state[next_led]); 
532}
533
534/* Handle key press. */
535void key_press(XKeyEvent *event)
536{
537  char buf[100];
538  char *ptr = buf;
539  int in_buf;
540
541  KeySym sym;
542
543  in_buf = XLookupString(event, buf, 100, &sym, NULL);
544
545  if ((sym != NoSymbol) && (sym & (0xff)) == sym)
546    {
547      while(in_buf-- > 0)
548        {
549          if ((ppointer - phrase) < 255)
550            {
551              *ppointer++ = *ptr++;
552              advance_leds();
553            }
554        }
555    }
556  else
557    /* Some special symbol. */
558    {
559      switch(sym)
560        {
561          /* These cause the last character to be eaten. */
562        case XK_Delete:
563        case XK_BackSpace:
564          if (ppointer != phrase)
565            {
566              ppointer--;
567              backward_leds();       
568            }
569          break;
570          /* These cause the event loop to terminate. */
571        case XK_Return:
572        case XK_Linefeed:
573        case XK_KP_Enter:
574          exiting = 1;
575          return;
576        case XK_Escape:
577        case XK_Cancel:
578          exiting = 2;
579          return;
580        }
581    }
582}
583
584/* Read the modifiers mapping. */
585void check_keyboard(void)
586{
587  modifiers = XGetModifierMapping(display);
588}
589
590/* Event loop. */
591void event_loop(void)
592{
593  int focused = 0;
594  XEvent event;
595  XSelectInput(display, main_window, ButtonPressMask |
596               VisibilityChangeMask | StructureNotifyMask |           
597               ExposureMask | ButtonReleaseMask | KeyPressMask);
598
599  /* Windows must be mapped not before XSelectInput, so that the
600     mapping notify will certainly arrive to our event loop. */
601  map_windows();
602
603  while(exiting == 0)
604    {
605      XNextEvent(display, &event);
606      switch (event.type)
607        {
608        case ButtonPress:
609          button_press(&event.xbutton);
610          break;
611        case ButtonRelease:
612          button_release(&event.xbutton);
613          break;
614        case KeyPress:
615          key_press(&event.xkey);
616          break;
617        case Expose:
618          if (event.xexpose.count == 0) {
619            draw_it();
620            if (!focused) {
621              XSetInputFocus(display, main_window, RevertToPointerRoot,
622                             CurrentTime);
623              if (XGrabKeyboard(display, main_window, True,
624                                GrabModeAsync, GrabModeAsync, CurrentTime)
625                  != GrabSuccess )
626                fatal ("Cannot grab keyboard.");
627              focused = 1;
628            }
629          }
630          break;                     
631        }
632    }
633  if (focused) {
634    XUngrabKeyboard(display, CurrentTime);
635  }
636  switch (exiting)
637    {
638    case 1:
639      *ppointer = 0;
640      printf("%s\n", phrase);
641      break;     
642    default:
643      break;     
644    }
645}
646
647int main(int argc, char **argv)
648{
649  open_display();
650  read_resources();
651
652  /* If we get just one argument, use it as the prompt. */
653  /* This must be called not before than read_resources() if we
654     wish to override the default from the resources database. */
655  if (argc == 2)
656    prompt = argv[1];
657
658  get_font();
659  compute_dimensions();
660  open_windows();
661  allocate_colors();
662  check_keyboard();
663  event_loop();
664  close_display();
665
666  return 0;
667}
Note: See TracBrowser for help on using the repository browser.