Add a GNOME3 pinentry based on gcr.
authorNeal H. Walfield <neal@gnu.org>
Tue, 12 May 2015 15:07:49 +0000 (17:07 +0200)
committerNeal H. Walfield <neal@gnu.org>
Tue, 12 May 2015 15:07:49 +0000 (17:07 +0200)
* configure.ac (--enable-pinentry-gnome3): Option to enable the GNOME3
pinentry.
(pinentry_gnome_3): Set to yes if enabled and gcr-3 and gcr-base-3 gcr
is available.
(GNOME3CFLAGS): Define and AC_SUBST.
(GNOME3LIBS): Define and AC_SUBST.
(GCR_API_SUBJECT_TO_CHANGE): Define.
(BUILD_PINENTRY_GNOME_3): Define.
* Makefile.am (pinentry_gnome_3): Define.
(SUBDIRS): Add ${pinentry_gnome_3}.
* gnome3/Makefile.am: New file.
* gnome3/pinentry-gnome3.c: New file.

Makefile.am
configure.ac
gnome3/Makefile.am [new file with mode: 0644]
gnome3/pinentry-gnome3.c [new file with mode: 0644]

index f8f7aac..177f37e 100644 (file)
@@ -1,5 +1,5 @@
 # Makefile.am
-# Copyright (C) 2002, 2012 g10 Code GmbH
+# Copyright (C) 2002, 2012, 2015 g10 Code GmbH
 #
 # This file is part of PINENTRY.
 #
@@ -46,6 +46,12 @@ else
 pinentry_gtk_2 =
 endif
 
+if BUILD_PINENTRY_GNOME_3
+pinentry_gnome_3 = gnome3
+else
+pinentry_gnome_3 =
+endif
+
 if BUILD_PINENTRY_QT4
 pinentry_qt4 = qt4
 else
@@ -59,7 +65,8 @@ pinentry_w32 =
 endif
 
 SUBDIRS = assuan secmem pinentry ${pinentry_curses} ${pinentry_tty} \
-         ${pinentry_gtk_2} ${pinentry_qt4} ${pinentry_w32} doc
+       ${pinentry_gtk_2} ${pinentry_gnome_3} ${pinentry_qt4} \
+       ${pinentry_w32} doc
 
 
 install-exec-local:
index c50ce68..9948d1f 100644 (file)
@@ -274,28 +274,34 @@ fi
 
 
 dnl
-dnl Check for GTK+-2 pinentry program.
+dnl Check for GTK+-2 / GNOME3 pinentry programs.
 dnl
 AC_ARG_ENABLE(pinentry-gtk2,
             AC_HELP_STRING([--enable-pinentry-gtk2], [build GTK+-2 pinentry]),
             pinentry_gtk_2=$enableval, pinentry_gtk_2=maybe)
 
+AC_ARG_ENABLE(pinentry-gnome3,
+            AC_HELP_STRING([--enable-pinentry-gnome3], [build GNOME 3 pinentry]),
+            pinentry_gnome_3=$enableval, pinentry_gnome_3=maybe)
+
 dnl check for pkg-config
-if test "$pinentry_gtk_2" != "no"; then
+if test "$pinentry_gtk_2" != "no" -o "$pinentry_gnome_3" != "no"; then
         AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
        if test x"${PKG_CONFIG}" = xno ; then
                pinentry_gtk_2=no
+               pinentry_gnome_3=no
        fi
 fi
 
 dnl check if the module gtk+-2.0 exists
-if test "$pinentry_gtk_2" != "no"; then
+if test "$pinentry_gtk_2" != "no" -o "$pinentry_gnome_3" != "no"; then
        AC_MSG_CHECKING([for gtk+-2])
        "${PKG_CONFIG}" --exists gtk+-2.0
        if test $? -ne 0 ; then
                AC_MSG_RESULT([no])
                AC_MSG_WARN([pkg-config could not find the module gtk+-2.0])
                pinentry_gtk_2=no
+               pinentry_gnome_3=no
        else
                AC_MSG_RESULT([yes])
                AC_MSG_CHECKING([gtk+-2 version >= 2.4.0])
@@ -305,17 +311,45 @@ if test "$pinentry_gtk_2" != "no"; then
                if test $? -ne 0 ; then
                        AC_MSG_WARN([building GTK+-2 pinentry disabled])
                        pinentry_gtk_2=no
