[svn] gpgme - r1353 - in trunk: . src tests tests/opassuan

svn author wk cvs at cvs.gnupg.org
Mon Jan 26 11:21:11 CET 2009


Author: wk
Date: 2009-01-26 11:21:10 +0100 (Mon, 26 Jan 2009)
New Revision: 1353

Added:
   trunk/src/dirinfo.c
   trunk/src/engine-assuan.c
   trunk/src/opassuan.c
   trunk/tests/opassuan/
   trunk/tests/opassuan/Makefile.am
   trunk/tests/opassuan/t-command.c
Modified:
   trunk/ChangeLog
   trunk/Makefile.am
   trunk/NEWS
   trunk/autogen.sh
   trunk/configure.ac
   trunk/src/ChangeLog
   trunk/src/Makefile.am
   trunk/src/context.h
   trunk/src/engine-backend.h
   trunk/src/engine-gpg.c
   trunk/src/engine-gpgconf.c
   trunk/src/engine-gpgsm.c
   trunk/src/engine.c
   trunk/src/engine.h
   trunk/src/gpgme.c
   trunk/src/gpgme.def
   trunk/src/gpgme.h.in
   trunk/src/libgpgme.vers
   trunk/src/util.h
   trunk/src/version.c
   trunk/tests/ChangeLog
   trunk/tests/Makefile.am
Log:
First take on the low-level assuan interface.


[The diff below has been truncated]

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/ChangeLog	2009-01-26 10:21:10 UTC (rev 1353)
@@ -1,3 +1,7 @@
+2009-01-26  Werner Koch  <wk at g10code.com>
+
+	* configure.ac (AC_CONFIG_FILES): Add tests/opassuan/Makefile.
+
 2008-12-08  Marcus Brinkmann  <marcus at g10code.de>
 
 	Release GPGME 1.1.8.
@@ -720,8 +724,8 @@
 
 	* configure.ac (AC_INIT): Bump version to 0.3.3.
 	* jnlib/Makefile.am: Rever to older version that includes xmalloc
-	but not dotlock and some other files.  Reported by Stéphane
-	Corthésy.
+	but not dotlock and some other files.  Reported by Stéphane
+	Corthésy.
 	
 2002-02-10  Marcus Brinkmann  <marcus at g10code.de>
 

Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/ChangeLog	2009-01-26 10:21:10 UTC (rev 1353)
@@ -1,3 +1,36 @@
+2009-01-26  Werner Koch  <wk at g10code.com>
+
+	* opassuan.c, dirinfo.c, engine-assuan.c: New.
+	* Makefile.am:  Add them.
+	* engine-backend.h: Add _gpgme_engine_ops_assuan. 
+	(struct engine_ops): Add field OPASSUAN_TRANSACT.  Update all
+	engine intializers.
+	* Makefile.am (gpgsm_components): Add engine-assuan.c.
+	* gpgme.h.in (gpgme_protocol_t): Add GPGME_PROTOCOL_ASSUAN.
+	(gpgme_assuan_data_cb_t, gpgme_assuan_sendfnc_ctx_t)
+	(gpgme_assuan_inquire_cb_t, gpgme_assuan_status_cb_t): New.
+	(gpgme_op_assuan_transact_start, gpgme_op_assuan_transact): New.
+	* gpgme.c (gpgme_get_protocol_name): Ditto.
+	(gpgme_set_protocol): Support it.
+	* engine.c (gpgme_get_engine_info): Ditto.
+	(engine_ops): Register it.
+	(_gpgme_engine_op_assuan_transact): New.
+	* libgpgme.vers (gpgme_op_assuan_transact_start)
+	(gpgme_op_assuan_transact): New.
+	* gpgme.def (gpgme_op_assuan_transact_start)
+	(gpgme_op_assuan_transact): New.
+	* engine-backend.h (struct engine_ops): Add GET_HOME_DIR and
+	initialize to NULL for all engines.
+	* engine.c (engine_get_home_dir): New.
+	(gpgme_get_engine_info): Use it.
+	(_gpgme_set_engine_info): Use it.
+	* engine.h (engine_assuan_result_cb_t): New.
+	* context.h (ctx_op_data_id_t): Add OPDATA_ASSUAN.
+
+	* util.h (GPG_ERR_UNFINISHED): Define if not yet defined.
+
+	* version.c (gpgme_check_version): Protect trace arg against NULL.
+
 2009-01-19  Werner Koch  <wk at g10code.com>
 
 	* rungpg.c: Rename to engine-gpg.c
@@ -803,7 +836,7 @@
 
 	* engine.c (gpgme_engine_check_version): Reimplemented to allow
 	checking the version correctly even after changing the engine
-	information.  Bug reported by Stéphane Corthésy.
+	information.  Bug reported by Stéphane Corthésy.
 
 	* rungpg.c (read_colon_line): Invoke colon preprocess handler if
 	it is set.
@@ -868,7 +901,7 @@
 2005-11-27  Marcus Brinkmann  <marcus at g10code.de>
 
 	* engine.c (_gpgme_set_engine_info): Use new_file_name in
-	engine_get_version invocation.  Reported by Stéphane Corthésy.
+	engine_get_version invocation.  Reported by Stéphane Corthésy.
 
 2005-11-24  Marcus Brinkmann  <marcus at g10code.de>
 
@@ -1818,7 +1851,7 @@
 
 	* gpgme-config.in (gpg_error_libs): Quote GPG_ERROR_CFLAGS and
 	GPG_ERROR_LIBS when setting the corresponding variables.
-	Reported by Stéphane Corthésy.
+	Reported by Stéphane Corthésy.
 
 2003-07-22  Marcus Brinkmann  <marcus at g10code.de>
 
@@ -3707,7 +3740,7 @@
 2002-09-28  Marcus Brinkmann  <marcus at g10code.de>
 
 	* conversion.c (_gpgme_hextobyte): Prevent superfluous
-	multiplication with base.  Reported by Stéphane Corthésy.
+	multiplication with base.  Reported by Stéphane Corthésy.
 
 	* keylist.c (gpgme_op_keylist_ext_start): Use private asynchronous
 	operation type in invocation of _gpgme_op_reset.
@@ -3820,7 +3853,7 @@
 	variables encrypt_info and encrypt_info_len.
 	* trustlist.c (gpgme_op_trustlist_start): Set colon line handler.
 	* posix-sema.c (sema_fatal): Remove function.
-	All these reported by Stéphane Corthésy.
+	All these reported by Stéphane Corthésy.
 
 2002-08-23  Werner Koch  <wk at gnupg.org>
 
@@ -3993,7 +4026,7 @@
 	* vasprintf.c: Update to more recent libiberty version.
 	* debug.h: Replace #elsif with #elif.
 
-	Submitted by Stéphane Corthésy:
+	Submitted by Stéphane Corthésy:
 	* util.h (vasprintf): Correct prototype.
 	* encrypt-sign.c: Include <stddef.h>.
 	(encrypt_sign_status_handler): Change type of ENCRYPT_INFO_LEN to
