First take on the low-level assuan interface.
This commit is contained in:
parent
23022dd9d9
commit
d951cb713f
@ -1,3 +1,7 @@
|
||||
2009-01-26 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (AC_CONFIG_FILES): Add tests/opassuan/Makefile.
|
||||
|
||||
2008-12-08 Marcus Brinkmann <marcus@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@g10code.de>
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
16
NEWS
16
NEWS
@ -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)
|
||||
------------------------------------------------
|
||||
|
||||
|
@ -159,4 +159,6 @@ $AUTOMAKE --gnu;
|
||||
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
|
||||
"
|
||||
|
@ -31,8 +31,8 @@ min_automake_version="1.10"
|
||||
# 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 @@ AC_SUBST(LTLIBOBJS)
|
||||
# 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)
|
||||
|
@ -1,3 +1,36 @@
|
||||
2009-01-26 Werner Koch <wk@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@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@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@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@g10code.de>
|
||||
|
||||
@ -3707,7 +3740,7 @@
|
||||
2002-09-28 Marcus Brinkmann <marcus@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@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@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@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@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@jaimedelamo.eu.org>
|
||||
2001-05-01 José Carlos García Sogo <jose@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
|
||||
|
@ -78,7 +78,7 @@ system_components_not_extra =
|
||||
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 @@ main_sources = \
|
||||
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) \
|
||||
|
@ -36,7 +36,7 @@ typedef enum
|
||||
{
|
||||
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 @@ struct ctx_op_data
|
||||
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. */
|
||||
|
189
src/dirinfo.c
Normal file
189
src/dirinfo.c
Normal file
@ -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);
|
||||
}
|
||||
|
744
src/engine-assuan.c
Normal file
744
src/engine-assuan.c
Normal file
@ -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
|
||||
};
|
@ -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 @@ struct engine_ops
|
||||
/* 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 @@ struct engine_ops
|
||||
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 @@ extern struct engine_ops _gpgme_engine_ops_gpgsm; /* CMS. */
|
||||
#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 */
|
||||
|
@ -2158,6 +2158,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
|
||||
{
|
||||
/* Static functions. */
|
||||
_gpgme_get_gpg_path,
|
||||
NULL,
|
||||
gpg_get_version,
|
||||
gpg_get_req_version,
|
||||
gpg_new,
|
||||
@ -2184,6 +2185,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
|
||||
gpg_trustlist,
|
||||
gpg_verify,
|
||||
NULL, /* getauditlog */
|
||||
NULL, /* opassuan_transact */
|
||||
NULL, /* conf_load */
|
||||
NULL, /* conf_save */
|
||||
gpg_set_io_cbs,
|
||||
|
@ -885,6 +885,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
|
||||
{
|
||||
/* Static functions. */
|
||||
_gpgme_get_gpgconf_path,
|
||||
NULL,
|
||||
gpgconf_get_version,
|
||||
gpgconf_get_req_version,
|
||||
gpgconf_new,
|
||||
@ -911,6 +912,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
|
||||
NULL, /* trustlist */
|
||||
NULL, /* verify */
|
||||
NULL, /* getauditlog */
|
||||
NULL, /* opassuan_transact */
|
||||
gpgconf_conf_load,
|
||||
gpgconf_conf_save,
|
||||
gpgconf_set_io_cbs,
|
||||
|
@ -1922,6 +1922,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
|
||||
{
|
||||
/* Static functions. */
|
||||
_gpgme_get_gpgsm_path,
|
||||
NULL,
|
||||
gpgsm_get_version,
|
||||
gpgsm_get_req_version,
|
||||
gpgsm_new,
|
||||
@ -1952,6 +1953,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
|
||||
NULL, /* trustlist */
|
||||
gpgsm_verify,
|
||||
gpgsm_getauditlog,
|
||||
NULL, /* opassuan_transact */
|
||||
NULL, /* conf_load */
|
||||
NULL, /* conf_save */
|
||||
gpgsm_set_io_cbs,
|
||||
|
78
src/engine.c
78
src/engine.c
@ -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,7 +51,12 @@ static struct engine_ops *engine_ops[] =
|
||||
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 @@ engine_get_file_name (gpgme_protocol_t proto)
|
||||
}
|
||||
|
||||
|
||||
/* 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_get_engine_info (gpgme_engine_info_t *info)
|
||||
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 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
|
||||
|
||||
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 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
|
||||
|
||||
(*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;
|
||||
@ -346,8 +370,21 @@ _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto,
|
||||
return gpg_error_from_errno (errno);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
@ -730,6 +767,33 @@ _gpgme_engine_op_getauditlog (engine_t engine, gpgme_data_t output,
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
14
src/engine.h
14
src/engine.h
@ -35,6 +35,9 @@ typedef gpgme_error_t (*engine_command_handler_t) (void *priv,
|
||||
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_verify (engine_t engine, gpgme_data_t sig,
|
||||
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);
|
||||
|
@ -192,7 +192,9 @@ gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
|
||||
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 @@ gpgme_get_protocol_name (gpgme_protocol_t protocol)
|
||||
case GPGME_PROTOCOL_CMS:
|
||||
return "CMS";
|
||||
|
||||
case GPGME_PROTOCOL_ASSUAN:
|
||||
return "Assuan";
|
||||
|
||||
case GPGME_PROTOCOL_UNKNOWN:
|
||||
return "unknown";
|
||||
|
||||
|
@ -167,5 +167,9 @@ EXPORTS
|
||||
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
|
||||
|
||||
|
@ -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 @@ typedef enum
|
||||
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 @@ typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque,
|
||||
gpgme_status_code_t status,
|
||||
const char *args, int fd);
|
||||
|
||||
|
||||
|
||||
|
||||
/* Context management functions. */
|
||||
|
||||
@ -1656,6 +1659,51 @@ gpgme_error_t gpgme_op_getauditlog_start (gpgme_ctx_t ctx, gpgme_data_t output,
|
||||
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);
|
||||
|
||||
/* Send the Assuan COMMAND and return results via the callbacks.
|
||||
Synchronous variant. */
|
||||
gpgme_error_t gpgme_op_assuan_transact (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);
|
||||
|
||||
|
||||
|
||||
/* Interface to gpgconf(1). */
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# libgpgme.vers - List of symbols to export.
|
||||
# Copyright (C) 2002, 2004, 2005 g10 Code GmbH
|
||||
# Copyright (C) 2002, 2004, 2005, 2009 g10 Code GmbH
|
||||
#
|
||||
# This file is part of GPGME.
|
||||
#
|
||||
@ -14,8 +14,7 @@
|
||||
# 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, 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/>.
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Please remember to add new functions also to gpgme.def
|
||||
@ -48,6 +47,10 @@ GPGME_1.1 {
|
||||
gpgme_op_conf_save;
|
||||
|
||||
gpgme_cancel_async;
|
||||
|
||||
gpgme_op_assuan_result;
|
||||
gpgme_op_assuan_transact;
|
||||
gpgme_op_assuan_transact_start;
|
||||
};
|
||||
|
||||
|
||||
|
158
src/opassuan.c
Normal file
158
src/opassuan.c
Normal file
@ -0,0 +1,158 @@
|
||||
/* opassuan.c - Low-level Assuan operations.
|
||||
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 "gpgme.h"
|
||||
#include "context.h"
|
||||
#include "ops.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* The result of the assuan command with 0 for OK and an error value
|
||||
for ERR. */
|
||||
gpgme_error_t result;
|
||||
} *op_data_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/* This callback is used to return the status of the assuan command
|
||||
back. Note that this is different from the error code returned
|
||||
from gpgme_op_assuan_transact because the later only reflects error
|
||||
with the connection. */
|
||||
static gpgme_error_t
|
||||
result_cb (void *priv, gpgme_error_t result)
|
||||
{
|
||||
gpgme_ctx_t ctx = (gpgme_ctx_t)priv;
|
||||
gpgme_error_t err;
|
||||
void *hook;
|
||||
op_data_t opd;
|
||||
|
||||
err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL);
|
||||
opd = hook;
|
||||
if (err)
|
||||
return err;
|
||||
if (!opd)
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
|
||||
opd->result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
gpgme_error_t
|
||||
gpgme_op_assuan_result (gpgme_ctx_t ctx)
|
||||
{
|
||||
gpgme_error_t err;
|
||||
void *hook;
|
||||
op_data_t opd;
|
||||
|
||||
err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL);
|
||||
opd = hook;
|
||||
if (err)
|
||||
return err;
|
||||
if (!opd)
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
|
||||
return opd->result;
|
||||
}
|
||||
|
||||
|
||||
static gpgme_error_t
|
||||
opassuan_start (gpgme_ctx_t ctx, int synchronous,
|
||||
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 status_cb,
|
||||
void *status_cb_value)
|
||||
{
|
||||
gpgme_error_t err;
|
||||
void *hook;
|
||||
op_data_t opd;
|
||||
|
||||
if (!command || !*command)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
/* The flag value 256 is used to suppress an engine reset. This is
|
||||
required to keep the connection running. */
|
||||
err = _gpgme_op_reset (ctx, ((synchronous&255) | 256));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, sizeof (*opd), NULL);
|
||||
opd = hook;
|
||||
if (err)
|
||||
return err;
|
||||
opd->result = gpg_error (GPG_ERR_UNFINISHED);
|
||||
|
||||
return _gpgme_engine_op_assuan_transact (ctx->engine, command,
|
||||
result_cb, ctx,
|
||||
data_cb, data_cb_value,
|
||||
inq_cb, inq_cb_value,
|
||||
status_cb, status_cb_value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* XXXX. This is the 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 status_cb,
|
||||
void *status_cb_value)
|
||||
{
|
||||
return opassuan_start (ctx, 0, command,
|
||||
data_cb, data_cb_value,
|
||||
inq_cb, inq_cb_value,
|
||||
status_cb, status_cb_value);
|
||||
}
|
||||
|
||||
|
||||
/* XXXX. This is the synchronous variant. */
|
||||
gpgme_error_t
|
||||
gpgme_op_assuan_transact (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 status_cb,
|
||||
void *status_cb_value)
|
||||
{
|
||||
gpgme_error_t err;
|
||||
|
||||
err = opassuan_start (ctx, 1, command,
|
||||
data_cb, data_cb_value,
|
||||
inq_cb, inq_cb_value,
|
||||
status_cb, status_cb_value);
|
||||
if (!err)
|
||||
err = _gpgme_wait_one (ctx);
|
||||
return err;
|
||||
}
|
||||
|
11
src/util.h
11
src/util.h
@ -35,6 +35,11 @@ const char *_gpgme_get_gpgconf_path (void);
|
||||
int _gpgme_get_conf_int (const char *key, int *value);
|
||||
void _gpgme_allow_set_foregound_window (pid_t pid);
|
||||
|
||||
/*-- dirinfo.c --*/
|
||||
const char *_gpgme_get_default_homedir (void);
|
||||
const char *_gpgme_get_default_agent_socket (void);
|
||||
|
||||
|
||||
|
||||
/*-- replacement functions in <funcname>.c --*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -111,4 +116,10 @@ int _gpgme_mkstemp (int *fd, char **name);
|
||||
const char *_gpgme_get_w32spawn_path (void);
|
||||
#endif
|
||||
|
||||
/*-- Error codes not yet available in current gpg-error.h. --*/
|
||||
#ifndef GPG_ERR_UNFINISHED
|
||||
#define GPG_ERR_UNFINISHED 199
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UTIL_H */
|
||||
|
@ -179,7 +179,8 @@ gpgme_check_version (const char *req_version)
|
||||
automagically initialize the debug system with out the locks
|
||||
being initialized and missing the assuan log level setting. */
|
||||
TRACE2 (DEBUG_INIT, "gpgme_check_version: ", 0,
|
||||
"req_version=%s, VERSION=%s", req_version, VERSION);
|
||||
"req_version=%s, VERSION=%s",
|
||||
req_version? req_version:"(null)", VERSION);
|
||||
|
||||
return _gpgme_compare_versions (VERSION, req_version) ? VERSION : NULL;
|
||||
}
|
||||
|
@ -1,3 +1,9 @@
|
||||
2009-01-26 Werner Koch <wk@g10code.com>
|
||||
|
||||
* opassuan/: New.
|
||||
* opassuan/Makefile.am: New.
|
||||
* opassuan/t-command.c: New.
|
||||
|
||||
2008-12-03 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* Makefile.am (INCLUDES): Fix path to include file.
|
||||
|
@ -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
|
||||
|
||||
@ -40,7 +39,7 @@ gpgtests =
|
||||
endif
|
||||
|
||||
if RUN_GPGSM_TESTS
|
||||
gpgsmtests = gpgsm
|
||||
gpgsmtests = gpgsm opassuan
|
||||
else
|
||||
gpgsmtests =
|
||||
endif
|
||||
|
35
tests/opassuan/Makefile.am
Normal file
35
tests/opassuan/Makefile.am
Normal file
@ -0,0 +1,35 @@
|
||||
# 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/>.
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO=
|
||||
|
||||
noinst_HEADERS =
|
||||
TESTS =
|
||||
|
||||
EXTRA_DIST =
|
||||
|
||||
INCLUDES = -I$(top_builddir)/src
|
||||
|
||||
AM_CPPFLAGS = @GPG_ERROR_CFLAGS@
|
||||
LDADD = ../../src/libgpgme.la
|
||||
|
||||
noinst_PROGRAMS = $(TESTS) t-command
|
||||
|
||||
DISTCLEANFILES =
|
||||
|
121
tests/opassuan/t-command.c
Normal file
121
tests/opassuan/t-command.c
Normal file
@ -0,0 +1,121 @@
|
||||
/* t-command.c - Regression test.
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <gpgme.h>
|
||||
|
||||
#define fail_if_err(err) \
|
||||
do \
|
||||
{ \
|
||||
if (err) \
|
||||
{ \
|
||||
fprintf (stderr, "%s:%d: %s: %s (%d.%d)\n", \
|
||||
__FILE__, __LINE__, gpg_strsource (err), \
|
||||
gpg_strerror (err), \
|
||||
gpg_err_source (err), gpg_err_code (err)); \
|
||||
exit (1); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
data_cb (void *opaque, const void *data, size_t datalen)
|
||||
{
|
||||
printf ("DATA_CB: datalen=%d\n", (int)datalen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
inq_cb (void *opaque, const char *name, const char *args,
|
||||
gpgme_assuan_sendfnc_t sendfnc,
|
||||
gpgme_assuan_sendfnc_ctx_t sendfnc_value)
|
||||
{
|
||||
printf ("INQ_CB: name=`%s' args=`%s'\n", name, args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
status_cb (void *opaque, const char *status, const char *args)
|
||||
{
|
||||
printf ("STATUS_CB: status=`%s' args=`%s'\n", status, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gpgme_error_t err;
|
||||
gpgme_ctx_t ctx;
|
||||
const char *command;
|
||||
|
||||
gpgme_check_version (NULL);
|
||||
#ifndef HAVE_W32_SYSTEM
|
||||
setlocale (LC_ALL, "");
|
||||
gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
|
||||
gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
|
||||
#endif
|
||||
|
||||
if (argc)
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
command = argc? *argv : "NOP";
|
||||
|
||||
|
||||
err = gpgme_new (&ctx);
|
||||
fail_if_err (err);
|
||||
|
||||
err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_ASSUAN);
|
||||
fail_if_err (err);
|
||||
|
||||
err = gpgme_op_assuan_transact (ctx, command,
|
||||
data_cb, NULL,
|
||||
inq_cb, NULL,
|
||||
status_cb, NULL);
|
||||
fail_if_err (err);
|
||||
err = gpgme_op_assuan_result (ctx);
|
||||
if (err)
|
||||
fprintf (stderr, "assuan command `%s' failed: %s <%s> (%d)\n",
|
||||
command, gpg_strerror (err), gpg_strsource (err), err);
|
||||
else
|
||||
fprintf (stderr, "assuan command `%s' succeeded\n", command);
|
||||
|
||||
|
||||
gpgme_release (ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user