summaryrefslogtreecommitdiff
path: root/app/ssh-askpass/x11-ssh-askpass.c
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 10:57:01 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 10:57:01 +0000
commitf35ebe9caf290b8266faae05f7ab8491ad301d7a (patch)
tree39d39e6eac3dd73663d172228b40ec9bc2709301 /app/ssh-askpass/x11-ssh-askpass.c
parent1cb4778bcef21ea9015cfccdb99abb7a0e035d74 (diff)
Importing from XF4, plus BSD make infrastructure
Diffstat (limited to 'app/ssh-askpass/x11-ssh-askpass.c')
-rw-r--r--app/ssh-askpass/x11-ssh-askpass.c1551
1 files changed, 1551 insertions, 0 deletions
diff --git a/app/ssh-askpass/x11-ssh-askpass.c b/app/ssh-askpass/x11-ssh-askpass.c
new file mode 100644
index 000000000..48f882ae2
--- /dev/null
+++ b/app/ssh-askpass/x11-ssh-askpass.c
@@ -0,0 +1,1551 @@
+/* x11-ssh-askpass.c: A generic X11-based password dialog for OpenSSH.
+ * created 1999-Nov-17 03:40 Jim Knoble <jmknoble@jmknoble.cx>
+ * autodate: 2001-Feb-14 04:00
+ *
+ * by Jim Knoble <jmknoble@jmknoble.cx>
+ * Copyright (C) 1999,2000,2001 Jim Knoble
+ *
+ * Disclaimer:
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties of
+ * merchantability, fitness for a particular purpose and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages or other liability, whether in an action of
+ * contract, tort or otherwise, arising from, out of or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * Portions of this code are distantly derived from code in xscreensaver
+ * by Jamie Zawinski <jwz@jwz.org>. That code says:
+ *
+ * --------8<------------------------------------------------8<--------
+ * xscreensaver, Copyright (c) 1991-1999 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ * --------8<------------------------------------------------8<--------
+ *
+ * The remainder of this code falls under the same permissions and
+ * provisions as those of the xscreensaver code.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* For (get|set)rlimit() ... */
+#include <sys/time.h>
+#include <sys/resource.h>
+/* ... end */
+/* For (get|set)rlimit(), sleep(), and getpid() ... */
+#include <unistd.h>
+/* ... end */
+
+/* For errno ... */
+#include <errno.h>
+/* ... end */
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+#include <X11/Xos.h>
+#include "dynlist.h"
+#include "drawing.h"
+#include "resources.h"
+#include "x11-ssh-askpass.h"
+
+#undef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+char *progname = NULL;
+char *progclass = NULL;
+XrmDatabase db = 0;
+
+static char *defaults[] = {
+#include "SshAskpass_ad.h"
+ 0
+};
+
+void outOfMemory(AppInfo *app, int line)
+{
+ fprintf(stderr, "%s[%ld]: Aaahhh! I ran out of memory at line %d.\n",
+ app->appName, (long) app->pid, line);
+ exit(EXIT_STATUS_NO_MEMORY);
+}
+
+void freeIf(void *p)
+{
+ if (p) {
+ free(p);
+ }
+}
+
+void freeFontIf(AppInfo *app, XFontStruct *f)
+{
+ if (f) {
+ XFreeFont(app->dpy, f);
+ }
+}
+
+XFontStruct *getFontResource(AppInfo *app, char *instanceName, char *className)
+{
+ char *fallbackFont = "fixed";
+
+ XFontStruct *f = NULL;
+ char *s = get_string_resource(instanceName, className);
+ f = XLoadQueryFont(app->dpy, (s ? s : fallbackFont));
+ if (!f) {
+ f = XLoadQueryFont(app->dpy, fallbackFont);
+ }
+ if (s) {
+ free(s);
+ }
+ return(f);
+}
+
+char *getStringResourceWithDefault(char *instanceName, char *className,
+ char *defaultText)
+{
+ char *s = get_string_resource(instanceName, className);
+ if (!s) {
+ if (!defaultText) {
+ s = strdup("");
+ } else {
+ s = strdup(defaultText);
+ }
+ }
+ return(s);
+}
+
+unsigned int getUnsignedIntegerResource(AppInfo *app, char *instanceName,
+ char *className,
+ unsigned int defaultValue)
+{
+ int n;
+ unsigned int value;
+ char c;
+ char *s = get_string_resource(instanceName, className);
+ char *cp = s;
+
+ if (NULL == s) {
+ return(defaultValue);
+ }
+ while ((*cp) && isspace(*cp)) {
+ /* Skip whitespace. */
+ cp++;
+ }
+ if (*cp) {
+ if (('0' == cp[0]) && cp[1]) {
+ if (('x' == cp[1]) || ('X' == cp[1])) {
+ /* Hex */
+ n = sscanf(cp + 2, "%x %c", &value, &c);
+ } else {
+ /* Octal */
+ n = sscanf(cp + 1, "%o %c", &value, &c);
+ }
+ if (1 == n) {
+ free(s);
+ return(value);
+ }
+ } else {
+ /* Unsigned Decimal */
+ n = sscanf(cp, "%u %c", &value, &c);
+ if (1 == n) {
+ free(s);
+ return(value);
+ }
+ }
+ }
+ /* If we get here, no conversion succeeded. */
+ fprintf(stderr, "%s[%ld]: invalid value '%s' for %s.\n",
+ app->appName, (long) app->pid, s, instanceName);
+ free(s);
+ return(defaultValue);
+}
+
+/* Default resolution is 75 dots/inch. 1 in = 2.54 cm. */
+#define DefaultResolution ((75 * 10000) / 254)
+long getResolutionResource(AppInfo *app, char *instanceName, char *className,
+ char *defaultResolutionSpec)
+{
+ char units[3];
+ char *s;
+ int n;
+ long resolution;
+ unsigned int i;
+
+ memset(units, 0, sizeof(units));
+ s = getStringResourceWithDefault(instanceName, className,
+ defaultResolutionSpec);
+ /* NOTE: The width of the %s format must be one less than
+ * the length of the units[] array above!
+ */
+ n = sscanf(s, "%ld / %2s", &resolution, units);
+ if (n != 2) {
+ fprintf(stderr, "%s[%ld]: invalid value '%s' for %s.\n",
+ app->appName, (long) app->pid, s, instanceName);
+ resolution = DefaultResolution;
+ } else {
+ if (resolution < 0) {
+ /* Resolution specifications should not be negative. */
+ resolution = -(resolution);
+ }
+ for (i = 0; i < (sizeof(units) - 1); i++) {
+ units[i] = tolower(units[i]);
+ }
+ if ((0 == strcmp(units, "in")) ||
+ (0 == strcmp(units, "i")) ||
+ (0 == strcmp(units, "\""))) {
+ /* dots/inch */
+ resolution = resolution * 10000 / 254;
+ } else if ((0 == strcmp(units, "m")) ||
+ (0 == strcmp(units, "me"))) {
+ /* dots/meter; no conversion necessary */
+ ;
+ } else {
+ /* some unit we don't recognize; cringe and stare at the floor */
+ resolution = DefaultResolution;
+ }
+ }
+ return(resolution);
+}
+#undef DefaultResolution
+
+void calcTextObjectExtents(TextObject *t, XFontStruct *font) {
+ if ((!t) || (!(t->text))) {
+ return;
+ }
+ t->textLength = strlen(t->text);
+ XTextExtents(font, t->text, t->textLength, &(t->direction),
+ &(t->ascent), &(t->descent), &(t->overall));
+}
+
+void calcLabelTextExtents(LabelInfo *label)
+{
+ TextObject *t;
+
+ if ((!label) || (!(label->fullText)) || (!(label->font))) {
+ return;
+ }
+ t = label->multiText;
+ while (NULL != t) {
+ calcTextObjectExtents(t, label->font);
+ label->w.height += (t->ascent + t->descent);
+ if (label->w.width < t->overall.width) {
+ label->w.width = t->overall.width;
+ }
+ t = t->next;
+ }
+}
+
+void calcTotalButtonExtents(ButtonInfo *button)
+{
+ if (!button) {
+ return;
+ }
+ button->w3.w.width = (button->w3.interiorWidth +
+ (2 * button->w3.shadowThickness));
+ button->w3.w.width += (2 * button->w3.borderWidth);
+ button->w3.w.height = (button->w3.interiorHeight +
+ (2 * button->w3.shadowThickness));
+ button->w3.w.height += (2 * button->w3.borderWidth);
+}
+
+void calcButtonExtents(ButtonInfo *button)
+{
+ if (!button) {
+ return;
+ }
+ calcLabelTextExtents(&(button->label));
+ button->w3.interiorWidth = (button->label.w.width +
+ (2 * button->w3.horizontalSpacing));
+ button->w3.interiorHeight = (button->label.w.height +
+ (2 * button->w3.verticalSpacing));
+ calcTotalButtonExtents(button);
+}
+
+void balanceButtonExtents(ButtonInfo *button1, ButtonInfo *button2)
+{
+ if ((!button1) || (!button2)) {
+ return;
+ }
+ button1->w3.interiorWidth = button2->w3.interiorWidth =
+ MAX(button1->w3.interiorWidth, button2->w3.interiorWidth);
+ button1->w3.interiorHeight = button2->w3.interiorHeight =
+ MAX(button1->w3.interiorHeight, button2->w3.interiorHeight);
+ calcTotalButtonExtents(button1);
+ calcTotalButtonExtents(button2);
+}
+
+void calcButtonLabelPosition(ButtonInfo *button)
+{
+ if (!button) {
+ return;
+ }
+ button->label.w.x = button->w3.w.x +
+ ((button->w3.w.width - button->label.w.width) / 2);
+ button->label.w.y = button->w3.w.y +
+ ((button->w3.w.height - button->label.w.height) / 2);
+}
+
+Dimension scaleXDimension(AppInfo *app, Dimension unscaled)
+{
+ Dimension scaled;
+
+ if (((app->defaultXResolution < app->xResolution) &&
+ ((app->defaultXResolution + app->xFuzz) < app->xResolution)) ||
+ ((app->xResolution < app->defaultXResolution) &&
+ ((app->xResolution + app->xFuzz) < app->defaultXResolution))) {
+ scaled = (unscaled * app->xResolution) / app->defaultXResolution;
+ } else {
+ scaled = unscaled;
+ }
+ return(scaled);
+}
+
+Dimension scaleYDimension(AppInfo *app, Dimension unscaled)
+{
+ Dimension scaled;
+
+ if (((app->defaultYResolution < app->yResolution) &&
+ ((app->defaultYResolution + app->yFuzz) < app->yResolution)) ||
+ ((app->yResolution < app->defaultYResolution) &&
+ ((app->yResolution + app->yFuzz) < app->defaultYResolution))) {
+ scaled = (unscaled * app->yResolution) / app->defaultYResolution;
+ } else {
+ scaled = unscaled;
+ }
+ return(scaled);
+}
+
+/* Assumes 's' is non-NULL. */
+TextObject *createTextObject(AppInfo *app, char *s)
+{
+ TextObject *t = malloc(sizeof(*t));
+ if (NULL == t) {
+ outOfMemory(app, __LINE__);
+ }
+ memset(t, 0, sizeof(*t));
+ if (('\n' == *s) || ('\0' == *s)) {
+ t->text = " ";
+ } else {
+ t->text = s;
+ }
+ return(t);
+}
+
+/* Assumes 'label' object exists and is zeroed. */
+void createLabel(AppInfo *app, char *text, LabelInfo *label)
+{
+ char *substring;
+ TextObject *t;
+
+ if ((!app) || (!text)) {
+ return;
+ }
+ label->fullText = strdup(text);
+ label->multiText = createTextObject(app, label->fullText);
+ t = label->multiText;
+ substring = strchr(label->fullText, '\n');
+ while (NULL != substring) {
+ *(substring++) = '\0';
+ t->next = createTextObject(app, substring);
+ if (t->next) {
+ t = t->next;
+ }
+ substring = strchr(substring, '\n');
+ }
+}
+
+void createDialog(AppInfo *app)
+{
+ DialogInfo *d;
+ char *labelText;
+
+ if (app->dialog) {
+ return;
+ }
+ d = malloc(sizeof(*d));
+ if (NULL == d) {
+ outOfMemory(app, __LINE__);
+ }
+ memset(d, 0, sizeof(*d));
+
+ app->grabKeyboard =
+ get_boolean_resource("grabKeyboard", "GrabKeyboard", True);
+ app->grabPointer =
+ get_boolean_resource("grabPointer", "GrabPointer", False);
+ app->grabServer =
+ get_boolean_resource("grabServer", "GrabServer", False);
+
+ /* inputTimeout resource specified in seconds for easy human interface.
+ * Convert to milliseconds here.
+ */
+ app->inputTimeout = (unsigned long) 1000 *
+ getUnsignedIntegerResource(app, "inputTimeout", "InputTimeout", 0);
+
+ app->defaultXResolution =
+ getResolutionResource(app, "defaultXResolution", "DefaultXResolution",
+ "75/in");
+ app->defaultYResolution =
+ getResolutionResource(app, "defaultYResolution", "DefaultYResolution",
+ "75/in");
+ app->xFuzz =
+ getResolutionResource(app, "xResolutionFuzz", "XResolutionFuzz", "20/in");
+ app->yFuzz =
+ getResolutionResource(app, "yResolutionFuzz", "YResolutionFuzz", "20/in");
+
+ d->title =
+ getStringResourceWithDefault("dialog.title", "Dialog.Title",
+ "OpenSSH Authentication Passphrase Request");
+ d->w3.w.foreground =
+ get_pixel_resource("foreground", "Foreground",
+ app->dpy, app->colormap, app->black);
+ d->w3.w.background =
+ get_pixel_resource("background", "Background",
+ app->dpy, app->colormap, app->white);
+ d->w3.topShadowColor =
+ get_pixel_resource("topShadowColor", "TopShadowColor",
+ app->dpy, app->colormap, app->white);
+ d->w3.bottomShadowColor =
+ get_pixel_resource("bottomShadowColor", "BottomShadowColor",
+ app->dpy, app->colormap, app->black);
+ d->w3.shadowThickness =
+ get_integer_resource("shadowThickness", "ShadowThickness", 3);
+ d->w3.borderColor =
+ get_pixel_resource("borderColor", "BorderColor",
+ app->dpy, app->colormap, app->black);
+ d->w3.borderWidth =
+ get_integer_resource("borderWidth", "BorderWidth", 1);
+
+ d->w3.horizontalSpacing = scaleXDimension(app,
+ get_integer_resource("horizontalSpacing", "Spacing", 5));
+ d->w3.verticalSpacing = scaleYDimension(app,
+ get_integer_resource("verticalSpacing", "Spacing", 6));
+
+ if (2 == app->argc) {
+ labelText = strdup(app->argv[1]);
+ } else {
+ labelText =
+ getStringResourceWithDefault("dialog.label", "Dialog.Label",
+ "Please enter your authentication passphrase:");
+ }
+ createLabel(app, labelText, &(d->label));
+ freeIf(labelText);
+ d->label.font = getFontResource(app, "dialog.font", "Dialog.Font");
+ calcLabelTextExtents(&(d->label));
+ d->label.w.foreground = d->w3.w.foreground;
+ d->label.w.background = d->w3.w.background;
+
+ d->okButton.w3.w.foreground =
+ get_pixel_resource("okButton.foreground", "Button.Foreground",
+ app->dpy, app->colormap, app->black);
+ d->okButton.w3.w.background =
+ get_pixel_resource("okButton.background", "Button.Background",
+ app->dpy, app->colormap, app->white);
+ d->okButton.w3.topShadowColor =
+ get_pixel_resource("okButton.topShadowColor", "Button.TopShadowColor",
+ app->dpy, app->colormap, app->white);
+ d->okButton.w3.bottomShadowColor =
+ get_pixel_resource("okButton.bottomShadowColor",
+ "Button.BottomShadowColor",
+ app->dpy, app->colormap, app->black);
+ d->okButton.w3.shadowThickness =
+ get_integer_resource("okButton.shadowThickness",
+ "Button.ShadowThickness", 2);
+ d->okButton.w3.borderColor =
+ get_pixel_resource("okButton.borderColor", "Button.BorderColor",
+ app->dpy, app->colormap, app->black);
+ d->okButton.w3.borderWidth =
+ get_integer_resource("okButton.borderWidth", "Button.BorderWidth", 1);
+ d->okButton.w3.horizontalSpacing = scaleXDimension(app,
+ get_integer_resource("okButton.horizontalSpacing", "Button.Spacing", 4));
+ d->okButton.w3.verticalSpacing = scaleYDimension(app,
+ get_integer_resource("okButton.verticalSpacing", "Button.Spacing", 2));
+ labelText =
+ getStringResourceWithDefault("okButton.label", "Button.Label", "OK");
+ createLabel(app, labelText, &(d->okButton.label));
+ freeIf(labelText);
+ d->okButton.label.font =
+ getFontResource(app, "okButton.font", "Button.Font");
+ calcButtonExtents(&(d->okButton));
+ d->okButton.label.w.foreground = d->okButton.w3.w.foreground;
+ d->okButton.label.w.background = d->okButton.w3.w.background;
+
+ d->cancelButton.w3.w.foreground =
+ get_pixel_resource("cancelButton.foreground", "Button.Foreground",
+ app->dpy, app->colormap, app->black);
+ d->cancelButton.w3.w.background =
+ get_pixel_resource("cancelButton.background", "Button.Background",
+ app->dpy, app->colormap, app->white);
+ d->cancelButton.w3.topShadowColor =
+ get_pixel_resource("cancelButton.topShadowColor",
+ "Button.TopShadowColor",
+ app->dpy, app->colormap, app->white);
+ d->cancelButton.w3.bottomShadowColor =
+ get_pixel_resource("cancelButton.bottomShadowColor",
+ "Button.BottomShadowColor",
+ app->dpy, app->colormap, app->black);
+ d->cancelButton.w3.shadowThickness =
+ get_integer_resource("cancelButton.shadowThickness",
+ "Button.ShadowThickness", 2);
+ d->cancelButton.w3.borderColor =
+ get_pixel_resource("cancelButton.borderColor", "Button.BorderColor",
+ app->dpy, app->colormap, app->black);
+ d->cancelButton.w3.borderWidth =
+ get_integer_resource("cancelButton.borderWidth", "Button.BorderWidth",
+ 1);
+ d->cancelButton.w3.horizontalSpacing = scaleXDimension(app,
+ get_integer_resource("cancelButton.horizontalSpacing", "Button.Spacing",
+ 4));
+ d->cancelButton.w3.verticalSpacing = scaleYDimension(app,
+ get_integer_resource("cancelButton.verticalSpacing", "Button.Spacing",
+ 2));
+ labelText =
+ getStringResourceWithDefault("cancelButton.label", "Button.Label",
+ "Cancel");
+ createLabel(app, labelText, &(d->cancelButton.label));
+ freeIf(labelText);
+ d->cancelButton.label.font =
+ getFontResource(app, "cancelButton.font", "Button.Font");
+ calcButtonExtents(&(d->cancelButton));
+ d->cancelButton.label.w.foreground = d->cancelButton.w3.w.foreground;
+ d->cancelButton.label.w.background = d->cancelButton.w3.w.background;
+
+ balanceButtonExtents(&(d->okButton), &(d->cancelButton));
+
+ d->indicator.w3.w.foreground =
+ get_pixel_resource("indicator.foreground", "Indicator.Foreground",
+ app->dpy, app->colormap, app->black);
+ d->indicator.w3.w.background =
+ get_pixel_resource("indicator.background", "Indicator.Background",
+ app->dpy, app->colormap, app->white);
+ d->indicator.w3.w.width = scaleXDimension(app,
+ get_integer_resource("indicator.width", "Indicator.Width", 15));
+ d->indicator.w3.w.height = scaleYDimension(app,
+ get_integer_resource("indicator.height", "Indicator.Height", 7));
+ d->indicator.w3.topShadowColor =
+ get_pixel_resource("indicator.topShadowColor",
+ "Indicator.TopShadowColor",
+ app->dpy, app->colormap, app->white);
+ d->indicator.w3.bottomShadowColor =
+ get_pixel_resource("indicator.bottomShadowColor",
+ "Indicator.BottomShadowColor",
+ app->dpy, app->colormap, app->black);
+ d->indicator.w3.shadowThickness =
+ get_integer_resource("indicator.shadowThickness",
+ "Indicator.ShadowThickness", 2);
+ d->indicator.w3.borderColor =
+ get_pixel_resource("indicator.borderColor", "Indicator.BorderColor",
+ app->dpy, app->colormap, app->black);
+ d->indicator.w3.borderWidth =
+ get_integer_resource("indicator.borderWidth", "Indicator.BorderWidth",
+ 0);
+ d->indicator.w3.horizontalSpacing = scaleXDimension(app,
+ get_integer_resource("indicator.horizontalSpacing", "Indicator.Spacing",
+ 2));
+ d->indicator.w3.verticalSpacing =scaleYDimension(app,
+ get_integer_resource("indicator.verticalSpacing", "Indicator.Spacing",
+ 4));
+ d->indicator.minimumCount =
+ get_integer_resource("indicator.minimumCount", "Indicator.MinimumCount",
+ 8);
+ d->indicator.maximumCount =
+ get_integer_resource("indicator.maximumCount", "Indicator.MaximumCount",
+ 24);
+ d->indicator.w3.interiorWidth = d->indicator.w3.w.width;
+ d->indicator.w3.interiorHeight = d->indicator.w3.w.height;
+ d->indicator.w3.w.width += (2 * d->indicator.w3.shadowThickness);
+ d->indicator.w3.w.width += (2 * d->indicator.w3.borderWidth);
+ d->indicator.w3.w.height += (2 * d->indicator.w3.shadowThickness);
+ d->indicator.w3.w.height += (2 * d->indicator.w3.borderWidth);
+ {
+ /* Make sure the indicators can all fit on the screen.
+ * 80% of the screen width seems fine.
+ */
+ Dimension maxWidth = (WidthOfScreen(app->screen) * 8 / 10);
+ Dimension extraSpace = ((2 * d->w3.horizontalSpacing) +
+ (2 * d->w3.shadowThickness));
+
+ if (d->indicator.maximumCount < 8) {
+ d->indicator.maximumCount = 8;
+ }
+ if (((d->indicator.maximumCount * d->indicator.w3.w.width) +
+ ((d->indicator.maximumCount - 1) *
+ d->indicator.w3.horizontalSpacing) + extraSpace) > maxWidth) {
+ d->indicator.maximumCount =
+ ((maxWidth - extraSpace - d->indicator.w3.w.width) /
+ (d->indicator.w3.w.width + d->indicator.w3.horizontalSpacing))
+ + 1;
+ }
+ if (d->indicator.minimumCount <= 6) {
+ d->indicator.minimumCount = 6;
+ }
+ if (d->indicator.minimumCount > d->indicator.maximumCount) {
+ d->indicator.minimumCount = d->indicator.maximumCount;
+ }
+ }
+
+ {
+ /* Calculate the width and horizontal position of things. */
+ Dimension labelAreaWidth;
+ Dimension buttonAreaWidth;
+ Dimension indicatorAreaWidth;
+ Dimension extraIndicatorSpace;
+ Dimension singleIndicatorSpace;
+ Dimension interButtonSpace;
+ Dimension w;
+ Position leftX;
+ int i;
+
+ labelAreaWidth = d->label.w.width + (2 * d->w3.horizontalSpacing);
+ buttonAreaWidth = ((3 * d->w3.horizontalSpacing) +
+ d->okButton.w3.w.width +
+ d->cancelButton.w3.w.width);
+ w = MAX(labelAreaWidth, buttonAreaWidth);
+ extraIndicatorSpace = ((2 * d->w3.horizontalSpacing) +
+ d->indicator.w3.w.width);
+ singleIndicatorSpace = (d->indicator.w3.w.width +
+ d->indicator.w3.horizontalSpacing);
+ d->indicator.count = ((w - extraIndicatorSpace) / singleIndicatorSpace);
+ d->indicator.current = 0;
+ d->indicator.count++; /* For gatepost indicator in extra space. */
+ if (((w - extraIndicatorSpace) % singleIndicatorSpace) >
+ (singleIndicatorSpace / 2)) {
+ d->indicator.count++;
+ }
+ if (d->indicator.count < d->indicator.minimumCount) {
+ d->indicator.count = d->indicator.minimumCount;
+ }
+ if (d->indicator.count > d->indicator.maximumCount) {
+ d->indicator.count = d->indicator.maximumCount;
+ }
+ indicatorAreaWidth = ((singleIndicatorSpace * (d->indicator.count - 1)) +
+ extraIndicatorSpace);
+ d->w3.interiorWidth = MAX(w, indicatorAreaWidth);
+ d->w3.w.width = d->w3.interiorWidth + (2 * d->w3.shadowThickness);
+
+ leftX = (d->w3.w.width - d->label.w.width) / 2;
+ d->label.w.x = leftX;
+
+ leftX = ((d->w3.w.width -
+ (d->indicator.count * d->indicator.w3.w.width) -
+ ((d->indicator.count - 1) * d->indicator.w3.horizontalSpacing))
+ / 2);
+ {
+ int n = d->indicator.count * sizeof(IndicatorElement);
+ d->indicators = malloc(n);
+ if (NULL == d->indicators) {
+ destroyDialog(app);
+ outOfMemory(app, __LINE__);
+ }
+ memset(d->indicators, 0, n);
+ }
+ d->indicators[0].parent = &(d->indicator);
+ d->indicators[0].w.x = d->indicator.w3.w.x = leftX;
+ d->indicators[0].w.width = d->indicator.w3.w.width;
+ d->indicators[0].isLit = False;
+ for (i = 1; i < d->indicator.count; i++) {
+ d->indicators[i].parent = &(d->indicator);
+ d->indicators[i].w.x = (d->indicators[i - 1].w.x +
+ d->indicator.w3.w.width +
+ d->indicator.w3.horizontalSpacing);
+ d->indicators[i].w.width = d->indicator.w3.w.width;
+ d->indicators[i].isLit = False;
+ }
+ interButtonSpace = ((d->w3.interiorWidth - d->okButton.w3.w.width -
+ d->cancelButton.w3.w.width) / 3);
+ d->okButton.w3.w.x = interButtonSpace + d->w3.shadowThickness;
+ d->cancelButton.w3.w.x = (d->okButton.w3.w.x + d->okButton.w3.w.width +
+ interButtonSpace);
+ }
+ {
+ /* Calculate the height and vertical position of things. */
+ int i;
+
+ d->w3.interiorHeight = ((4 * d->w3.verticalSpacing) +
+ (2 * d->indicator.w3.verticalSpacing) +
+ d->label.w.height +
+ d->indicator.w3.w.height +
+ d->okButton.w3.w.height);
+ d->w3.w.height = d->w3.interiorHeight + (2 * d->w3.shadowThickness);
+ d->label.w.y = d->w3.shadowThickness + d->w3.verticalSpacing;
+ d->indicator.w3.w.y = (d->label.w.y + d->label.w.height +
+ d->w3.verticalSpacing +
+ d->indicator.w3.verticalSpacing);
+ for (i = 0; i < d->indicator.count; i++) {
+ d->indicators[i].w.y = d->indicator.w3.w.y;
+ d->indicators[i].w.height = d->indicator.w3.w.height;
+ }
+ d->okButton.w3.w.y = d->cancelButton.w3.w.y =
+ (d->indicator.w3.w.y + d->indicator.w3.w.height +
+ d->w3.verticalSpacing + d->indicator.w3.verticalSpacing);
+ }
+ calcButtonLabelPosition(&(d->okButton));
+ calcButtonLabelPosition(&(d->cancelButton));
+
+ d->w3.w.x = (WidthOfScreen(app->screen) - d->w3.w.width) / 2;
+ d->w3.w.y = (HeightOfScreen(app->screen) - d->w3.w.height) / 3;
+
+ app->dialog = d;
+}
+
+void destroyLabel(AppInfo *app, LabelInfo *label)
+{
+ TextObject *thisTextObject;
+ TextObject *nextTextObject;
+
+ thisTextObject = label->multiText;
+ nextTextObject = thisTextObject->next;
+ freeIf(thisTextObject);
+ while (NULL != nextTextObject) {
+ thisTextObject = nextTextObject;
+ nextTextObject = thisTextObject->next;
+ freeIf(thisTextObject);
+ }
+ freeIf(label->fullText);
+ freeFontIf(app, label->font);
+}
+
+void destroyDialog(AppInfo *app)
+{
+ DialogInfo *d = app->dialog;
+
+ freeIf(d->title);
+ freeIf(d->indicators);
+
+ destroyLabel(app, &(d->label));
+ destroyLabel(app, &(d->okButton.label));
+ destroyLabel(app, &(d->cancelButton.label));
+
+ XFree(d->sizeHints);
+ XFree(d->wmHints);
+ XFree(d->classHints);
+ XFree(d->windowName.value);
+
+ freeIf(d);
+}
+
+void createDialogWindow(AppInfo *app)
+{
+ XSetWindowAttributes attr;
+ unsigned long attrMask = 0;
+ DialogInfo *d = app->dialog;
+
+ attr.background_pixel = d->w3.w.background;
+ attrMask |= CWBackPixel;
+ attr.border_pixel = d->w3.borderColor;
+ attrMask |= CWBorderPixel;
+ attr.cursor = None;
+ attrMask |= CWCursor;
+ attr.event_mask = app->eventMask;
+ attrMask |= CWEventMask;
+
+ d->dialogWindow = XCreateWindow(app->dpy, app->rootWindow,
+ d->w3.w.x, d->w3.w.y,
+ d->w3.w.width, d->w3.w.height,
+ d->w3.borderWidth,
+ DefaultDepthOfScreen(app->screen),
+ InputOutput,
+ DefaultVisualOfScreen(app->screen),
+ attrMask, &attr);
+
+ d->sizeHints = XAllocSizeHints();
+ if (!(d->sizeHints)) {
+ destroyDialog(app);
+ outOfMemory(app, __LINE__);
+ }
+ d->sizeHints->flags = 0;
+ d->sizeHints->flags |= PPosition;
+ d->sizeHints->flags |= PSize;
+ d->sizeHints->min_width = d->w3.w.width;
+ d->sizeHints->min_height = d->w3.w.height;
+ d->sizeHints->flags |= PMinSize;
+ d->sizeHints->max_width = d->w3.w.width;
+ d->sizeHints->max_height = d->w3.w.height;
+ d->sizeHints->flags |= PMaxSize;
+ d->sizeHints->base_width = d->w3.w.width;
+ d->sizeHints->base_height = d->w3.w.height;
+ d->sizeHints->flags |= PBaseSize;
+
+ d->wmHints = XAllocWMHints();
+ if (!(d->wmHints)) {
+ destroyDialog(app);
+ outOfMemory(app, __LINE__);
+ }
+ d->wmHints->flags = 0;
+ d->wmHints->input = True;
+ d->wmHints->flags |= InputHint;
+ d->wmHints->initial_state = NormalState;
+ d->wmHints->flags |= StateHint;
+
+ d->classHints = XAllocClassHint();
+ if (!(d->classHints)) {
+ destroyDialog(app);
+ outOfMemory(app, __LINE__);
+ }
+ d->classHints->res_name = app->appName;
+ d->classHints->res_class = app->appClass;
+
+ if (!XStringListToTextProperty(&(d->title), 1, &(d->windowName))) {
+ destroyDialog(app);
+ outOfMemory(app, __LINE__);
+ }
+ XSetWMProperties(app->dpy, d->dialogWindow, &(d->windowName), NULL,
+ app->argv, app->argc, d->sizeHints,
+ d->wmHints, d->classHints);
+ XSetTransientForHint(app->dpy, d->dialogWindow, d->dialogWindow);
+
+ app->wmDeleteWindowAtom = XInternAtom(app->dpy, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(app->dpy, d->dialogWindow, &(app->wmDeleteWindowAtom), 1);
+}
+
+void createGCs(AppInfo *app)
+{
+ DialogInfo *d = app->dialog;
+
+ XGCValues gcv;
+ unsigned long gcvMask;
+
+ gcvMask = 0;
+ gcv.foreground = d->w3.w.background;
+ gcvMask |= GCForeground;
+ gcv.fill_style = FillSolid;
+ gcvMask |= GCFillStyle;
+ app->fillGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv);
+
+ gcvMask = 0;
+ gcv.foreground = d->w3.borderColor;
+ gcvMask |= GCForeground;
+ gcv.line_width = d->w3.borderWidth;
+ gcvMask |= GCLineWidth;
+ gcv.line_style = LineSolid;
+ gcvMask |= GCLineStyle;
+ gcv.cap_style = CapButt;
+ gcvMask |= GCCapStyle;
+ gcv.join_style = JoinMiter;
+ gcvMask |= GCJoinStyle;
+ app->borderGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv);
+
+ gcvMask = 0;
+ gcv.foreground = d->label.w.foreground;
+ gcvMask |= GCForeground;
+ gcv.background = d->label.w.background;
+ gcvMask |= GCBackground;
+ gcv.font = d->label.font->fid;
+ gcvMask |= GCFont;
+ app->textGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv);
+
+ gcvMask = 0;
+ gcv.foreground = d->indicator.w3.w.foreground;
+ gcvMask |= GCForeground;
+ gcv.fill_style = FillSolid;
+ gcvMask |= GCFillStyle;
+ app->brightGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv);
+
+ gcvMask = 0;
+ gcv.foreground = d->indicator.w3.w.background;
+ gcvMask |= GCForeground;
+ gcv.fill_style = FillSolid;
+ gcvMask |= GCFillStyle;
+ app->dimGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv);
+}
+
+void destroyGCs(AppInfo *app)
+{
+ XFreeGC(app->dpy, app->fillGC);
+ XFreeGC(app->dpy, app->borderGC);
+ XFreeGC(app->dpy, app->textGC);
+ XFreeGC(app->dpy, app->brightGC);
+ XFreeGC(app->dpy, app->dimGC);
+}
+
+void paintLabel(AppInfo *app, Drawable draw, LabelInfo label)
+{
+ TextObject *t;
+ Position x;
+ Position y;
+
+ if (!(label.fullText)) {
+ return;
+ }
+ XSetForeground(app->dpy, app->textGC, label.w.foreground);
+ XSetBackground(app->dpy, app->textGC, label.w.background);
+ XSetFont(app->dpy, app->textGC, label.font->fid);
+
+ t = label.multiText;
+ x = label.w.x;
+ y = label.w.y + t->ascent;
+ while (NULL != t) {
+ if (t->text) {
+ XDrawString(app->dpy, draw, app->textGC, x, y, t->text,
+ t->textLength);
+ }
+ y += t->descent;
+ t = t->next;
+ if (t) {
+ y += t->ascent;
+ }
+ }
+}
+
+void paintButton(AppInfo *app, Drawable draw, ButtonInfo button)
+{
+ Position x;
+ Position y;
+ Dimension width;
+ Dimension height;
+
+ if (button.w3.borderWidth > 0) {
+ XSetForeground(app->dpy, app->borderGC, button.w3.borderColor);
+ XFillRectangle(app->dpy, draw, app->borderGC, button.w3.w.x,
+ button.w3.w.y, button.w3.w.width, button.w3.w.height);
+ }
+ if ((button.w3.shadowThickness <= 0) && (button.pressed)) {
+ Pixel tmp = button.w3.w.background;
+ button.w3.w.background = button.w3.w.foreground;
+ button.w3.w.foreground = tmp;
+ tmp = button.label.w.background;
+ button.label.w.background = button.label.w.foreground;
+ button.label.w.foreground = tmp;
+ }
+ x = (button.w3.w.x + button.w3.borderWidth);
+ y = (button.w3.w.y + button.w3.borderWidth);
+ width = (button.w3.w.width - (2 * button.w3.borderWidth));
+ height = (button.w3.w.height - (2 * button.w3.borderWidth));
+ if ((button.w3.shadowThickness > 0) && (button.pressed)) {
+ XSetForeground(app->dpy, app->fillGC, button.w3.topShadowColor);
+ } else {
+ XSetForeground(app->dpy, app->fillGC, button.w3.w.background);
+ }
+ XFillRectangle(app->dpy, draw, app->fillGC, x, y, width, height);
+ if (button.w3.shadowThickness > 0) {
+ if (button.pressed) {
+ draw_shaded_rectangle(app->dpy, draw, x, y, width, height,
+ button.w3.shadowThickness,
+ button.w3.bottomShadowColor,
+ button.w3.topShadowColor);
+ } else {
+ draw_shaded_rectangle(app->dpy, draw, x, y, width, height,
+ button.w3.shadowThickness,
+ button.w3.topShadowColor,
+ button.w3.bottomShadowColor);
+ }
+ }
+ if ((button.w3.shadowThickness > 0) && (button.pressed)) {
+ Dimension pressedAdjustment;
+
+ pressedAdjustment = button.w3.shadowThickness / 2;
+ if (pressedAdjustment < 1) {
+ pressedAdjustment = 1;
+ }
+ x = button.label.w.x;
+ y = button.label.w.y;
+ button.label.w.x += pressedAdjustment;
+ button.label.w.y += pressedAdjustment;
+ paintLabel(app, draw, button.label);
+ button.label.w.x = x;
+ button.label.w.y = y;
+ } else {
+ paintLabel(app, draw, button.label);
+ }
+ if ((button.w3.shadowThickness <= 0) && (button.pressed)) {
+ Pixel tmp = button.w3.w.background;
+ button.w3.w.background = button.w3.w.foreground;
+ button.w3.w.foreground = tmp;
+ tmp = button.label.w.background;
+ button.label.w.background = button.label.w.foreground;
+ button.label.w.foreground = tmp;
+ }
+}
+
+void paintIndicator(AppInfo *app, Drawable draw, IndicatorElement indicator)
+{
+ Position x;
+ Position y;
+ Dimension width;
+ Dimension height;
+ GC gc = app->dimGC;
+
+ if (indicator.parent->w3.borderWidth > 0) {
+ XSetForeground(app->dpy, app->borderGC,
+ indicator.parent->w3.borderColor);
+ XFillRectangle(app->dpy, draw, app->borderGC, indicator.w.x,
+ indicator.w.y, indicator.w.width, indicator.w.height);
+ }
+ if (indicator.isLit) {
+ gc = app->brightGC;
+ }
+ x = (indicator.w.x + indicator.parent->w3.borderWidth);
+ y = (indicator.w.y + indicator.parent->w3.borderWidth);
+ width = (indicator.w.width - (2 * indicator.parent->w3.borderWidth));
+ height = (indicator.w.height - (2 * indicator.parent->w3.borderWidth));
+ XFillRectangle(app->dpy, draw, gc, x, y, width, height);
+ if (indicator.parent->w3.shadowThickness > 0) {
+ draw_shaded_rectangle(app->dpy, draw, x, y, width, height,
+ indicator.parent->w3.shadowThickness,
+ indicator.parent->w3.bottomShadowColor,
+ indicator.parent->w3.topShadowColor);
+ }
+}
+
+void updateIndicatorElement(AppInfo *app, int i)
+{
+ DialogInfo *d = app->dialog;
+
+ d->indicators[i].isLit = !(d->indicators[i].isLit);
+ paintIndicator(app, d->dialogWindow, d->indicators[i]);
+}
+
+void updateIndicators(AppInfo *app, int condition)
+{
+ DialogInfo *d = app->dialog;
+
+ if (condition > 0) {
+ /* Move forward one. */
+ updateIndicatorElement(app, d->indicator.current);
+ if (d->indicator.current < (d->indicator.count - 1)) {
+ (d->indicator.current)++;
+ } else {
+ d->indicator.current = 0;
+ }
+ } else if (condition < 0) {
+ /* Move backward one. */
+ if (d->indicator.current > 0) {
+ (d->indicator.current)--;
+ } else {
+ d->indicator.current = d->indicator.count - 1;
+ }
+ updateIndicatorElement(app, d->indicator.current);
+ } else {
+ /* Erase them all. */
+ int i;
+
+ for (i = 0; i < d->indicator.count; i++) {
+ d->indicators[i].isLit = False;
+ paintIndicator(app, d->dialogWindow, d->indicators[i]);
+ }
+ d->indicator.current = 0;
+ }
+ XSync(app->dpy, False);
+}
+
+void paintDialog(AppInfo *app)
+{
+ DialogInfo *d = app->dialog;
+ Drawable draw = d->dialogWindow;
+ int i;
+
+ XSetForeground(app->dpy, app->fillGC, d->w3.w.background);
+ XFillRectangle(app->dpy, draw, app->fillGC, 0, 0,
+ d->w3.w.width, d->w3.w.height);
+ if (d->w3.shadowThickness > 0) {
+ draw_shaded_rectangle(app->dpy, draw, 0, 0,
+ d->w3.w.width, d->w3.w.height,
+ d->w3.shadowThickness,
+ d->w3.topShadowColor,
+ d->w3.bottomShadowColor);
+ }
+ paintLabel(app, draw, d->label);
+ for (i = 0; i < d->indicator.count; i++) {
+ paintIndicator(app, draw, d->indicators[i]);
+ }
+ paintButton(app, draw, d->okButton);
+ paintButton(app, draw, d->cancelButton);
+ XSync(app->dpy, False);
+}
+
+void performGrab(AppInfo *app, int grabType, char *grabTypeName,
+ Bool shouldGrab, Bool *isGrabbed) {
+ if ((!(shouldGrab)) || (*isGrabbed)) {
+ return;
+ } else if ((GRAB_KEYBOARD != grabType) && (GRAB_POINTER != grabType)) {
+ fprintf(stderr, "%s[%ld]: performGrab: invalid grab type (%d).\n",
+ app->appName, (long) app->pid, grabType);
+ return;
+ } else {
+ int status = GrabInvalidTime; /* keep gcc -Wall from complaining */
+ unsigned int seconds = 0;
+ int helpful_message = 0;
+ /* keyboard and pointer */
+ Window grabWindow = app->dialog->dialogWindow;
+ Bool ownerEvents = False;
+ Bool pointerMode = GrabModeAsync;
+ Bool keyboardMode = GrabModeAsync;
+ /* pointer only */
+ unsigned int eventMask = ButtonPressMask | ButtonReleaseMask;
+ Window confineTo = None;
+ Cursor cursor = None;
+
+ *isGrabbed = True;
+
+ if (NULL == grabTypeName) {
+ fprintf(stderr, "%s[%ld]: performGrab: null grab type name.\n",
+ app->appName, (long) app->pid);
+ }
+
+ if (0 == app->grabFailTimeout) {
+ /* Ensure we try to perform the grab at least once. */
+ app->grabFailTimeout = 1;
+ }
+ while (seconds < app->grabFailTimeout) {
+ XSync(app->dpy, False);
+ switch (grabType) {
+ case GRAB_KEYBOARD:
+ status = XGrabKeyboard(app->dpy, grabWindow, ownerEvents,
+ pointerMode, keyboardMode, CurrentTime);
+ break;
+ case GRAB_POINTER:
+ status = XGrabPointer(app->dpy, grabWindow, ownerEvents,
+ eventMask, pointerMode, keyboardMode,
+ confineTo, cursor, CurrentTime);
+ break;
+ }
+ XSync(app->dpy, False);
+ if (GrabSuccess == status) {
+ if (helpful_message) {
+ fprintf(stderr, "%s[%ld]: Got %s.\n",
+ app->appName, (long) app->pid, grabTypeName);
+ }
+ break;
+ }
+ if (!helpful_message) {
+ fprintf(stderr, "%s[%ld]: Trying to grab %s ...\n",
+ app->appName, (long) app->pid, grabTypeName);
+ helpful_message = 1;
+ }
+ seconds += app->grabRetryInterval;
+ sleep(app->grabRetryInterval);
+ }
+ if (GrabSuccess != status) {
+ char *reason = "reason unknown";
+
+ switch (status) {
+ case AlreadyGrabbed:
+ reason = "someone else already has it";
+ break;
+ case GrabFrozen:
+ reason = "someone else has frozen it";
+ break;
+ case GrabInvalidTime:
+ reason = "bad grab time [this shouldn't happen]";
+ break;
+ case GrabNotViewable:
+ reason = "grab not viewable [this shouldn't happen]";
+ break;
+ }
+ fprintf(stderr, "%s[%ld]: Could not grab %s (%s)\n",
+ app->appName, (long) app->pid, grabTypeName, reason);
+ exitApp(app, EXIT_STATUS_ERROR);
+ }
+ }
+}
+
+
+void grabKeyboard(AppInfo *app)
+{
+ performGrab(app, GRAB_KEYBOARD, "keyboard", app->grabKeyboard,
+ &(app->isKeyboardGrabbed));
+}
+
+void ungrabKeyboard(AppInfo *app)
+{
+ if (app->grabKeyboard) {
+ XUngrabKeyboard(app->dpy, CurrentTime);
+ }
+}
+
+void grabPointer(AppInfo *app)
+{
+ performGrab(app, GRAB_POINTER, "pointer", app->grabPointer,
+ &(app->isPointerGrabbed));
+}
+
+void ungrabPointer(AppInfo *app)
+{
+ if (app->grabPointer) {
+ XUngrabPointer(app->dpy, CurrentTime);
+ }
+}
+
+void grabServer(AppInfo *app)
+{
+ if ((!(app->grabServer)) || (app->isServerGrabbed)) {
+ return;
+ } else {
+ app->isServerGrabbed = True;
+ XSync(app->dpy, False);
+ XGrabServer(app->dpy);
+ XSync(app->dpy, False);
+ }
+}
+
+void ungrabServer(AppInfo *app)
+{
+ if (app->grabServer) {
+ XUngrabServer(app->dpy);
+ }
+}
+
+void cleanUp(AppInfo *app)
+{
+ cancelInputTimeout(app);
+ XDestroyWindow(app->dpy, app->dialog->dialogWindow);
+ destroyGCs(app);
+ destroyDialog(app);
+ if (app->buf) {
+ memset(app->buf, 0, app->bufSize);
+ }
+ freeIf(app->buf);
+ ungrabPointer(app);
+ ungrabKeyboard(app);
+ ungrabServer(app);
+}
+
+void exitApp(AppInfo *app, int exitCode)
+{
+ cleanUp(app);
+ exit(exitCode);
+}
+
+void acceptAction(AppInfo *app)
+{
+ int status = append_to_buf(&(app->buf), &(app->bufSize),
+ &(app->bufIndex), '\0');
+ if (APPEND_FAILURE == status) {
+ cleanUp(app);
+ outOfMemory(app, __LINE__);
+ }
+ fputs(app->buf, stdout);
+ fputc('\n', stdout);
+ exitApp(app, EXIT_STATUS_ACCEPT);
+}
+
+void cancelAction(AppInfo *app)
+{
+ exitApp(app, EXIT_STATUS_CANCEL);
+}
+
+void backspacePassphrase(AppInfo *app)
+{
+ if (0 >= app->bufIndex) {
+ XBell(app->dpy, 0);
+ return;
+ }
+ (app->bufIndex)--;
+ updateIndicators(app, -1);
+}
+
+void erasePassphrase(AppInfo *app)
+{
+ if (0 >= app->bufIndex) {
+ XBell(app->dpy, 0);
+ return;
+ }
+ updateIndicators(app, 0);
+ app->bufIndex = 0;
+}
+
+void addToPassphrase(AppInfo *app, char c)
+{
+ int status = append_to_buf(&(app->buf), &(app->bufSize),
+ &(app->bufIndex), c);
+ if (APPEND_FAILURE == status) {
+ cleanUp(app);
+ outOfMemory(app, __LINE__);
+ }
+ updateIndicators(app, 1);
+}
+
+void handleKeyPress(AppInfo *app, XEvent *event)
+{
+ char s[2];
+ int n;
+
+ if (event->xkey.send_event) {
+ /* Pay no attention to synthetic key events. */
+ return;
+ }
+ cancelInputTimeout(app);
+ n = XLookupString(&(event->xkey), s, 1, NULL, NULL);
+
+ if (1 != n) {
+ return;
+ }
+ s[1] = '\0';
+ switch (s[0]) {
+ case '\010':
+ case '\177':
+ backspacePassphrase(app);
+ break;
+ case '\025':
+ case '\030':
+ erasePassphrase(app);
+ break;
+ case '\012':
+ case '\015':
+ acceptAction(app);
+ break;
+ case '\033':
+ cancelAction(app);
+ break;
+ default:
+ addToPassphrase(app, s[0]);
+ break;
+ }
+}
+
+Bool eventIsInsideButton(AppInfo *app, XEvent *event, ButtonInfo button)
+{
+ /* 'gcc -Wall' complains about 'app' being an unused parameter.
+ * Tough. We might want to use it later, and then we don't have
+ * to change it in each place it's called. Performance won't suffer.
+ */
+ int status = False;
+ int x, y;
+
+ switch(event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ x = event->xbutton.x;
+ y = event->xbutton.y;
+ break;
+ case MotionNotify:
+ x = event->xmotion.x;
+ y = event->xmotion.y;
+ break;
+ default:
+ return(False);
+ }
+ if ((x >= (button.w3.w.x + button.w3.borderWidth)) &&
+ (x < (button.w3.w.x + button.w3.w.width -
+ (2 * button.w3.borderWidth))) &&
+ (y >= (button.w3.w.y + button.w3.borderWidth)) &&
+ (y < (button.w3.w.y + button.w3.w.height -
+ (2 * button.w3.borderWidth)))) {
+ status = True;
+ }
+ return(status);
+}
+
+void handleButtonPress(AppInfo *app, XEvent *event)
+{
+ DialogInfo *d = app->dialog;
+
+ cancelInputTimeout(app);
+ if (event->xbutton.button != Button1) {
+ return;
+ }
+ if (ButtonPress == event->type) {
+ if (eventIsInsideButton(app, event, d->okButton)) {
+ d->pressedButton = OK_BUTTON;
+ d->okButton.pressed = True;
+ paintButton(app, d->dialogWindow, d->okButton);
+ } else if (eventIsInsideButton(app, event, d->cancelButton)) {
+ d->pressedButton = CANCEL_BUTTON;
+ d->cancelButton.pressed = True;
+ paintButton(app, d->dialogWindow, d->cancelButton);
+ } else {
+ d->pressedButton = NO_BUTTON;
+ }
+ } else if (ButtonRelease == event->type) {
+ if (OK_BUTTON == d->pressedButton) {
+ if (eventIsInsideButton(app, event, d->okButton)) {
+ acceptAction(app);
+ } else {
+ if (d->okButton.pressed) {
+ d->okButton.pressed = False;
+ paintButton(app, d->dialogWindow, d->okButton);
+ }
+ }
+ } else if (CANCEL_BUTTON == d->pressedButton) {
+ if (eventIsInsideButton(app, event, d->cancelButton)) {
+ cancelAction(app);
+ } else {
+ if (d->cancelButton.pressed) {
+ d->cancelButton.pressed = False;
+ paintButton(app, d->dialogWindow, d->cancelButton);
+ }
+ }
+ }
+ d->pressedButton = NO_BUTTON;
+ }
+}
+
+void handlePointerMotion(AppInfo *app, XEvent *event)
+{
+ DialogInfo *d = app->dialog;
+
+ if (NO_BUTTON == d->pressedButton) {
+ return;
+ } else if (OK_BUTTON == d->pressedButton) {
+ if (eventIsInsideButton(app, event, d->okButton)) {
+ if (!(d->okButton.pressed)) {
+ d->okButton.pressed = True;
+ paintButton(app, d->dialogWindow, d->okButton);
+ }
+ } else {
+ if (d->okButton.pressed) {
+ d->okButton.pressed = False;
+ paintButton(app, d->dialogWindow, d->okButton);
+ }
+ }
+ } else if (CANCEL_BUTTON == d->pressedButton) {
+ if (eventIsInsideButton(app, event, d->cancelButton)) {
+ if (!(d->cancelButton.pressed)) {
+ d->cancelButton.pressed = True;
+ paintButton(app, d->dialogWindow, d->cancelButton);
+ }
+ } else {
+ if (d->cancelButton.pressed) {
+ d->cancelButton.pressed = False;
+ paintButton(app, d->dialogWindow, d->cancelButton);
+ }
+ }
+ }
+}
+
+void handleInputTimeout(XtPointer data, XtIntervalId *timerId)
+{
+ /* 'gcc -Wall' complains about 'timerId' being an unused parameter.
+ * Tough. Xt forces us to have it here. Like it.
+ */
+ AppInfo *app = (AppInfo *) data;
+ if (app->inputTimeoutActive) {
+ app->inputTimeoutActive = False;
+ fprintf(stderr, "%s[%ld]: *Yawn*...timed out after %lu seconds.\n",
+ app->appName, (long) app->pid, (app->inputTimeout / 1000));
+ exitApp(app, EXIT_STATUS_TIMEOUT);
+ }
+}
+
+void cancelInputTimeout(AppInfo *app)
+{
+ if (app->inputTimeoutActive) {
+ app->inputTimeoutActive = False;
+ XtRemoveTimeOut(app->inputTimeoutTimerId);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ AppInfo app;
+ XEvent event;
+
+ memset(&app, 0, sizeof(app));
+
+ progclass = "SshAskpass";
+ app.toplevelShell = XtAppInitialize(&(app.appContext), progclass,
+ NULL, 0, &argc, argv,
+ defaults, NULL, 0);
+ app.argc = argc;
+ app.argv = argv;
+ app.dpy = XtDisplay(app.toplevelShell);
+ app.screen = DefaultScreenOfDisplay(app.dpy);
+ app.rootWindow = RootWindowOfScreen(app.screen);
+ app.black = BlackPixel(app.dpy, DefaultScreen(app.dpy));
+ app.white = WhitePixel(app.dpy, DefaultScreen(app.dpy));
+ app.colormap = DefaultColormapOfScreen(app.screen);
+ app.resourceDb = XtDatabase(app.dpy);
+ XtGetApplicationNameAndClass(app.dpy, &progname, &progclass);
+ app.appName = progname;
+ app.appClass = progclass;
+ /* For resources.c. */
+ db = app.resourceDb;
+
+ /* Seconds after which keyboard/pointer grab fail. */
+ app.grabFailTimeout = 5;
+ /* Number of seconds to wait between grab attempts. */
+ app.grabRetryInterval = 1;
+
+ app.pid = getpid();
+
+ {
+ struct rlimit resourceLimit;
+ int status;
+
+ status = getrlimit(RLIMIT_CORE, &resourceLimit);
+ if (-1 == status) {
+ fprintf(stderr, "%s[%ld]: getrlimit failed (%s)\n", app.appName,
+ (long) app.pid, strerror(errno));
+ exit(EXIT_STATUS_ERROR);
+ }
+ resourceLimit.rlim_cur = 0;
+ status = setrlimit(RLIMIT_CORE, &resourceLimit);
+ if (-1 == status) {
+ fprintf(stderr, "%s[%ld]: setrlimit failed (%s)\n", app.appName,
+ (long) app.pid, strerror(errno));
+ exit(EXIT_STATUS_ERROR);
+ }
+ }
+
+ app.xResolution =
+ WidthOfScreen(app.screen) * 1000 / WidthMMOfScreen(app.screen);
+ app.yResolution =
+ HeightOfScreen(app.screen) * 1000 / HeightMMOfScreen(app.screen);
+
+ createDialog(&app);
+ createGCs(&app);
+
+ app.eventMask = 0;
+ app.eventMask |= ExposureMask;
+ app.eventMask |= ButtonPressMask;
+ app.eventMask |= ButtonReleaseMask;
+ app.eventMask |= Button1MotionMask;
+ app.eventMask |= KeyPressMask;
+
+ createDialogWindow(&app);
+
+ XMapWindow(app.dpy, app.dialog->dialogWindow);
+ if (app.inputTimeout > 0) {
+ app.inputTimeoutActive = True;
+ app.inputTimeoutTimerId =
+ XtAppAddTimeOut(app.appContext, app.inputTimeout,
+ handleInputTimeout, (XtPointer) &app);
+ }
+
+
+ while(True) {
+ XtAppNextEvent(app.appContext, &event);
+ switch (event.type) {
+ case Expose:
+ grabServer(&app);
+ grabKeyboard(&app);
+ grabPointer(&app);
+ if (event.xexpose.count) {
+ break;
+ }
+ paintDialog(&app);
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ handleButtonPress(&app, &event);
+ break;
+ case MotionNotify:
+ handlePointerMotion(&app, &event);
+ case KeyPress:
+ handleKeyPress(&app, &event);
+ break;
+ case ClientMessage:
+ if ((32 == event.xclient.format) &&
+ ((unsigned long) event.xclient.data.l[0] ==
+ app.wmDeleteWindowAtom)) {
+ cancelAction(&app);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ fprintf(stderr, "%s[%ld]: This should not happen.\n", app.appName,
+ (long) app.pid);
+ return(EXIT_STATUS_ANOMALY);
+}
+