@@ -4003,14 +4036,14 @@
 
 2002-07-25  Marcus Brinkmann  <marcus at g10code.de>
 
-	* wait.c (fdt_global): Make static.  Reported by Stéphane
-	Corthésy.
+	* wait.c (fdt_global): Make static.  Reported by Stéphane
+	Corthésy.
 
 	* rungpg.c (_gpgme_gpg_op_keylist_ext): Skip empty string
-	patterns.  Reported by Stéphane Corthésy.
+	patterns.  Reported by Stéphane Corthésy.
 
 	* key.c (gpgme_key_get_as_xml): Add OTRUST attribute.  Requested
-	by Stéphane Corthésy.
+	by Stéphane Corthésy.
 	(gpgme_key_get_string_attr): Add GPGME_ATTR_SIG_SUMMARY case to
 	silence gcc warning.
 
@@ -5060,7 +5093,7 @@
 
 2001-12-19  Marcus Brinkmann  <marcus at g10code.de>
 
-	* engine.c: Include `string.h'.  Reported by Stéphane Corthésy.
+	* engine.c: Include `string.h'.  Reported by Stéphane Corthésy.
 
 	* version.c (get_engine_info): Remove prototype.
 
@@ -5597,7 +5630,7 @@
 	callers to use this function without a check for tmp_key.
 	
 	* keylist.c (gpgme_op_keylist_next): Reset the key_cond after
-	emptying the queue.  Bug reported by Stéphane Corthésy.
+	emptying the queue.  Bug reported by Stéphane Corthésy.
 
 2001-09-12  Werner Koch  <wk at gnupg.org>
 
@@ -5679,7 +5712,7 @@
 	* version.c (gpgme_check_engine): Stop version number parsing at
 	the opening angle and not the closing one.  By Tommy Reynolds.
 
-2001-05-01  José Carlos García Sogo <jose at jaimedelamo.eu.org>
+2001-05-01  José Carlos García Sogo <jose at jaimedelamo.eu.org>
 
 	* encrypt.c (gpgme_op_encrypt_start): Deleted the assert ( !c->gpg )
 	line, because it gave an error if another operation had been made 
@@ -5865,8 +5898,8 @@
 	* rungpg.c (_gpgme_gpg_spawn): Use new function to get GPG's path.
 
 	* signers.c (gpgme_signers_add): Ooops, one should test code and
-	not just write it; the newarr was not assigned.  Thanks to José
-	for pointing this out.  Hmmm, still not tested, why shoudl a coder
+	not just write it; the newarr was not assigned.  Thanks to José
+	for pointing this out.  Hmmm, still not tested, why should a coder
 	test his fix :-)
 
 	* w32-io.c: Does now use reader threads, so that we can use

Modified: trunk/tests/ChangeLog
===================================================================
--- trunk/tests/ChangeLog	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/tests/ChangeLog	2009-01-26 10:21:10 UTC (rev 1353)
@@ -1,3 +1,9 @@
+2009-01-26  Werner Koch  <wk at g10code.com>
+
+	* opassuan/: New.
+	* opassuan/Makefile.am: New.
+	* opassuan/t-command.c: New.
+
 2008-12-03  Marcus Brinkmann  <marcus at g10code.de>
 
 	* Makefile.am (INCLUDES): Fix path to include file.

Modified: trunk/Makefile.am
===================================================================
--- trunk/Makefile.am	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/Makefile.am	2009-01-26 10:21:10 UTC (rev 1353)
@@ -15,8 +15,7 @@
 # Public License for more details.
 # 
 # You should have received a copy of the GNU Lesser 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
+# License along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 ## Process this file with automake to produce Makefile.in
 

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/NEWS	2009-01-26 10:21:10 UTC (rev 1353)
@@ -1,3 +1,19 @@
+Noteworthy changes in version 1.1.9
+------------------------------------------------
+
+ * Interface changes relative to the 1.1.7 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ GPGME_PROTOCOL_ASSUAN          NEW.
+ gpgme_assuan_data_cb_t         NEW.
+ gpgme_assuan_sendfnc_ctx_t     NEW.
+ gpgme_assuan_inquire_cb_t      NEW.
+ gpgme_assuan_status_cb_t       NEW.
+ gpgme_op_assuan_transact_start NEW.
+ gpgme_op_assuan_transact       NEW.
+ gpgme_op_assuan_result         NEW.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
 Noteworthy changes in version 1.1.8 (2008-12-08)
 ------------------------------------------------
 

Modified: trunk/autogen.sh
===================================================================
--- trunk/autogen.sh	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/autogen.sh	2009-01-26 10:21:10 UTC (rev 1353)
@@ -159,4 +159,6 @@
 echo "Running autoconf${FORCE} ..."
 $AUTOCONF${FORCE}
 
-echo "You may now run \"./configure --enable-maintainer-mode && make\"."
+echo "You may now run:
+  ./configure --enable-maintainer-mode && make
+"

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/configure.ac	2009-01-26 10:21:10 UTC (rev 1353)
@@ -31,8 +31,8 @@
 # specific feature can already be done under the assumption that the
 # SVN version is the most recent one in a branch.  To disable the SVN
 # version for the real release, set the my_issvn macro to no.
-m4_define(my_version, [1.1.8])
-m4_define(my_issvn, [no])
+m4_define(my_version, [1.1.9])
+m4_define(my_issvn, [yes])
 
 m4_define([svn_revision], m4_esyscmd([echo -n $( (svn info 2>/dev/null \
             || echo 'Revision: 0')|sed -n '/^Revision:/ {s/[^0-9]//gp;q;}')]))
@@ -744,7 +744,10 @@
 # Create config files 
 
 AC_CONFIG_FILES(Makefile assuan/Makefile src/Makefile
-		tests/Makefile tests/gpg/Makefile tests/gpgsm/Makefile
+		tests/Makefile 
+                tests/gpg/Makefile
+                tests/gpgsm/Makefile
+                tests/opassuan/Makefile
 		doc/Makefile complus/Makefile
                 src/versioninfo.rc
                 src/gpgme.h)

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/Makefile.am	2009-01-26 10:21:10 UTC (rev 1353)
@@ -78,7 +78,7 @@
 endif
 
 if HAVE_GPGSM
-gpgsm_components = engine-gpgsm.c
+gpgsm_components = engine-gpgsm.c engine-assuan.c
 else
 gpgsm_components =
 endif
@@ -105,9 +105,10 @@
 	sign.c passphrase.c progress.c					\
 	key.c keylist.c trust-item.c trustlist.c			\
 	import.c export.c genkey.c delete.c edit.c getauditlog.c        \
+	opassuan.c                                                      \
 	engine.h engine-backend.h engine.c engine-gpg.c status-table.h	\
 	$(gpgsm_components) $(gpgconf_components) gpgconf.c		\