+                       pinentry_gnome_3=no
                else
                        GTK2CFLAGS=`"${PKG_CONFIG}" --cflags gtk+-2.0`
                        GTK2LIBS=`"${PKG_CONFIG}" --libs gtk+-2.0`
                        AC_SUBST(GTK2CFLAGS)
                        AC_SUBST(GTK2LIBS)
-                       pinentry_gtk_2=yes
+                       if test "$pinentry_gtk_2" != "no"
+                       then
+                         pinentry_gtk_2=yes
+                       fi
+                       if test "$pinentry_gnome_3" != "no"
+                       then
+                         pinentry_gnome_3=yes
+                       fi
                fi
        fi
 fi
 AM_CONDITIONAL(BUILD_PINENTRY_GTK_2, test "$pinentry_gtk_2" = "yes")
 
+if test "$pinentry_gnome_3" != "no"; then
+       AC_MSG_CHECKING([for gcr])
+       "${PKG_CONFIG}" --exists gcr-3,gcr-base-3
+       if test $? -ne 0 ; then
+               AC_MSG_RESULT([no])
+               AC_MSG_WARN([pkg-config could not find the module gcr-3,gcr-base-3])
+               pinentry_gnome_3=no
+       else
+               AC_MSG_RESULT([yes])
+               GNOME3CFLAGS=`"${PKG_CONFIG}" --cflags gcr-3,gcr-base-3`
+               GNOME3LIBS=`"${PKG_CONFIG}" --libs gcr-3,gcr-base-3`
+               AC_SUBST(GNOME3CFLAGS)
+               AC_SUBST(GNOME3LIBS)
+               AC_DEFINE(GCR_API_SUBJECT_TO_CHANGE, 1, [Nod nod])
+               pinentry_gnome_3=yes
+       fi
+fi
+
+AM_CONDITIONAL(BUILD_PINENTRY_GNOME_3, test "$pinentry_gnome_3" = "yes")
+
 dnl
 dnl Check for libsecret.
 dnl
@@ -450,16 +484,20 @@ else
   if test "$pinentry_qt4" = "yes"; then
     PINENTRY_DEFAULT=pinentry-qt4
   else
-    if test "$pinentry_curses" = "yes"; then
-      PINENTRY_DEFAULT=pinentry-curses
+    if test "$pinentry_gnome_3" = "yes"; then
+      PINENTRY_DEFAULT=pinentry-gnome3
     else
-      if test "$pinentry_tty" = "yes"; then
-        PINENTRY_DEFAULT=pinentry-tty
+      if test "$pinentry_curses" = "yes"; then
+        PINENTRY_DEFAULT=pinentry-curses
       else
-        if test "$pinentry_w32" = "yes"; then
-          PINENTRY_DEFAULT=pinentry-w32
+        if test "$pinentry_tty" = "yes"; then
+          PINENTRY_DEFAULT=pinentry-tty
         else
-          AC_MSG_ERROR([[No pinentry enabled.]])
+          if test "$pinentry_w32" = "yes"; then
+            PINENTRY_DEFAULT=pinentry-w32
+          else
+            AC_MSG_ERROR([[No pinentry enabled.]])
+          fi
         fi
       fi
     fi
@@ -475,6 +513,7 @@ pinentry/Makefile
 curses/Makefile
 tty/Makefile
 gtk+-2/Makefile
+gnome3/Makefile
 qt4/Makefile
 w32/Makefile
 doc/Makefile