-	sema.h priv-io.h $(system_components)				\
+	sema.h priv-io.h $(system_components) dirinfo.c			\
 	debug.c debug.h gpgme.c version.c error.c
 
 libgpgme_la_SOURCES = $(main_sources)					\

Modified: trunk/src/context.h
===================================================================
--- trunk/src/context.h	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/context.h	2009-01-26 10:21:10 UTC (rev 1353)
@@ -36,7 +36,7 @@
   {
     OPDATA_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE,
     OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
-    OPDATA_VERIFY, OPDATA_TRUSTLIST
+    OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN
   } ctx_op_data_id_t;
 
 
@@ -51,7 +51,7 @@
   ctx_op_data_id_t type;
 
   /* The function to release HOOK and all its associated resources.
-     Can be NULL if no special dealllocation routine is necessary.  */
+     Can be NULL if no special deallocation routine is necessary.  */
   void (*cleanup) (void *hook);
 
   /* The hook that points to the operation data.  */

Added: trunk/src/dirinfo.c
===================================================================
--- trunk/src/dirinfo.c	                        (rev 0)
+++ trunk/src/dirinfo.c	2009-01-26 10:21:10 UTC (rev 1353)
@@ -0,0 +1,189 @@
+/* dirinfo.c - Get directory information
+ * Copyright (C) 2009 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * GPGME 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "priv-io.h"
+#include "debug.h"
+#include "sema.h"
+
+DEFINE_STATIC_LOCK (dirinfo_lock);
+
+/* Constants used internally to select the data.  */
+enum 
+  {
+    WANT_HOMEDIR,
+    WANT_AGENT_SOCKET
+  };
+
+/* Values retrieved via gpgconf and cached here.  */
+static struct {
+  int  valid;         /* Cached information is valid.  */
+  char *homedir;
+  char *agent_socket;
+} dirinfo;
+
+
+/* Parse the output of "gpgconf --list-dirs".  This function expects
+   that DIRINFO_LOCK is held by the caller.  */
+static void
+parse_output (char *line)
+{
+  char *value, *p;
+
+  value = strchr (line, ':');
+  if (!value)
+    return;
+  *value++ = 0;
+  p = strchr (value, ':');
+  if (p)
+    *p = 0;
+  if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0))
+    return;
+  if (!*value)
+    return;
+  
+  if (!strcmp (line, "homedir") && !dirinfo.homedir)
+    dirinfo.homedir = strdup (value);
+  else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
+    dirinfo.agent_socket = strdup (value);
+}
+
+
+/* Read the directory information from gpgconf.  This function expects
+   that DIRINFO_LOCK is held by the caller.  */
+static void
+read_gpgconf_dirs (void) 
+{
+  const char *pgmname;
+  char linebuf[1024] = {0};
+  int linelen = 0;
+  char * argv[3];
+  int rp[2];
+  struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
+				   {-1, -1} };
+  int status;
+  int nread;
+  char *mark = NULL;
+
+  pgmname = _gpgme_get_gpgconf_path ();
+  if (!pgmname)
+    return;  /* No way.  */
+
+  argv[0] = (char *)pgmname;
+  argv[1] = "--list-dirs";
+  argv[2] = NULL;
+
+  if (_gpgme_io_pipe (rp, 1) < 0)
+    return;
+
+  cfd[0].fd = rp[1];
+
+  status = _gpgme_io_spawn (pgmname, argv, cfd, NULL);
+  if (status < 0)
+    {
+      _gpgme_io_close (rp[0]);
+      _gpgme_io_close (rp[1]);
+      return;
+    }
+
+  do
+    {
+      nread = _gpgme_io_read (rp[0], 
+                              linebuf + linelen, 
+                              sizeof linebuf - linelen - 1);
+      if (nread > 0)
+	{
+          char *line;
+          const char *lastmark = NULL;
+          size_t nused;
+
+	  linelen += nread;
+	  linebuf[linelen] = '\0';
+
+	  for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
+	    {
+              lastmark = mark;
+	      if (mark > line && mark[-1] == '\r')
+		mark[-1] = '\0';
+              else
+                mark[0] = '\0';
+
+              parse_output (line);
+	    }
+
+          nused = lastmark? (lastmark + 1 - linebuf) : 0;
+          memmove (linebuf, linebuf + nused, linelen - nused);
+          linelen -= nused;
+	}
+    }
+  while (nread > 0 && linelen < sizeof linebuf - 1);
+  
+  _gpgme_io_close (rp[0]);
+}
+
+
+static const char *
+get_gpgconf_dir (int what)
+{
+  const char *result = NULL;
+
+  LOCK (dirinfo_lock);
+  if (!dirinfo.valid)
+    {
+      read_gpgconf_dirs ();
+      /* Even if the reading of the directories failed (e.g. due to an
+         too old version gpgconf or no gpgconf at all), we need to
+         mark the entries as valid so that we won't try over and over
+         to read them.  Note further that we are not able to change
+         the read values later because they are practically statically
+         allocated.  */
+      dirinfo.valid = 1;
+    }
+  switch (what)
+    {
+    case WANT_HOMEDIR: result = dirinfo.homedir; break;
+    case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
+    }
+  UNLOCK (dirinfo_lock);
+  return result;
+}
+
+
+/* Return the default home directory.   Returns NULL if not known.  */
+const char *
+_gpgme_get_default_homedir (void)
+{
+  return get_gpgconf_dir (WANT_HOMEDIR);
+}
+
+/* Return the default gpg-agent socket name.  Returns NULL if not known.  */
+const char *
+_gpgme_get_default_agent_socket (void)
+{
+  return get_gpgconf_dir (WANT_AGENT_SOCKET);
+}
+

Added: trunk/src/engine-assuan.c
===================================================================
--- trunk/src/engine-assuan.c	                        (rev 0)
+++ trunk/src/engine-assuan.c	2009-01-26 10:21:10 UTC (rev 1353)
@@ -0,0 +1,744 @@
+/* engine-assuan.c - Low-level Assuan protocol engine
+ * Copyright (C) 2009 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+   Note: This engine requires a modern Assuan server which uses
+   gpg-error codes.  In particular there is no backward compatible
+   mapping of old Assuan error codes implemented.
+*/
+
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <unistd.h>
+#include <locale.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "ops.h"
+#include "wait.h"
+#include "priv-io.h"
+#include "sema.h"
+
+#include "assuan.h"
+#include "debug.h"
+
+#include "engine-backend.h"
+
+
+typedef struct
+{
+  int fd;	/* FD we talk about.  */
+  int server_fd;/* Server FD for this connection.  */
+  int dir;	/* Inbound/Outbound, maybe given implicit?  */
+  void *data;	/* Handler-specific data.  */
+  void *tag;	/* ID from the user for gpgme_remove_io_callback.  */
+} iocb_data_t;
+
+/* Engine instance data.  */
+struct engine_llass
+{
+  assuan_context_t assuan_ctx;
+
+  int lc_ctype_set;
+  int lc_messages_set;
+
+  iocb_data_t status_cb;
+
+  struct gpgme_io_cbs io_cbs;
+
+  /* Internal callbacks.  */
+  engine_assuan_result_cb_t result_cb;
+  void *result_cb_value; 
+
+  /* User provided callbacks.  */
+  struct {
+    gpgme_assuan_data_cb_t data_cb;
+    void *data_cb_value;
+
+    gpgme_assuan_inquire_cb_t inq_cb;
+    void *inq_cb_value;
+
+    gpgme_assuan_status_cb_t status_cb;
+    void *status_cb_value;
+  } user;
+
+  /* Option flags.  */
+  struct {
+    int gpg_agent:1;  /* Assume this is a gpg-agent connection.  */
+  } opt;
+
+};
+typedef struct engine_llass *engine_llass_t;
+
+/* Helper to pass data to a callback.  */
+struct _gpgme_assuan_sendfnc_ctx
+{
+  assuan_context_t assuan_ctx;
+};
+
+
+
+/* Prototypes.  */
+static void llass_io_event (void *engine,
+                            gpgme_event_io_t type, void *type_data);
+
+
+
+
+
+/* return the default home directory.  */
+static const char *
+llass_get_home_dir (void)
+{
+  /* For this engine the home directory is not a filename but a string
+     used to convey options.  The exclamation mark is a marker to show
+     that this is not a directory name. Options are strings delimited
+     by a space.  The only option defined for now is GPG_AGENT to
+     enable GPG_AGENT specific commands to send to the server at
+     connection startup.  */
+  return "!GPG_AGENT";
+}
+
+static char *
+llass_get_version (const char *file_name)
+{
+  return strdup ("1.0");
+}
+
+
+static const char *
+llass_get_req_version (void)
+{
+  return "1.0";
+}
+
+
+static void
+close_notify_handler (int fd, void *opaque)
+{
+  engine_llass_t llass = opaque;
+
+  assert (fd != -1);
+  if (llass->status_cb.fd == fd)
+    {
+      if (llass->status_cb.tag)
+	llass->io_cbs.remove (llass->status_cb.tag);
+      llass->status_cb.fd = -1;
+      llass->status_cb.tag = NULL;
+    }
+}
+
+
+
+static gpgme_error_t
+llass_cancel (void *engine)
+{
+  engine_llass_t llass = engine;
+
+  if (!llass)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (llass->status_cb.fd != -1)
+    _gpgme_io_close (llass->status_cb.fd);
+
+  if (llass->assuan_ctx)
+    {
+      assuan_disconnect (llass->assuan_ctx);
+      llass->assuan_ctx = NULL;
+    }
+
+  return 0;
+}
+
+
+static void
+llass_release (void *engine)
+{
+  engine_llass_t llass = engine;
+
+  if (!llass)
+    return;
+
+  llass_cancel (engine);
+
+  free (llass);
+}
+
+
+/* Create a new instance. If HOME_DIR is NULL standard options for use
+   with gpg-agent are issued.  */  
+static gpgme_error_t
+llass_new (void **engine, const char *file_name, const char *home_dir)
+{
+  gpgme_error_t err = 0;
+  engine_llass_t llass;
+  char *optstr;
+
+  llass = calloc (1, sizeof *llass);
+  if (!llass)
+    return gpg_error_from_syserror ();
+
+  llass->status_cb.fd = -1;
+  llass->status_cb.dir = 1;
+  llass->status_cb.tag = 0;
+  llass->status_cb.data = llass;
+
+  /* Parse_options.  */
+  if (home_dir && *home_dir == '!')
+    {
+      home_dir++;
+      /* Very simple parser only working for the one option we support.  */
+      if (!strncmp (home_dir, "GPG_AGENT", 9) 
+          && (!home_dir[9] || home_dir[9] == ' '))
+        llass->opt.gpg_agent = 1;
+    }
+
+  err = assuan_socket_connect (&llass->assuan_ctx, file_name, 0);
+  if (err)
+    goto leave;
+
+  if (llass->opt.gpg_agent)
+    {
+      char *dft_display = NULL;
+
+      err = _gpgme_getenv ("DISPLAY", &dft_display);
+      if (err)
+        goto leave;
+      if (dft_display)
+        {
+          if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
+            {
+              err = gpg_error_from_syserror ();
+              free (dft_display);
+              goto leave;
+            }
+          free (dft_display);
+
+          err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL, NULL,
+                                 NULL, NULL, NULL);
+          free (optstr);
+          if (err)
+            goto leave;
+        }
+    }
+
+  if (llass->opt.gpg_agent && isatty (1))
+    {
+      int rc;
+      char dft_ttyname[64];
+      char *dft_ttytype = NULL;
+
+      rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+      if (rc)
+	{
+	  err = gpg_error_from_errno (rc);
+	  goto leave;
+	}
+      else
+	{
+	  if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
+	    {
+	      err = gpg_error_from_syserror ();
+	      goto leave;
+	    }
+	  err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL, NULL,
+				 NULL, NULL, NULL);
+	  free (optstr);
+	  if (err)
+            goto leave;
+
+	  err = _gpgme_getenv ("TERM", &dft_ttytype);
+	  if (err)
+	    goto leave;
+	  if (dft_ttytype)
+	    {
+	      if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
+		{
+		  err = gpg_error_from_syserror ();
+		  free (dft_ttytype);
+		  goto leave;
+		}
+	      free (dft_ttytype);
+              
+	      err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL,
+				     NULL, NULL, NULL, NULL);
+	      free (optstr);
+	      if (err)
+                goto leave;
+	    }
+	}
+    }
+
+
+#ifdef HAVE_W32_SYSTEM
+  /* Under Windows we need to use AllowSetForegroundWindow.  Tell
+     llass to tell us when it needs it.  */
+  if (!err && llass->opt.gpg_agent)
+    {
+      err = assuan_transact (llass->assuan_ctx, "OPTION allow-pinentry-notify",
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
+        err = 0; /* This work only with recent gpg-agents.  */
+    }
+#endif /*HAVE_W32_SYSTEM*/
+
+
+ leave:
+  /* Close the server ends of the pipes (because of this, we must use
+     the stored server_fd_str in the function start).  Our ends are
+     closed in llass_release().  */
+
+  if (err)
+    llass_release (llass);
+  else
+    *engine = llass;
+
+  return err;
+}
+
+
+static gpgme_error_t
+llass_set_locale (void *engine, int category, const char *value)
+{
+  gpgme_error_t err;
+  engine_llass_t llass = engine;
+  char *optstr;
+  char *catstr;
+
+  if (!llass->opt.gpg_agent)
+    return 0;
+
+  /* FIXME: If value is NULL, we need to reset the option to default.
+     But we can't do this.  So we error out here.  gpg-agent needs
+     support for this.  */
+  if (category == LC_CTYPE)
+    {
+      catstr = "lc-ctype";
+      if (!value && llass->lc_ctype_set)
+	return gpg_error (GPG_ERR_INV_VALUE);
+      if (value)
+	llass->lc_ctype_set = 1;
+    }
+#ifdef LC_MESSAGES
+  else if (category == LC_MESSAGES)
+    {
+      catstr = "lc-messages";
+      if (!value && llass->lc_messages_set)
+	return gpg_error (GPG_ERR_INV_VALUE);
+      if (value)
+	llass->lc_messages_set = 1;
+    }
+#endif /* LC_MESSAGES */
+  else
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* FIXME: Reset value to default.  */
+  if (!value)
+    return 0;
+
+  if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
+    err = gpg_error_from_errno (errno);
+  else
+    {
+      err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL,
+			     NULL, NULL, NULL, NULL);
+      free (optstr);
+    }
+  return err;
+}
+
+
+
+static gpgme_error_t
+inquire_cb_sendfnc (gpgme_assuan_sendfnc_ctx_t ctx,
+                    const void *data, size_t datalen)
+{
+  if (data && datalen)
+    return assuan_send_data (ctx->assuan_ctx, data, datalen);
+  else
+    return 0;  /* Don't allow an inquire to send a flush.  */
+}
+
+
+/* This is the inquiry callback.  It handles stuff which ee need to
+   handle here and passes everything on to the user callback.  */
+static gpgme_error_t
+inquire_cb (engine_llass_t llass, const char *keyword, const char *args)
+{
+  gpg_error_t err;
+
+  if (llass->opt.gpg_agent && !strcmp (keyword, "PINENTRY_LAUNCHED"))
+    {
+      _gpgme_allow_set_foregound_window ((pid_t)strtoul (args, NULL, 10));
+    }
+
+  if (llass->user.inq_cb)
+    {
+      struct _gpgme_assuan_sendfnc_ctx sendfnc_ctx;
+
+      sendfnc_ctx.assuan_ctx = llass->assuan_ctx;
+      err = llass->user.inq_cb (llass->user.inq_cb_value,
+                                keyword, args,
+                                inquire_cb_sendfnc, &sendfnc_ctx);
+    }
+  else
+    err = 0;
+
+  return err;
+}
+
+
+static gpgme_error_t
+llass_status_handler (void *opaque, int fd)
+{
+  gpgme_error_t err = 0;
+  engine_llass_t llass = opaque;
+  char *line;
+  size_t linelen;
+
+  do
+    {
+      err = assuan_read_line (llass->assuan_ctx, &line, &linelen);
+      if (err)
+	{
+          TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
+		  "fd 0x%x: error reading assuan line: %s",
+                  fd, gpg_strerror (err));
+	}
+      else if (linelen >= 2 && line[0] == 'D' && line[1] == ' ')
+        {
+          char *src = line + 2;
+	  char *end = line + linelen;
+	  char *dst = src;
+
+          linelen = 0;
+          while (src < end)
+            {
+              if (*src == '%' && src + 2 < end)
+                {
+                  /* Handle escaped characters.  */
+                  ++src;
+                  *dst++ = _gpgme_hextobyte (src);
+                  src += 2;
+                }
+              else
+                *dst++ = *src++;
+
+              linelen++;
+            }
+
+          src = line + 2;
+          if (linelen && llass->user.data_cb)
+            err = llass->user.data_cb (llass->user.data_cb_value,
+                                       src, linelen);
+          else
+            err = 0;
+
+          TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
+		  "fd 0x%x: D inlinedata; status from cb: %s",
+                  fd, (llass->user.data_cb ?
+                       (err? gpg_strerror (err):"ok"):"no callback"));
+        }
+      else if (linelen >= 3
+               && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
+               && (line[3] == '\0' || line[3] == ' '))
+        {
+          /* END received.  Tell the data callback.  */
+          if (llass->user.data_cb)
+            err = llass->user.data_cb (llass->user.data_cb_value, NULL, 0);
+          else
+            err = 0;
+
+          TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
+		  "fd 0x%x: END line; status from cb: %s",
+                  fd, (llass->user.data_cb ?
+                       (err? gpg_strerror (err):"ok"):"no callback"));
+        }
+      else if (linelen > 2 && line[0] == 'S' && line[1] == ' ')
+	{
+	  char *args;
+          char *src;
+
+          for (src=line+2; *src == ' '; src++)
+            ;
+
+	  args = strchr (src, ' ');
+	  if (!args)
+	    args = line + linelen; /* Let it point to an empty string.  */
+	  else
+	    *(args++) = 0;
+
+          while (*args == ' ')
+            args++;
+
+          if (llass->user.status_cb)
+            err = llass->user.status_cb (llass->user.status_cb_value,
+                                         src, args);
+          else
+            err = 0;
+
+          TRACE3 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
+		  "fd 0x%x: S line (%s) - status from cb: %s",
+                  fd, line+2, (llass->user.status_cb ?
+                               (err? gpg_strerror (err):"ok"):"no callback"));
+	}
+      else if (linelen >= 7
+               && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
+               && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
+               && line[6] == 'E'
+               && (line[7] == '\0' || line[7] == ' '))
+        {
+          char *src;
+	  char *args;
+
+          for (src=line+7; *src == ' '; src++)
+            ;
+
+	  args = strchr (src, ' ');
+	  if (!args)
+	    args = line + linelen; /* Let it point to an empty string.  */
+	  else
+	    *(args++) = 0;
+
+          while (*args == ' ')
+            args++;
+
+          err = inquire_cb (llass, src, args);
+          if (!err) /* Flush and send END.  */
+            err = assuan_send_data (llass->assuan_ctx, NULL, 0);
+        }
+      else if (linelen >= 3
+	       && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
+	       && (line[3] == '\0' || line[3] == ' '))
+	{
+	  if (line[3] == ' ')
+	    err = atoi (line+4);
+	  else
+	    err = gpg_error (GPG_ERR_GENERAL);
+          TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
+		  "fd 0x%x: ERR line: %s",
+                  fd, err ? gpg_strerror (err) : "ok");
+          if (llass->result_cb)
+            err = llass->result_cb (llass->result_cb_value, err);
+          else
+            err = 0;
+          if (!err)
+            {
+              _gpgme_io_close (llass->status_cb.fd);
+              return 0;
+            }
+	}
+      else if (linelen >= 2
+	       && line[0] == 'O' && line[1] == 'K'
+	       && (line[2] == '\0' || line[2] == ' '))
+	{
+          TRACE1 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
+		  "fd 0x%x: OK line", fd);
+          if (llass->result_cb)
+            err = llass->result_cb (llass->result_cb_value, 0);
+          else
+            err = 0;
+          if (!err)
+            {
+              _gpgme_io_close (llass->status_cb.fd);
+              return 0;
+            }
+	}
+      else
+        {
+          /* Comment line or invalid line.  */
+        }
+
+    }
+  while (!err && assuan_pending_line (llass->assuan_ctx));
+
+  return err;
+}
+
+
+static gpgme_error_t
+add_io_cb (engine_llass_t llass, iocb_data_t *iocbd, gpgme_io_cb_t handler)
+{
+  gpgme_error_t err;
+
+  TRACE_BEG2 (DEBUG_ENGINE, "engine-assuan:add_io_cb", llass,
+              "fd %d, dir %d", iocbd->fd, iocbd->dir);
+  err = (*llass->io_cbs.add) (llass->io_cbs.add_priv,
+			      iocbd->fd, iocbd->dir,
+			      handler, iocbd->data, &iocbd->tag);
+  if (err)
+    return TRACE_ERR (err);
+  if (!iocbd->dir)
+    /* FIXME Kludge around poll() problem.  */
+    err = _gpgme_io_set_nonblocking (iocbd->fd);
+  return TRACE_ERR (err);
+}
+
+
+static gpgme_error_t
+start (engine_llass_t llass, const char *command)
+{
+  gpgme_error_t err;
+  int fdlist[5];
+  int nfds;
+
+  /* We need to know the fd used by assuan for reads.  We do this by
+     using the assumption that the first returned fd from
+     assuan_get_active_fds() is always this one.  */
+  nfds = assuan_get_active_fds (llass->assuan_ctx, 0 /* read fds */,
+                                fdlist, DIM (fdlist));
+  if (nfds < 1)
+    return gpg_error (GPG_ERR_GENERAL);	/* FIXME */
+
+  /* We "duplicate" the file descriptor, so we can close it here (we
+     can't close fdlist[0], as that is closed by libassuan, and
+     closing it here might cause libassuan to close some unrelated FD
+     later).  Alternatively, we could special case status_fd and
+     register/unregister it manually as needed, but this increases
+     code duplication and is more complicated as we can not use the
+     close notifications etc.  A third alternative would be to let
+     Assuan know that we closed the FD, but that complicates the
+     Assuan interface.  */
+
+  llass->status_cb.fd = _gpgme_io_dup (fdlist[0]);
+  if (llass->status_cb.fd < 0)
+    return gpg_error_from_syserror ();
+
+  if (_gpgme_io_set_close_notify (llass->status_cb.fd,
+				  close_notify_handler, llass))
+    {
+      _gpgme_io_close (llass->status_cb.fd);
+      llass->status_cb.fd = -1;
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  err = add_io_cb (llass, &llass->status_cb, llass_status_handler);
+  if (!err)
+    err = assuan_write_line (llass->assuan_ctx, command);
+
+  /* FIXME: If *command == '#' no answer is expected.  */
+
+  if (!err)
+    llass_io_event (llass, GPGME_EVENT_START, NULL);
+
+  return err;
+}
+
+
+
+static gpgme_error_t
+llass_transact (void *engine,
+                const char *command,
+                engine_assuan_result_cb_t result_cb,
+                void *result_cb_value,
+                gpgme_assuan_data_cb_t data_cb,
+                void *data_cb_value,
+                gpgme_assuan_inquire_cb_t inq_cb,
+                void *inq_cb_value,
+                gpgme_assuan_status_cb_t status_cb,
+                void *status_cb_value)
+{
+  engine_llass_t llass = engine;
+  gpgme_error_t err;
+
+  if (!llass || !command || !*command)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  llass->result_cb = result_cb;
+  llass->result_cb_value = result_cb_value;
+  llass->user.data_cb = data_cb;
+  llass->user.data_cb_value = data_cb_value;
+  llass->user.inq_cb = inq_cb;
+  llass->user.inq_cb_value = inq_cb_value;
+  llass->user.status_cb = status_cb;
+  llass->user.status_cb_value = status_cb_value;
+
+  err = start (llass, command);
+  return err;
+}
+
+
+
+static void
+llass_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
+{
+  engine_llass_t llass = engine;
+  llass->io_cbs = *io_cbs;
+}
+
+
+static void
+llass_io_event (void *engine, gpgme_event_io_t type, void *type_data)
+{
+  engine_llass_t llass = engine;
+
+  TRACE3 (DEBUG_ENGINE, "gpgme:llass_io_event", llass,
+          "event %p, type %d, type_data %p",
+          llass->io_cbs.event, type, type_data);
+  if (llass->io_cbs.event)
+    (*llass->io_cbs.event) (llass->io_cbs.event_priv, type, type_data);
+}
+
+
+struct engine_ops _gpgme_engine_ops_assuan =
+  {
+    /* Static functions.  */
+    _gpgme_get_default_agent_socket,
+    llass_get_home_dir,
+    llass_get_version,
+    llass_get_req_version,
+    llass_new,
+
+    /* Member functions.  */
+    llass_release,
+    NULL,		/* reset */
+    NULL,               /* set_status_handler */
+    NULL,		/* set_command_handler */
+    NULL,               /* set_colon_line_handler */
+    llass_set_locale,
+    NULL,               /* decrypt */
+    NULL,               /* delete */
+    NULL,		/* edit */
+    NULL,               /* encrypt */
+    NULL,		/* encrypt_sign */
+    NULL,               /* export */
+    NULL,               /* export_ext */
+    NULL,               /* genkey */
+    NULL,               /* import */
+    NULL,               /* keylist */
+    NULL,               /* keylist_ext */
+    NULL,               /* sign */
+    NULL,		/* trustlist */
+    NULL,               /* verify */
+    NULL,               /* getauditlog */
+    llass_transact,     /* opassuan_transact */
+    NULL,		/* conf_load */
+    NULL,		/* conf_save */
+    llass_set_io_cbs,
+    llass_io_event,
+    llass_cancel
+  };

Modified: trunk/src/engine-backend.h
===================================================================
--- trunk/src/engine-backend.h	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/engine-backend.h	2009-01-26 10:21:10 UTC (rev 1353)
@@ -1,5 +1,5 @@
 /* engine-backend.h - A crypto backend for the engine interface.
-   Copyright (C) 2002, 2003, 2004 g10 Code GmbH
+   Copyright (C) 2002, 2003, 2004, 2009 g10 Code GmbH
  
    This file is part of GPGME.
  
@@ -14,9 +14,8 @@
    Lesser General Public License for more details.
    
    You should have received a copy of the GNU Lesser 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.  */
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
 
 #ifndef ENGINE_BACKEND_H
 #define ENGINE_BACKEND_H
@@ -35,6 +34,11 @@
   /* Return the default file name for the binary of this engine.  */
   const char *(*get_file_name) (void);
 
+  /* Return the default home dir for the binary of this engine.  If
+     this function pointer is not set, the standard default home dir
+     of the engine is used. */
+  const char *(*get_home_dir) (void);
+
   /* Returns a malloced string containing the version of the engine
      with the given binary file name (or the default if FILE_NAME is
      NULL.  */
@@ -96,6 +100,16 @@
 			   gpgme_data_t plaintext);
   gpgme_error_t  (*getauditlog) (void *engine, gpgme_data_t output,
                                  unsigned int flags);