@@ -493,6 +532,7 @@ AC_MSG_NOTICE([
        Curses Pinentry ..: $pinentry_curses
        TTY Pinentry .....: $pinentry_tty
        GTK+-2 Pinentry ..: $pinentry_gtk_2
+       GNOME 3 Pinentry .: $pinentry_gnome_3
        Qt4 Pinentry .....: $pinentry_qt4 $pinentry_qt4_clip_msg
        W32 Pinentry .....: $pinentry_w32
 
diff --git a/gnome3/Makefile.am b/gnome3/Makefile.am
new file mode 100644 (file)
index 0000000..78df706
--- /dev/null
@@ -0,0 +1,39 @@
+# Makefile.am - PIN entry GTK+ frontend.
+# Copyright (C) 2002, 2015 g10 Code GmbH
+#
+# This file is part of PINENTRY.
+#
+# PINENTRY is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# PINENTRY is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+## Process this file with automake to produce Makefile.in
+
+bin_PROGRAMS = pinentry-gnome3
+
+if FALLBACK_CURSES
+ncurses_include = $(NCURSES_INCLUDE)
+libcurses = ../pinentry/libpinentry-curses.a $(LIBCURSES) $(LIBICONV)
+else
+ncurses_include =
+libcurses =
+endif
+
+AM_CPPFLAGS = $(COMMON_CFLAGS) $(GNOME3CFLAGS) \
+       $(ncurses_include) -I$(top_srcdir)/assuan \
+       -I$(top_srcdir)/secmem -I$(top_srcdir)/pinentry
+LDADD = $(COMMON_LIBS) \
+       ../pinentry/libpinentry.a ../assuan/libassuan.a ../secmem/libsecmem.a \
+       $(LIBCAP) $(GNOME3LIBS) $(libcurses)
+
+pinentry_gnome3_SOURCES = pinentry-gnome3.c
diff --git a/gnome3/pinentry-gnome3.c b/gnome3/pinentry-gnome3.c
new file mode 100644 (file)
index 0000000..74ec89c
--- /dev/null
@@ -0,0 +1,271 @@
+/* pinentry-gnome3.c
+   Copyright (C) 2015 g10 Code GmbH
+
+   pinentry-gnome-3 is a pinentry application for GNOME 3.  It tries
+   to follow the Gnome Human Interface Guide as close as possible.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+#include <gcr/gcr-base.h>
+
+#include <string.h>
+
+#include "assuan.h"
+
+#include "memory.h"
+
+#include "pinentry.h"
+
+#ifdef FALLBACK_CURSES
+#include "pinentry-curses.h"
+#endif
+
+\f
+#define PGMNAME "pinentry-gnome3"
+
+#ifndef VERSION
+#  define VERSION
+#endif
+
+static gchar *
+pinentry_utf8_validate (gchar *text)
+{
+  gchar *result;
+
+  if (!text)
+    return NULL;
+
+  if (g_utf8_validate (text, -1, NULL))
+    return g_strdup (text);
+
+  /* Failure: Assume that it was encoded in the current locale and
+     convert it to utf-8.  */
+  result = g_locale_to_utf8 (text, -1, NULL, NULL, NULL);
+  if (!result)
+    {
+      gchar *p;
+
+      result = p = g_strdup (text);
+      while (!g_utf8_validate (p, -1, (const gchar **) &p))
+       *p = '?';
+    }
+  return result;
+}
+
+static GcrPrompt *
+create_prompt (pinentry_t pe, int confirm)
+{
+  GcrPrompt *prompt;
+  GError *error = NULL;
+  char *msg;
+
+  /* Create the prompt.  */
+  prompt = GCR_PROMPT (gcr_system_prompt_open (-1, NULL, &error));
+  if (! prompt)
+    {
+      g_warning ("couldn't create prompt for gnupg passphrase: %s",
+                error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  /* Set the messages for the various buttons, etc.  */
+  if (pe->title)
+    {
+      msg = pinentry_utf8_validate (pe->title);
+      gcr_prompt_set_title (prompt, msg);
+      g_free (msg);
+    }
+
+  if (pe->description)
+    {
+      msg = pinentry_utf8_validate (pe->description);
+      gcr_prompt_set_description (prompt, msg);
+      g_free (msg);
+    }
+
+  /* An error occured during the last prompt.  */
+  if (pe->error)
+    {
+      msg = pinentry_utf8_validate (pe->error);
+      gcr_prompt_set_warning (prompt, msg);
+      g_free (msg);
+    }
+
+  if (! pe->prompt && confirm)
+    gcr_prompt_set_message (prompt, "Message");
+  else if (! pe->prompt && ! confirm)
+    gcr_prompt_set_message (prompt, "Enter Passphrase");
+  else
+    {
+      msg = pinentry_utf8_validate (pe->prompt);
+      gcr_prompt_set_message (prompt, msg);
+      g_free (msg);
+    }
+
+  if (! confirm)
+    gcr_prompt_set_password_new (prompt, !!pe->repeat_passphrase);
+
+  if (pe->ok || pe->default_ok)
+    {
+      msg = pinentry_utf8_validate (pe->ok ?: pe->default_ok);
+      gcr_prompt_set_continue_label (prompt, msg);
+      g_free (msg);
+    }
+  /* XXX: Disable this button if pe->one_button is set.  */
+  if (pe->cancel || pe->default_cancel)
+    {
+      msg = pinentry_utf8_validate (pe->cancel ?: pe->default_cancel);
+      gcr_prompt_set_cancel_label (prompt, msg);
+      g_free (msg);
+    }
+
+  if (confirm && pe->notok)
+    {
+      /* XXX: Add support for the third option.  */
+    }
+
+  /* XXX: gcr expects a string; we have a int.  */
+  // gcr_prompt_set_caller_window (prompt, pe->parent_wid);
+
+  if (! confirm && pe->allow_external_password_cache && pe->keyinfo)
+    {
+      if (pe->default_pwmngr)
+       {
+         msg = pinentry_utf8_validate (pe->default_pwmngr);
+         gcr_prompt_set_choice_label (prompt, msg);
+         g_free (msg);
+       }
+      else
+       gcr_prompt_set_choice_label
+         (prompt, "Automatically unlock this key, whenever I'm logged in");
+    }
+
+  return prompt;
+}
+
+static int
+gnome3_cmd_handler (pinentry_t pe)
+{
+  GcrPrompt *prompt = NULL;
+  GError *error = NULL;
+  int ret = -1;
+
+  if (pe->pin)
+    /* Passphrase mode.  */
+    {
+      const char *password;
+
+      prompt = create_prompt (pe, 0);
+      if (! prompt)
+       /* Something went wrong.  */
+       {
+         pe->canceled = 1;
+         return -1;
+       }
+
+      /* "The returned password is valid until the next time a method
+        is called to display another prompt."  */
+      password = gcr_prompt_password_run (prompt, NULL, &error);
+      if (error)
+       /* Error.  */
+       {
+         pe->specific_err = ASSUAN_General_Error;
+         g_error_free (error);
+         ret = -1;
+       }
+      else if (! password && ! error)
+       /* User cancelled the operation.  */
+       ret = -1;
+      else
+       {
+         pinentry_setbufferlen (pe, strlen (password) + 1);
+         if (pe->pin)
+           strcpy (pe->pin, password);
+
+         if (pe->repeat_passphrase)
+           pe->repeat_okay = 1;
+
+         ret = 1;
+       }
+    }
+  else
+    /* Message box mode.  */
+    {
+      GcrPromptReply reply;
+
+      prompt = create_prompt (pe, 1);
+      if (! prompt)
+       /* Something went wrong.  */
+       {
+         pe->canceled = 1;
+         return -1;
+       }
+
+      /* XXX: We don't support a third button!  */
+
+      reply = gcr_prompt_confirm_run (prompt, NULL, &error);
+      if (error)
+       {
+         pe->specific_err = ASSUAN_General_Error;
+         ret = 0;
+       }
+      else if (reply == GCR_PROMPT_REPLY_CONTINUE
+              /* XXX: Hack since gcr doesn't yet support one button
+                 message boxes treat cancel the same as okay.  */
+              || pe->one_button)
+       /* Confirmation.  */
+       ret = 1;
+      else
+       /* GCR_PROMPT_REPLY_CANCEL */
+       {
+         pe->canceled = 1;
+         ret = 0;
+       }
+    }
+
+  if (prompt)
+    g_clear_object (&prompt);
+  return ret;
+}
+
+pinentry_cmd_handler_t pinentry_cmd_handler = gnome3_cmd_handler;
+
+int
+main (int argc, char *argv[])
+{
+  pinentry_init (PGMNAME);
+
+#ifdef FALLBACK_CURSES
+  if (pinentry_have_display (argc, argv))
+    gtk_init (&argc, &argv);
+  else
+    pinentry_cmd_handler = curses_cmd_handler;
+#else
+  gtk_init (&argc, &argv);
+#endif
+
+  pinentry_parse_opts (argc, argv);
+
+  if (pinentry_loop ())
+    return 1;
+
+  return 0;
+}