+  gpgme_error_t  (*opassuan_transact) (void *engine, 
+                                       const char *command,
+                                       engine_assuan_result_cb_t result_cb,
+                                       void *result_cb_value,
+                                       gpgme_assuan_data_cb_t data_cb,
+                                       void *data_cb_value,
+                                       gpgme_assuan_inquire_cb_t inq_cb,
+                                       void *inq_cb_value,
+                                       gpgme_assuan_status_cb_t status_cb,
+                                       void *status_cb_value);
 
   gpgme_error_t  (*conf_load) (void *engine, gpgme_conf_comp_t *conf_p);
   gpgme_error_t  (*conf_save) (void *engine, gpgme_conf_comp_t conf);
@@ -114,5 +128,8 @@
 #ifdef ENABLE_GPGCONF
 extern struct engine_ops _gpgme_engine_ops_gpgconf;	/* gpg-conf.  */
 #endif
+#ifdef ENABLE_GPGSM  /* If this is enabled we also have assuan support.  */
+extern struct engine_ops _gpgme_engine_ops_assuan;	/* Low-level Assuan. */
+#endif
 
 #endif /* ENGINE_BACKEND_H */

Modified: trunk/src/engine-gpg.c
===================================================================
--- trunk/src/engine-gpg.c	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/engine-gpg.c	2009-01-26 10:21:10 UTC (rev 1353)
@@ -2158,6 +2158,7 @@
   {
     /* Static functions.  */
     _gpgme_get_gpg_path,
+    NULL,               
     gpg_get_version,
     gpg_get_req_version,
     gpg_new,
@@ -2184,6 +2185,7 @@
     gpg_trustlist,
     gpg_verify,
     NULL,		/* getauditlog */
+    NULL,               /* opassuan_transact */
     NULL,		/* conf_load */
     NULL,		/* conf_save */
     gpg_set_io_cbs,

Modified: trunk/src/engine-gpgconf.c
===================================================================
--- trunk/src/engine-gpgconf.c	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/engine-gpgconf.c	2009-01-26 10:21:10 UTC (rev 1353)
@@ -885,6 +885,7 @@
   {
     /* Static functions.  */
     _gpgme_get_gpgconf_path,
+    NULL,
     gpgconf_get_version,
     gpgconf_get_req_version,
     gpgconf_new,
@@ -911,6 +912,7 @@
     NULL,		/* trustlist */
     NULL,		/* verify */
     NULL,		/* getauditlog */
+    NULL,               /* opassuan_transact */
     gpgconf_conf_load,
     gpgconf_conf_save,
     gpgconf_set_io_cbs,

Modified: trunk/src/engine-gpgsm.c
===================================================================
--- trunk/src/engine-gpgsm.c	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/engine-gpgsm.c	2009-01-26 10:21:10 UTC (rev 1353)
@@ -1922,6 +1922,7 @@
   {
     /* Static functions.  */
     _gpgme_get_gpgsm_path,
+    NULL,
     gpgsm_get_version,
     gpgsm_get_req_version,
     gpgsm_new,
@@ -1952,6 +1953,7 @@
     NULL,		/* trustlist */
     gpgsm_verify,
     gpgsm_getauditlog,
+    NULL,               /* opassuan_transact */
     NULL,		/* conf_load */
     NULL,		/* conf_save */
     gpgsm_set_io_cbs,

Modified: trunk/src/engine.c
===================================================================
--- trunk/src/engine.c	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/engine.c	2009-01-26 10:21:10 UTC (rev 1353)
@@ -1,6 +1,6 @@
 /* engine.c - GPGME engine support.
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004, 2006 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2006, 2009 g10 Code GmbH
  
    This file is part of GPGME.
  
@@ -15,9 +15,8 @@
    Lesser General Public License for more details.
    
    You should have received a copy of the GNU Lesser 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.  */
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -52,8 +51,13 @@
     NULL,
 #endif
 #ifdef ENABLE_GPGCONF
-    &_gpgme_engine_ops_gpgconf		/* gpg-conf.  */
+    &_gpgme_engine_ops_gpgconf,		/* gpg-conf.  */
 #else
+    NULL,
+#endif
+#ifdef ENABLE_GPGSM  /* This indicates that we have assuan support.  */
+    &_gpgme_engine_ops_assuan		/* Low-Level Assuan.  */
+#else
     NULL
 #endif
   };
@@ -78,6 +82,20 @@
 }
 
 
+/* Get the standard home dir of the engine for PROTOCOL.  */
+static const char *
+engine_get_home_dir (gpgme_protocol_t proto)
+{
+  if (proto > DIM (engine_ops))
+    return NULL;
+
+  if (engine_ops[proto] && engine_ops[proto]->get_home_dir)
+    return (*engine_ops[proto]->get_home_dir) ();
+  else
+    return NULL;
+}
+
+
 /* Get a malloced string containing the version number of the engine
    for PROTOCOL.  */
 static char *
@@ -175,18 +193,22 @@
       gpgme_engine_info_t *lastp = &engine_info;
       gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP,
 					GPGME_PROTOCOL_CMS,
-					GPGME_PROTOCOL_GPGCONF };
+					GPGME_PROTOCOL_GPGCONF,
+					GPGME_PROTOCOL_ASSUAN };
       unsigned int proto;
 
       for (proto = 0; proto < DIM (proto_list); proto++)
 	{
 	  const char *ofile_name = engine_get_file_name (proto_list[proto]);
+	  const char *ohome_dir  = engine_get_home_dir (proto_list[proto]);
 	  char *file_name;
+	  char *home_dir;
 
 	  if (!ofile_name)
 	    continue;
 
 	  file_name = strdup (ofile_name);
+          home_dir = ohome_dir? strdup (ohome_dir): NULL;
 
 	  *lastp = malloc (sizeof (*engine_info));
 	  if (!*lastp || !file_name)
@@ -198,6 +220,8 @@
 
 	      if (file_name)
 		free (file_name);
+	      if (home_dir)
+		free (home_dir);
 
 	      UNLOCK (engine_info_lock);
 	      return gpg_error_from_errno (saved_errno);
@@ -205,7 +229,7 @@
 
 	  (*lastp)->protocol = proto_list[proto];
 	  (*lastp)->file_name = file_name;
-	  (*lastp)->home_dir = NULL;
+	  (*lastp)->home_dir = home_dir;
 	  (*lastp)->version = engine_get_version (proto_list[proto], NULL);
 	  (*lastp)->req_version = engine_get_req_version (proto_list[proto]);
 	  (*lastp)->next = NULL;
@@ -347,7 +371,20 @@
 	}
     }
   else
-    new_home_dir = NULL;
+    {
+      const char *ohome_dir = engine_get_home_dir (proto);
+      if (ohome_dir)
+        {
+          new_home_dir = strdup (ohome_dir);
+          if (!new_home_dir)
+            {
+              free (new_file_name);
+              return gpg_error_from_errno (errno);
+            }
+        }
+      else
+        new_home_dir = NULL;
+    }
 
   /* Remove the old members.  */
   assert (info->file_name);
@@ -731,6 +768,33 @@
 
 
 gpgme_error_t
+_gpgme_engine_op_assuan_transact (engine_t engine, 
+                                  const char *command,
+                                  engine_assuan_result_cb_t result_cb,
+                                  void *result_cb_value,
+                                  gpgme_assuan_data_cb_t data_cb,
+                                  void *data_cb_value,
+                                  gpgme_assuan_inquire_cb_t inq_cb,
+                                  void *inq_cb_value,
+                                  gpgme_assuan_status_cb_t status_cb,
+                                  void *status_cb_value)
+{
+  if (!engine)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (!engine->ops->opassuan_transact)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+  return (*engine->ops->opassuan_transact) (engine->engine, 
+                                            command,
+                                            result_cb, result_cb_value,
+                                            data_cb, data_cb_value,
+                                            inq_cb, inq_cb_value,
+                                            status_cb, status_cb_value);
+}
+
+
+gpgme_error_t
 _gpgme_engine_op_conf_load (engine_t engine, gpgme_conf_comp_t *conf_p)
 {
   if (!engine)

Modified: trunk/src/engine.h
===================================================================
--- trunk/src/engine.h	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/engine.h	2009-01-26 10:21:10 UTC (rev 1353)
@@ -35,7 +35,10 @@
 						   gpgme_status_code_t code,
 						   const char *keyword,
 						   int fd, int *processed);
+typedef gpgme_error_t (*engine_assuan_result_cb_t) (void *priv,
+                                                    gpgme_error_t result);
 
+
 /* Get a deep copy of the engine info and return it in INFO.  */
 gpgme_error_t _gpgme_engine_info_copy (gpgme_engine_info_t *r_info);
 
@@ -126,6 +129,17 @@
 gpgme_error_t _gpgme_engine_op_getauditlog (engine_t engine,
                                             gpgme_data_t output,
                                             unsigned int flags);
+gpgme_error_t _gpgme_engine_op_assuan_transact 
+                (engine_t engine, 
+                 const char *command,
+                 engine_assuan_result_cb_t result_cb,
+                 void *result_cb_value,
+                 gpgme_assuan_data_cb_t data_cb,
+                 void *data_cb_value,
+                 gpgme_assuan_inquire_cb_t inq_cb,
+                 void *inq_cb_value,
+                 gpgme_assuan_status_cb_t status_cb,
+                 void *status_cb_value);
 
 gpgme_error_t _gpgme_engine_op_conf_load (engine_t engine,
 					  gpgme_conf_comp_t *conf_p);

Modified: trunk/src/gpgme.c
===================================================================
--- trunk/src/gpgme.c	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/gpgme.c	2009-01-26 10:21:10 UTC (rev 1353)
@@ -192,7 +192,9 @@
 	      protocol, gpgme_get_protocol_name (protocol)
 	      ? gpgme_get_protocol_name (protocol) : "unknown");
 
-  if (protocol != GPGME_PROTOCOL_OpenPGP && protocol != GPGME_PROTOCOL_CMS)
+  if (protocol != GPGME_PROTOCOL_OpenPGP
+      && protocol != GPGME_PROTOCOL_CMS
+      && protocol != GPGME_PROTOCOL_ASSUAN)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
 
   if (ctx->protocol != protocol)
@@ -233,6 +235,9 @@
     case GPGME_PROTOCOL_CMS:
       return "CMS";
 
+    case GPGME_PROTOCOL_ASSUAN:
+      return "Assuan";
+
     case GPGME_PROTOCOL_UNKNOWN:
       return "unknown";
 

Modified: trunk/src/gpgme.def
===================================================================
--- trunk/src/gpgme.def	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/gpgme.def	2009-01-26 10:21:10 UTC (rev 1353)
@@ -167,5 +167,9 @@
     gpgme_op_conf_save			  @130
 
     gpgme_cancel_async                    @131
+
+    gpgme_op_assuan_result                @132
+    gpgme_op_assuan_transact_start        @133
+    gpgme_op_assuan_transact              @134
 ; END
 

Modified: trunk/src/gpgme.h.in
===================================================================
--- trunk/src/gpgme.h.in	2009-01-19 14:44:13 UTC (rev 1352)
+++ trunk/src/gpgme.h.in	2009-01-26 10:21:10 UTC (rev 1353)
@@ -1,6 +1,6 @@
 /* gpgme.h - Public interface to GnuPG Made Easy.                   -*- c -*-
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH
 
    This file is part of GPGME.
  
@@ -301,6 +301,7 @@
     GPGME_PROTOCOL_OpenPGP = 0,  /* The default mode.  */
     GPGME_PROTOCOL_CMS     = 1,
     GPGME_PROTOCOL_GPGCONF = 2,  /* Special code for gpgconf.  */
+    GPGME_PROTOCOL_ASSUAN  = 3,  /* Low-level access to an Assuan server.  */
     GPGME_PROTOCOL_UNKNOWN = 255
   }
 gpgme_protocol_t;
@@ -746,6 +747,8 @@
 					  gpgme_status_code_t status,
 					  const char *args, int fd);
 
+
+
 
 /* Context management functions.  */
 
@@ -1656,7 +1659,52 @@
 gpgme_error_t gpgme_op_getauditlog (gpgme_ctx_t ctx, gpgme_data_t output, 
                                     unsigned int flags);
 
+
 
+/* Low-level Assuan protocol access.  */
+typedef gpgme_error_t (*gpgme_assuan_data_cb_t) 
+     (void *opaque, const void *data, size_t datalen);
+
+struct _gpgme_assuan_sendfnc_ctx;
+typedef struct _gpgme_assuan_sendfnc_ctx *gpgme_assuan_sendfnc_ctx_t;
+typedef gpgme_error_t (*gpgme_assuan_sendfnc_t)
+     (gpgme_assuan_sendfnc_ctx_t ctx, const void *data, size_t datalen);
+
+typedef gpgme_error_t (*gpgme_assuan_inquire_cb_t)
+     (void *opaque, const char *name, const char *args,
+      gpgme_assuan_sendfnc_t sendfnc, 
+      gpgme_assuan_sendfnc_ctx_t sendfnc_ctx);
+
+typedef gpgme_error_t (*gpgme_assuan_status_cb_t)
+     (void *opaque, const char *status, const char *args);
+
+/* Return the result of the last Assuan command. */
+gpgme_error_t gpgme_op_assuan_result (gpgme_ctx_t ctx);
+
+/* Send the Assuan COMMAND and return results via the callbacks.
+   Asynchronous variant. */
+gpgme_error_t gpgme_op_assuan_transact_start (gpgme_ctx_t ctx, 
+                                              const char *command,
+                                              gpgme_assuan_data_cb_t data_cb,
+                                              void *data_cb_value,
+                                              gpgme_assuan_inquire_cb_t inq_cb,
+                                              void *inq_cb_value,
+                                              gpgme_assuan_status_cb_t stat_cb,
+                                              void *stat_cb_value);
+




More information about the Gnupg-commits mailing list