-EXTRA_DIST = README-alpha
+EXTRA_DIST = README-alpha build-w32
-SUBDIRS = gpgme tests
+if BUILD_BONOBO
+bonobo = bonobo
+else
+bonobo =
+endif
+if BUILD_COMPLUS
+complus = complus
+else
+complus =
+endif
+
+
+SUBDIRS = jnlib gpgme tests ${bonobo} ${complus}
/* path to the gpg binary */
#undef GPG_PATH
+/* stuff needed by lnlib/ */
+#undef HAVE_BYTE_TYPEDEF
+#undef HAVE_USHORT_TYPEDEF
+#undef HAVE_ULONG_TYPEDEF
+#undef HAVE_U16_TYPEDEF
+#undef HAVE_U32_TYPEDEF
+
+
+
@BOTTOM@
/* not yet needed #include "gpgme-defs.h"*/
fi
])
+dnl GNUPG_CHECK_TYPEDEF(TYPE, HAVE_NAME)
+dnl Check whether a typedef exists and create a #define $2 if it exists
+dnl
+AC_DEFUN(GNUPG_CHECK_TYPEDEF,
+ [ AC_MSG_CHECKING(for $1 typedef)
+ AC_CACHE_VAL(gnupg_cv_typedef_$1,
+ [AC_TRY_COMPILE([#include <stdlib.h>
+ #include <sys/types.h>], [
+ #undef $1
+ int a = sizeof($1);
+ ], gnupg_cv_typedef_$1=yes, gnupg_cv_typedef_$1=no )])
+ AC_MSG_RESULT($gnupg_cv_typedef_$1)
+ if test "$gnupg_cv_typedef_$1" = yes; then
+ AC_DEFINE($2)
+ fi
+ ])
+
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+bin_PROGRAMS = gpgme
+
+INCLUDES = -I$(top_srcdir)/jnlib
+LDADD = -L ../jnlib -ljnlib
+
+gpgme_SOURCES = main.c main.h
+
+
+
--- /dev/null
+/* gpgme - Bonbobo component to access GnuPG
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
--- /dev/null
+/* main.c - Bonbobo component to access GnuPG
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
--- /dev/null
+/* main.h - GPGME Bonobo component
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef MAIN_H
+#define MAIN_H
+
+
+struct {
+ int verbose;
+ int quiet;
+ unsigned int debug;
+ char *homedir;
+} opt;
+
+
+
+
+#endif /* MAIN_H */
+
+
+
+
+
+
+
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+# No need to install this becuase we are cross-compiling anyway.
+noinst_PROGRAMS = gpgme
+
+INCLUDES = -I$(top_srcdir)/jnlib
+LDADD = -L ../jnlib -ljnlib
+
+gpgme_SOURCES = main.c main.h
+
+
+
--- /dev/null
+/* main.c - COM+ component to access GnuPG
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <time.h>
+#include <windows.h>
+
+#include "argparse.h"
+
+#include "main.h"
+
+
+static void register_server (void);
+static void unregister_server (void);
+static void enter_complus (void);
+
+
+enum cmd_and_opt_values { aNull = 0,
+ oQuiet = 'q',
+ oVerbose = 'v',
+
+ oNoVerbose = 500,
+ oOptions,
+ oDebug,
+ oDebugAll,
+ oNoGreeting,
+ oNoOptions,
+ oHomedir,
+ oGPGBinary,
+ oRegServer,
+ oUnregServer,
+ oEmbedding,
+aTest };
+
+
+static ARGPARSE_OPTS opts[] = {
+
+ { 301, NULL, 0, N_("@Options:\n ") },
+
+ { oVerbose, "verbose", 0, N_("verbose") },
+ { oQuiet, "quiet", 0, N_("be somewhat more quiet") },
+ { oOptions, "options" , 2, N_("read options from file")},
+ { oDebug, "debug" ,4|16, N_("set debugging flags")},
+ { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
+ { oGPGBinary, "gpg-program", 2 , "@" },
+ { oRegServer, "RegServer" , 0, "@" },
+ { oUnregServer, "UnregServer" , 0, "@" },
+ { oEmbedding, "Embedding" , 0, "@" },
+{0} };
+
+static const char *
+my_strusage( int level )
+{
+ const char *p;
+ switch( level ) {
+ case 11: p = "gpgme";
+ break;
+ case 13: p = VERSION; break;
+ /*case 17: p = PRINTABLE_OS_NAME; break;*/
+ case 19: p =
+ _("Please report bugs to <gpgme-bugs@gnupg.org>.\n");
+ break;
+ case 1:
+ case 40: p =
+ _("Usage: gpgme [options] (-h for help)");
+ break;
+ case 41: p =
+ _("Syntax: gpgme [options]\n"
+ "GnuPG COM+ component\n");
+ break;
+
+ default: p = NULL;
+ }
+ return p;
+}
+
+
+int
+main (int argc, char **argv )
+{
+ ARGPARSE_ARGS pargs;
+ int orig_argc;
+ char **orig_argv;
+ FILE *configfp = NULL;
+ char *configname = NULL;
+ unsigned configlineno;
+ int parse_debug = 0;
+ int default_config =1;
+ int greeting = 0;
+ int nogreeting = 0;
+ int action = 0;
+
+ set_strusage( my_strusage );
+ /*log_set_name ("gpa"); not yet implemented in logging.c */
+
+ opt.homedir = getenv("GNUPGHOME");
+ if( !opt.homedir || !*opt.homedir ) {
+ #ifdef HAVE_DRIVE_LETTERS
+ opt.homedir = "c:/gnupg";
+ #else
+ opt.homedir = "~/.gnupg";
+ #endif
+ }
+
+ /* check whether we have a config file on the commandline */
+ orig_argc = argc;
+ orig_argv = argv;
+ pargs.argc = &argc;
+ pargs.argv = &argv;
+ pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */
+ while( arg_parse( &pargs, opts) ) {
+ if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll )
+ parse_debug++;
+ else if( pargs.r_opt == oOptions ) {
+ /* yes there is one, so we do not try the default one, but
+ * read the option file when it is encountered at the commandline
+ */
+ default_config = 0;
+ }
+ else if( pargs.r_opt == oNoOptions )
+ default_config = 0; /* --no-options */
+ else if( pargs.r_opt == oHomedir )
+ opt.homedir = pargs.r.ret_str;
+ }
+
+ if( default_config )
+ configname = make_filename(opt.homedir, "gpgme.conf", NULL );
+
+
+ argc = orig_argc;
+ argv = orig_argv;
+ pargs.argc = &argc;
+ pargs.argv = &argv;
+ pargs.flags= 1 | (1<<5); /* do not remove the args, allow one dash */
+ next_pass:
+ if( configname ) {
+ configlineno = 0;
+ configfp = fopen( configname, "r" );
+ if( !configfp ) {
+ if( default_config ) {
+ if( parse_debug )
+ log_info(_("NOTE: no default option file `%s'\n"),
+ configname );
+ }
+ else {
+ log_error(_("option file `%s': %s\n"),
+ configname, strerror(errno) );
+ exit(2);
+ }
+ free(configname); configname = NULL;
+ }
+ if( parse_debug && configname )
+ log_info(_("reading options from `%s'\n"), configname );
+ default_config = 0;
+ }
+
+ while( optfile_parse( configfp, configname, &configlineno,
+ &pargs, opts) ) {
+ switch( pargs.r_opt ) {
+ case oQuiet: opt.quiet = 1; break;
+ case oVerbose: opt.verbose++; break;
+
+ case oDebug: opt.debug |= pargs.r.ret_ulong; break;
+ case oDebugAll: opt.debug = ~0; break;
+
+ case oOptions:
+ /* config files may not be nested (silently ignore them) */
+ if( !configfp ) {
+ free(configname);
+ configname = xstrdup(pargs.r.ret_str);
+ goto next_pass;
+ }
+ break;
+ case oNoGreeting: nogreeting = 1; break;
+ case oNoVerbose: opt.verbose = 0; break;
+ case oNoOptions: break; /* no-options */
+ case oHomedir: opt.homedir = pargs.r.ret_str; break;
+ case oGPGBinary: break;
+
+ case oRegServer: action = 1; break;
+ case oUnregServer: action = 2; break;
+ case oEmbedding: action = 3; break;
+
+ default : pargs.err = configfp? 1:2; break;
+ }
+ }
+ if( configfp ) {
+ fclose( configfp );
+ configfp = NULL;
+ free(configname); configname = NULL;
+ goto next_pass;
+ }
+ free( configname ); configname = NULL;
+ if( log_get_errorcount(0) )
+ exit(2);
+ if( nogreeting )
+ greeting = 0;
+
+ if( greeting ) {
+ fprintf(stderr, "%s %s; %s\n",
+ strusage(11), strusage(13), strusage(14) );
+ fprintf(stderr, "%s\n", strusage(15) );
+ }
+ #ifdef IS_DEVELOPMENT_VERSION
+ log_info("NOTE: this is a development version!\n");
+ #endif
+
+ if ( action == 1 )
+ register_server ();
+ else if (action == 2 )
+ unregister_server ();
+ else if (action == 3 )
+ enter_complus ();
+ else {
+ fprintf (stderr, "This is a COM+ component with no user interface.\n"
+ "gpgme --help will give you a list of options\n" );
+ exit (1);
+ }
+
+ return 0;
+}
+
+static void
+register_server ()
+{
+}
+
+static void
+unregister_server ()
+{
+}
+
+static void
+enter_complus ()
+{
+ HANDLE running;
+ int reg;
+ void *factory;
+
+ /* CoInitializeEx (NULL, COINIT_MULTITHREADED); */
+ running = CreateEvent (NULL, FALSE, FALSE, NULL );
+
+ #if 0
+ factory = create_class_factory ();
+ CoRegisterClassObject (CLSID_gpgme, factory,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_SUSPENDED|REGCLASS_MULTIPLEUSE, ® );
+ CoResumeClassObjects ();
+ #endif
+
+ WaitForSingleObject ( running, INFINITE );
+ CloseHandle (running);
+ #if 0
+ CoRevokeClassObject ( reg );
+ factory->release ();
+ CoUnitialize ();
+ #endif
+}
+
+
+
+
+
+
--- /dev/null
+/* main.h - GPGME COM+ component
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef COMPLUS_MAIN_H
+#define COMPLUS_MAIN_H
+
+#include "xmalloc.h"
+#include "stringhelp.h"
+#include "logging.h"
+
+
+#define _(a) (a)
+#define N_(a) (a)
+
+
+struct {
+ int verbose;
+ int quiet;
+ unsigned int debug;
+ char *homedir;
+} opt;
+
+
+
+
+#endif /* COMPLUS_MAIN_H */
+
+
+
+
+
+
+
# AGE, set REVISION to 0.
# 3. Interfaces removed (BAD, breaks upward compatibility): Increment
# CURRENT, set AGE and REVISION to 0.
-AM_INIT_AUTOMAKE(gpgme,0.1.0)
+AM_INIT_AUTOMAKE(gpgme,0.1.1)
LIBGPGME_LT_CURRENT=0
LIBGPGME_LT_AGE=0
-LIBGPGME_LT_REVISION=2
+LIBGPGME_LT_REVISION=3
##############################################
AC_SUBST(LIBGPGME_LT_CURRENT)
fi
GPG=
+component_system=None
case "${target}" in
*-*-mingw32* | i?86-emx-os2 | i?86-*-os2*emx | i?86-*-msdosdjgpp* )
# special stuff for Windoze NT
AC_DEFINE(HAVE_DRIVE_LETTERS)
AC_DEFINE(HAVE_DOSISH_SYSTEM)
GPG='c:\\gnupg\\gpg.exe'
+ component_system='COM+'
;;
*)
;;
dnl
+
dnl
dnl Checks for typedefs and structures
dnl
+GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(ushort, HAVE_USHORT_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(ulong, HAVE_ULONG_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(u16, HAVE_U16_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(u32, HAVE_U32_TYPEDEF)
+# We should not use them in this software;
+# However jnlib/types.h needs them - so we take the easy way.
+AC_CHECK_SIZEOF(unsigned short, 2)
+AC_CHECK_SIZEOF(unsigned int, 4)
+AC_CHECK_SIZEOF(unsigned long, 4)
+if test "$ac_cv_sizeof_unsigned_short" = "0" \
+ || test "$ac_cv_sizeof_unsigned_int" = "0" \
+ || test "$ac_cv_sizeof_unsigned_long" = "0"; then
+ AC_MSG_WARN([Hmmm, something is wrong with the sizes - using defaults]);
+fi
+
+
dnl
dnl Checks for compiler features
dnl
dnl Checks for library functions
dnl
-AC_CHECK_FUNCS(stpcpy)
+dnl These are needed by libjnlib
+AC_CHECK_FUNCS(memicmp stpcpy strlwr strtoul memmove stricmp)
dnl
dnl Checks for system services
dnl
-if test -z "GPG"; then
+if test -z "$GPG"; then
AC_PATH_PROG(GPG, gpg)
if test -z "$GPG"; then
AC_MSG_ERROR([[
AC_DEFINE_UNQUOTED(GPG_PATH, "$GPG")
+dnl
+dnl FIXME: check whether Bonobo is installed
+dnl
+
+
dnl
dnl Create config files
dnl
dnl
+AM_CONDITIONAL(BUILD_COMPLUS, test "$component_system" = "COM+")
+AM_CONDITIONAL(BUILD_BONOBO, test "$component_system" = "Bonobo")
+
dnl Make the version number in gpgme/gpgme.h the same as the one here.
dnl (this is easier than to have a *.in file just for one substitution)
GNUPG_FIX_HDR_VERSION(gpgme/gpgme.h, GPGME_VERSION)
AC_OUTPUT([
Makefile
+jnlib/Makefile
gpgme/Makefile
gpgme/gpgme-config
tests/Makefile
+bonobo/Makefile
+complus/Makefile
])
+echo "
+ GPGME v${VERSION} has been configured as follows:
+
+ GPG path: $GPG
+ Component: $component_system
+"
int use_armor;
int use_textmode;
- /* GpgmePassphraseCb passphrase_cb;*/
- /* void * passphrase_cb_value;*/
-
ResultType result_type;
union {
VerifyResult verify;
GpgmeKey tmp_key; /* used by keylist.c */
volatile int key_cond; /* something new is available */
struct key_queue_item_s *key_queue;
+
+ char *prompt_1;
};
const char *data;
GpgmeDataType type;
GpgmeDataMode mode;
+
+ int (*read_cb)( void *, char *, size_t, size_t *);
+ void *read_cb_value;
+ int read_cb_eof;
+
size_t readpos;
size_t writepos;
size_t private_len;
return 0;
}
+
+GpgmeError
+gpgme_data_new_with_read_cb ( GpgmeData *r_dh,
+ int (*read_cb)(void*,char *,size_t,size_t*),
+ void *read_cb_value )
+{
+ GpgmeData dh;
+ GpgmeError err;
+
+ if (!r_dh || !read_cb)
+ return mk_error (Invalid_Value);
+ *r_dh = NULL;
+ err = gpgme_data_new ( &dh );
+ if (err)
+ return err;
+ dh->type = GPGME_DATA_TYPE_CB;
+ dh->mode = GPGME_DATA_MODE_OUT;
+ dh->read_cb = read_cb;
+ dh->read_cb_value = read_cb_value;
+
+ *r_dh = dh;
+ return 0;
+}
+
/**
* gpgme_data_new_from_file:
* @r_dh: returns the new data object
GpgmeDataType
gpgme_data_get_type ( GpgmeData dh )
{
- if ( !dh || !dh->data )
+ if ( !dh || (!dh->data && !dh->read_cb))
return GPGME_DATA_TYPE_NONE;
return dh->type;
{
if ( !dh )
return mk_error (Invalid_Value);
- /* Fixme: We should check whether rewinding does make sense for the
- * data type */
- dh->readpos = 0;
+
+ if (dh->type == GPGME_DATA_TYPE_MEM ) {
+ dh->readpos = 0;
+ }
+ else if (dh->type == GPGME_DATA_TYPE_CB) {
+ dh->len = dh->readpos = 0;
+ dh->read_cb_eof = 0;
+ /* FIXME: do a special call to the read function to trigger a rewind
+ there */
+ }
+ else
+ return mk_error (General_Error);
return 0;
}
* If there are no more bytes available %GPGME_EOF is returned and @nread
* is set to 0.
*
- * Return value: An errocodee or 0 on success, EOF is indcated by the
+ * Return value: An errorcode or 0 on success, EOF is indcated by the
* error code GPGME_EOF.
**/
GpgmeError
if ( !dh )
return mk_error (Invalid_Value);
- nbytes = dh->len - dh->readpos;
- if ( !nbytes ) {
- *nread = 0;
- return mk_error(EOF);
+ if (dh->type == GPGME_DATA_TYPE_MEM ) {
+ nbytes = dh->len - dh->readpos;
+ if ( !nbytes ) {
+ *nread = 0;
+ return mk_error(EOF);
+ }
+ if (nbytes > length)
+ nbytes = length;
+ memcpy ( buffer, dh->data + dh->readpos, nbytes );
+ *nread = nbytes;
+ dh->readpos += nbytes;
+ }
+ else if (dh->type == GPGME_DATA_TYPE_CB) {
+ nbytes = dh->len - dh->readpos;
+ if ( nbytes ) {
+ /* we have unread data - return this */
+ if (nbytes > length)
+ nbytes = length;
+ memcpy ( buffer, dh->data + dh->readpos, nbytes );
+ *nread = nbytes;
+ dh->readpos += nbytes;
+ }
+ else { /* get the data from the callback */
+ if (!dh->read_cb || dh->read_cb_eof) {
+ *nread = 0;
+ return mk_error (EOF);
+ }
+ if (dh->read_cb (dh->read_cb_value, buffer, length, nread )) {
+ *nread = 0;
+ dh->read_cb_eof = 1;
+ return mk_error (EOF);
+ }
+ }
}
- if (nbytes > length)
- nbytes = length;
- memcpy ( buffer, dh->data + dh->readpos, nbytes );
- *nread = nbytes;
- dh->readpos += nbytes;
+ else
+ return mk_error (General_Error);
return 0;
}
+GpgmeError
+_gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length )
+{
+ if ( !dh )
+ return mk_error (Invalid_Value);
+
+ if (dh->type == GPGME_DATA_TYPE_MEM ) {
+ /* check that we don't unread more than we have yet read */
+ if ( dh->readpos < length )
+ return mk_error (Invalid_Value);
+ /* No need to use the buffer for this data type */
+ dh->readpos -= length;
+ }
+ else {
+ return mk_error (General_Error);
+ }
+
+ return 0;
+}
+
+
/*
* This function does make sense when we know that it contains no nil chars.
*/
int no_passphrase;
int okay;
int failed;
+
};
}
+static GpgmeError
+create_result_struct ( GpgmeCtx ctx )
+{
+ assert ( !ctx->result.decrypt );
+ ctx->result.decrypt = xtrycalloc ( 1, sizeof *ctx->result.decrypt );
+ if ( !ctx->result.decrypt ) {
+ return mk_error (Out_Of_Core);
+ }
+ ctx->result_type = RESULT_TYPE_DECRYPT;
+ return 0;
+}
static void
decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
if ( ctx->out_of_core )
return;
if ( ctx->result_type == RESULT_TYPE_NONE ) {
- assert ( !ctx->result.decrypt );
- ctx->result.decrypt = xtrycalloc ( 1, sizeof *ctx->result.decrypt );
- if ( !ctx->result.decrypt ) {
+ if ( create_result_struct ( ctx ) ) {
ctx->out_of_core = 1;
return;
}
- ctx->result_type = RESULT_TYPE_DECRYPT;
}
assert ( ctx->result_type == RESULT_TYPE_DECRYPT );
case STATUS_NEED_PASSPHRASE:
case STATUS_NEED_PASSPHRASE_SYM:
- fprintf (stderr, "Ooops: Need a passphrase - use the agent\n");
+ fprintf (stderr, "need a passphrase ...\n" );
+ _gpgme_set_prompt (ctx, 1, "Hey! We need your passphrase!");
+ /* next thing gpg has to do is to read it from the passphrase-fd */
break;
case STATUS_MISSING_PASSPHRASE:
}
-
GpgmeError
-gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData ciph, GpgmeData plain )
+gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase,
+ GpgmeData ciph, GpgmeData plain )
{
int rc = 0;
int i;
_gpgme_gpg_add_arg ( c->gpg, "--decrypt" );
for ( i=0; i < c->verbosity; i++ )
_gpgme_gpg_add_arg ( c->gpg, "--verbose" );
-
+ if (passphrase) {
+ _gpgme_gpg_add_arg (c->gpg, "--passphrase-fd" );
+ _gpgme_gpg_add_data (c->gpg, passphrase, -2 );
+ }
+
+
/* Check the supplied data */
if ( !ciph || gpgme_data_get_type (ciph) == GPGME_DATA_TYPE_NONE ) {
rc = mk_error (No_Data);
goto leave;
}
-
_gpgme_data_set_mode (ciph, GPGME_DATA_MODE_OUT );
+
if ( gpgme_data_get_type (plain) != GPGME_DATA_TYPE_NONE ) {
rc = mk_error (Invalid_Value);
goto leave;
/**
* gpgme_op_decrypt:
* @c: The context
+ * @passphrase: A data object with the passphrase or NULL.
* @in: ciphertext input
* @out: plaintext output
*
* Return value: 0 on success or an errorcode.
**/
GpgmeError
-gpgme_op_decrypt ( GpgmeCtx c, GpgmeData in, GpgmeData out )
+gpgme_op_decrypt ( GpgmeCtx c, GpgmeData passphrase,
+ GpgmeData in, GpgmeData out )
{
- GpgmeError err = gpgme_op_decrypt_start ( c, in, out );
+ GpgmeError err = gpgme_op_decrypt_start ( c, passphrase, in, out );
if ( !err ) {
gpgme_wait (c, 1);
if ( c->result_type != RESULT_TYPE_DECRYPT )
--- /dev/null
+/* Generated automatically by mkerrors */
+/* Do not edit! */
+
+#include <stdio.h>
+#include "gpgme.h"
+
+/**
+ * gpgme_strerror:
+ * @err: Error code
+ *
+ * This function returns a textual representaion of the given
+ * errocode. If this is an unknown value, a string with the value
+ * is returned (which is hold in a static buffer).
+ *
+ * Return value: String with the error description.
+ **/
+const char *
+gpgme_strerror (GpgmeError err)
+{
+ const char *s;
+ static char buf[25];
+
+ switch (err) {
+ case GPGME_No_Error: s="No Error"; break;
+ case GPGME_General_Error: s="General Error"; break;
+ case GPGME_Out_Of_Core: s="Out Of Core"; break;
+ case GPGME_Invalid_Value: s="Invalid Value"; break;
+ case GPGME_Busy: s="Busy"; break;
+ case GPGME_No_Request: s="No Request"; break;
+ case GPGME_Exec_Error: s="Exec Error"; break;
+ case GPGME_Too_Many_Procs: s="Too Many Procs"; break;
+ case GPGME_Pipe_Error: s="Pipe Error"; break;
+ case GPGME_No_Recipients: s="No Recipients"; break;
+ case GPGME_No_Data: s="No Data"; break;
+ case GPGME_Conflict: s="Conflict"; break;
+ case GPGME_Not_Implemented: s="Not Implemented"; break;
+ case GPGME_Read_Error: s="Read Error"; break;
+ case GPGME_Write_Error: s="Write Error"; break;
+ case GPGME_Invalid_Type: s="Invalid Type"; break;
+ case GPGME_Invalid_Mode: s="Invalid Mode"; break;
+ case GPGME_File_Error: s="File Error"; break;
+ case GPGME_Decryption_Failed: s="Decryption Failed"; break;
+ case GPGME_No_Passphrase: s="No Passphrase"; break;
+ default: sprintf (buf, "ec=%d", err ); s=buf; break;
+}
+
+return s;
+}
+
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
#include "util.h"
#include "context.h"
_gpgme_key_release ( c->tmp_key );
gpgme_data_release ( c->notation );
/* fixme: release the key_queue */
- xfree ( c );
+ xfree (c->prompt_1);
+ xfree (c);
}
c->use_textmode = yes;
}
-#if 0
+/*
+ * The only which currently allowed is 1
+ */
void
-gpgme_set_passphrase_cb ( GpgmeCtx c, GpgmePassphraseCb fnc, void *fncval )
+_gpgme_set_prompt ( GpgmeCtx c, int which, const char *text )
{
- if ( c ) {
- c->passphrase_cb = fnc;
- c->passphrase_cb_value = fncval;
+ assert ( which == 1 );
+
+ xfree (c->prompt_1); c->prompt_1 = NULL;
+ if (text) {
+ c->prompt_1 = xtrystrdup (text);
+ if ( !c->prompt_1 )
+ c->out_of_core = 1;
}
}
-#endif
+
+const char *
+gpgme_get_prompt ( GpgmeCtx c, int which )
+{
+ if ( which != 1 )
+ return NULL;
+ return c->prompt_1;
+}
+
+
* let autoconf (using the AM_PATH_GPGME macro) check that this
* header matches the installed library.
* Warning: Do not edit the next line. configure will do that for you! */
-#define GPGME_VERSION "0.1.0"
+#define GPGME_VERSION "0.1.1"
GPGME_DATA_TYPE_NONE = 0,
GPGME_DATA_TYPE_MEM = 1,
GPGME_DATA_TYPE_FD = 2,
- GPGME_DATA_TYPE_FILE = 3
+ GPGME_DATA_TYPE_FILE = 3,
+ GPGME_DATA_TYPE_CB = 4
} GpgmeDataType;
typedef enum {
GPGME_SIG_STAT_ERROR = 5
} GpgmeSigStat;
-/*typedef GpgmeData (*GpgmePassphraseCb)( void *opaque, const char *desc );*/
-
/* Context management */
GpgmeError gpgme_new (GpgmeCtx *r_ctx);
char *gpgme_get_notation ( GpgmeCtx c );
void gpgme_set_armor ( GpgmeCtx c, int yes );
void gpgme_set_textmode ( GpgmeCtx c, int yes );
-/*void gpgme_set_passphrase_cb ( GpgmeCtx c,
- GpgmePassphraseCb fnc, void *fncval );*/
+
/* Functions to handle recipients */
GpgmeError gpgme_data_new_from_mem ( GpgmeData *r_dh,
const char *buffer, size_t size,
int copy );
+GpgmeError gpgme_data_new_with_read_cb ( GpgmeData *r_dh,
+ int (*read_cb)(void*,char *,size_t,size_t*),
+ void *read_cb_value );
+
GpgmeError gpgme_data_new_from_file ( GpgmeData *r_dh,
const char *fname,
int copy );
GpgmeError gpgme_op_encrypt_start ( GpgmeCtx c,
GpgmeRecipients recp,
GpgmeData in, GpgmeData out );
-GpgmeError gpgme_op_decrypt_start ( GpgmeCtx c,
+GpgmeError gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase,
GpgmeData ciph, GpgmeData plain );
GpgmeError gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out );
GpgmeError gpgme_op_verify_start ( GpgmeCtx c,
/* Convenience functions for normal usage */
GpgmeError gpgme_op_encrypt ( GpgmeCtx c, GpgmeRecipients recp,
GpgmeData in, GpgmeData out );
-GpgmeError gpgme_op_decrypt ( GpgmeCtx c, GpgmeData in, GpgmeData out );
+GpgmeError gpgme_op_decrypt ( GpgmeCtx c, GpgmeData passphrase,
+ GpgmeData in, GpgmeData out );
GpgmeError gpgme_op_sign ( GpgmeCtx c, GpgmeData in, GpgmeData out );
GpgmeError gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
GpgmeSigStat *r_status );
/* miscellaneous functions */
const char *gpgme_check_version ( const char *req_version );
const char *gpgme_strerror (GpgmeError err);
+const char *gpgme_get_prompt ( GpgmeCtx c, int which );
#ifdef __cplusplus
struct io_select_fd_s {
int fd;
+ int is_closed;
int for_read;
int for_write;
int signaled;
int _gpgme_io_read ( int fd, void *buffer, size_t count );
int _gpgme_io_write ( int fd, const void *buffer, size_t count );
-int _gpgme_io_pipe ( int filedes[2] );
+int _gpgme_io_pipe ( int filedes[2], int inherit_idx );
int _gpgme_io_close ( int fd );
int _gpgme_io_set_nonblocking ( int fd );
int _gpgme_io_spawn ( const char *path, char **argv,
/*-- gpgme.c --*/
void _gpgme_release_result ( GpgmeCtx c );
+void _gpgme_set_prompt ( GpgmeCtx c, int which, const char *text );
/*-- wait.c --*/
GpgmeCtx _gpgme_wait_on_condition ( GpgmeCtx c,
GpgmeError _gpgme_data_append_percentstring_for_xml ( GpgmeData dh,
const char *string );
+GpgmeError _gpgme_data_unread (GpgmeData dh,
+ const char *buffer, size_t length );
+
/*-- key.c --*/
GpgmeError _gpgme_key_new( GpgmeKey *r_key );
}
int
-_gpgme_io_pipe ( int filedes[2] )
+_gpgme_io_pipe ( int filedes[2], int inherit_idx )
{
+ /* we don't need inherit_idx in this implementation */
return pipe ( filedes );
}
#include "status-table.h"
+
/* This type is used to build a list of gpg arguments and
* data sources/sinks */
struct arg_and_data_s {
struct arg_and_data_s *next;
GpgmeData data; /* If this is not NULL .. */
int dup_to;
+ int print_fd; /* print the fd number and not the special form of it */
char arg[1]; /* .. this is used */
};
}
/* In any case we need a status pipe - create it right here and
* don't handle it with our generic GpgmeData mechanism */
- if (_gpgme_io_pipe (gpg->status.fd) == -1) {
+ if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) {
rc = mk_error (Pipe_Error);
goto leave;
}
_gpgme_gpg_add_arg ( gpg, "--batch" );
_gpgme_gpg_add_arg ( gpg, "--no-tty" );
+
leave:
if (rc) {
_gpgme_gpg_release (gpg);
xfree (gpg->colon.buffer);
if ( gpg->argv )
free_argv (gpg->argv);
+ #if 0
+ /* fixme: We need a way to communicate back closed fds, so that we
+ * don't do it a second time. One way to do it is by using a global
+ * table of open fds associated with gpg objects - but this requires
+ * additional locking. */
if (gpg->status.fd[0] != -1 )
_gpgme_io_close (gpg->status.fd[0]);
if (gpg->status.fd[1] != -1 )
_gpgme_io_close (gpg->colon.fd[0]);
if (gpg->colon.fd[1] != -1 )
_gpgme_io_close (gpg->colon.fd[1]);
+ #endif
free_fd_data_map (gpg->fd_data_map);
kill_gpg (gpg); /* fixme: should be done asyncronously */
xfree (gpg);
}
a->next = NULL;
a->data = data;
- a->dup_to = dup_to;
+ if ( dup_to == -2 ) {
+ a->print_fd = 1;
+ a->dup_to = -1;
+ }
+ else {
+ a->print_fd = 0;
+ a->dup_to = dup_to;
+ }
*gpg->argtail = a;
gpg->argtail = &a->next;
return 0;
if (!gpg->colon.buffer) {
return mk_error (Out_Of_Core);
}
- if (_gpgme_io_pipe (gpg->colon.fd) == -1) {
+ if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) {
xfree (gpg->colon.buffer); gpg->colon.buffer = NULL;
return mk_error (Pipe_Error);
}
{
int i;
+ if ( !fd_data_map )
+ return;
+
for (i=0; fd_data_map[i].data; i++ ) {
+#if 0 /* fixme -> see gpg_release */
if ( fd_data_map[i].fd != -1 )
_gpgme_io_close (fd_data_map[i].fd);
if ( fd_data_map[i].peer_fd != -1 )
_gpgme_io_close (fd_data_map[i].peer_fd);
+#endif
/* don't realease data because this is only a reference */
}
xfree (fd_data_map);
if (a->data) {
/*fprintf (stderr, "build_argv: data\n" );*/
datac++;
- if ( a->dup_to == -1 )
+ if ( a->dup_to == -1 && !a->print_fd )
need_special = 1;
}
else {
free_argv (argv);
return mk_error (Invalid_Type);
case GPGME_DATA_TYPE_MEM:
+ case GPGME_DATA_TYPE_CB:
break;
case GPGME_DATA_TYPE_FD:
case GPGME_DATA_TYPE_FILE:
{
int fds[2];
- if (_gpgme_io_pipe (fds) == -1) {
+ if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 )
+ == -1) {
xfree (fd_data_map);
free_argv (argv);
return mk_error (Pipe_Error);
free_argv (argv);
return mk_error (Out_Of_Core);
}
- sprintf ( argv[argc], "-&%d", fd_data_map[datac].peer_fd );
+ sprintf ( argv[argc],
+ a->print_fd? "%d" : "-&%d",
+ fd_data_map[datac].peer_fd );
argc++;
}
datac++;
/* build the fd list for the child */
n=0;
- fd_child_list[n].fd = gpg->status.fd[0];
+ fd_child_list[n].fd = gpg->status.fd[0];
fd_child_list[n].dup_to = -1;
n++;
if ( gpg->colon.fnc ) {
fd_parent_list[n].dup_to = -1;
- fflush (stderr);
pid = _gpgme_io_spawn (GPG_PATH, gpg->argv, fd_child_list, fd_parent_list);
xfree (fd_child_list);
if (pid == -1) {
assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
nread = _gpgme_io_read (fd, buf, 200 );
- fprintf(stderr, "inbound on fd %d: nread=%d\n", fd, nread );
if ( nread < 0 ) {
fprintf (stderr, "read_mem_data: read failed on fd %d (n=%d): %s\n",
fd, nread, strerror (errno) );
nbytes = dh->len - dh->readpos;
if ( !nbytes ) {
- fprintf (stderr, "write_mem_data(%d): closing\n", fd );
_gpgme_io_close (fd);
return 1;
}
* To avoid that we have set the pipe to nonblocking.
*/
-
- fprintf (stderr, "write_mem_data(%d): about to write %d bytes len=%d rpos=%d\n",
- fd, (int)nbytes, (int)dh->len, dh->readpos );
nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
- fprintf (stderr, "write_mem_data(%d): wrote %d bytes\n", fd, nwritten );
if (nwritten == -1 && errno == EAGAIN )
return 0;
if ( nwritten < 1 ) {
return 0;
}
+static int
+write_cb_data ( GpgmeData dh, int fd )
+{
+ size_t nbytes;
+ int err, nwritten;
+ char buffer[512];
+
+ err = gpgme_data_read ( dh, buffer, DIM(buffer), &nbytes );
+ if (err == GPGME_EOF) {
+ _gpgme_io_close (fd);
+ return 1;
+ }
+
+ nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
+ if (nwritten == -1 && errno == EAGAIN )
+ return 0;
+ if ( nwritten < 1 ) {
+ fprintf (stderr, "write_cb_data(%d): write failed (n=%d): %s\n",
+ fd, nwritten, strerror (errno) );
+ _gpgme_io_close (fd);
+ return 1;
+ }
+
+ if ( nwritten < nbytes ) {
+ if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) )
+ fprintf (stderr, "wite_cb_data: unread of %d bytes failed\n",
+ nbytes - nwritten );
+ _gpgme_io_close (fd);
+ return 1;
+ }
+
+ return 0;
+}
+
static int
gpg_outbound_handler ( void *opaque, int pid, int fd )
if ( write_mem_data ( dh, fd ) )
return 1; /* ready */
break;
+ case GPGME_DATA_TYPE_CB:
+ if (write_cb_data (dh, fd))
+ return 1; /* ready */
+ break;
default:
assert (0);
}
-
return 0;
}
--- /dev/null
+/* Generated automatically by mkstatus */
+/* Do not edit! */
+
+struct status_table_s {
+ const char *name;
+ GpgStatusCode code;
+};
+
+static struct status_table_s status_table[] =
+{
+ { "ABORT", STATUS_ABORT },
+ { "BADARMOR", STATUS_BADARMOR },
+ { "BADMDC", STATUS_BADMDC },
+ { "BADSIG", STATUS_BADSIG },
+ { "BAD_PASSPHRASE", STATUS_BAD_PASSPHRASE },
+ { "BEGIN_DECRYPTION", STATUS_BEGIN_DECRYPTION },
+ { "BEGIN_ENCRYPTION", STATUS_BEGIN_ENCRYPTION },
+ { "DECRYPTION_FAILED", STATUS_DECRYPTION_FAILED },
+ { "DECRYPTION_OKAY", STATUS_DECRYPTION_OKAY },
+ { "DELETE_PROBLEM", STATUS_DELETE_PROBLEM },
+ { "ENC_TO", STATUS_ENC_TO },
+ { "END_DECRYPTION", STATUS_END_DECRYPTION },
+ { "END_ENCRYPTION", STATUS_END_ENCRYPTION },
+ { "ENTER", STATUS_ENTER },
+ { "ERRMDC", STATUS_ERRMDC },
+ { "ERRSIG", STATUS_ERRSIG },
+ { "FILE_DONE", STATUS_FILE_DONE },
+ { "FILE_ERROR", STATUS_FILE_ERROR },
+ { "FILE_START", STATUS_FILE_START },
+ { "GET_BOOL", STATUS_GET_BOOL },
+ { "GET_HIDDEN", STATUS_GET_HIDDEN },
+ { "GET_LINE", STATUS_GET_LINE },
+ { "GOODMDC", STATUS_GOODMDC },
+ { "GOODSIG", STATUS_GOODSIG },
+ { "GOOD_PASSPHRASE", STATUS_GOOD_PASSPHRASE },
+ { "GOT_IT", STATUS_GOT_IT },
+ { "IMPORTED", STATUS_IMPORTED },
+ { "IMPORT_RES", STATUS_IMPORT_RES },
+ { "KEYREVOKED", STATUS_KEYREVOKED },
+ { "LEAVE", STATUS_LEAVE },
+ { "MISSING_PASSPHRASE", STATUS_MISSING_PASSPHRASE },
+ { "NEED_PASSPHRASE", STATUS_NEED_PASSPHRASE },
+ { "NEED_PASSPHRASE_SYM,", STATUS_NEED_PASSPHRASE_SYM, },
+ { "NODATA", STATUS_NODATA },
+ { "NOTATION_DATA", STATUS_NOTATION_DATA },
+ { "NOTATION_NAME", STATUS_NOTATION_NAME },
+ { "NO_PUBKEY", STATUS_NO_PUBKEY },
+ { "NO_SECKEY", STATUS_NO_SECKEY },
+ { "POLICY_URL", STATUS_POLICY_URL },
+ { "PROGRESS", STATUS_PROGRESS },
+ { "RSA_OR_IDEA", STATUS_RSA_OR_IDEA },
+ { "SESSION_KEY", STATUS_SESSION_KEY },
+ { "SHM_GET", STATUS_SHM_GET },
+ { "SHM_GET_BOOL", STATUS_SHM_GET_BOOL },
+ { "SHM_GET_HIDDEN", STATUS_SHM_GET_HIDDEN },
+ { "SHM_INFO", STATUS_SHM_INFO },
+ { "SIGEXPIRED", STATUS_SIGEXPIRED },
+ { "SIG_CREATED", STATUS_SIG_CREATED },
+ { "SIG_ID", STATUS_SIG_ID },
+ { "TRUST_FULLY", STATUS_TRUST_FULLY },
+ { "TRUST_MARGINAL", STATUS_TRUST_MARGINAL },
+ { "TRUST_NEVER", STATUS_TRUST_NEVER },
+ { "TRUST_ULTIMATE", STATUS_TRUST_ULTIMATE },
+ { "TRUST_UNDEFINED", STATUS_TRUST_UNDEFINED },
+ { "VALIDSIG", STATUS_VALIDSIG },
+ {NULL, 0}
+};
+
_gpgme_gpg_add_arg ( c->gpg, "--verify" );
for ( i=0; i < c->verbosity; i++ )
_gpgme_gpg_add_arg ( c->gpg, "--verbose" );
-
/* Check the supplied data */
if ( gpgme_data_get_type (sig) == GPGME_DATA_TYPE_NONE ) {
/* Tell the gpg object about the data */
_gpgme_gpg_add_arg ( c->gpg, "--" );
_gpgme_gpg_add_data ( c->gpg, sig, -1 );
- if (text)
+ if (text) {
+ _gpgme_gpg_add_arg ( c->gpg, "-" );
_gpgme_gpg_add_data ( c->gpg, text, 0 );
+ }
/* and kick off the process */
rc = _gpgme_gpg_spawn ( c->gpg, c );
--- /dev/null
+/* version.c - version check
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "gpgme.h"
+
+static const char*
+parse_version_number ( const char *s, int *number )
+{
+ int val = 0;
+
+ if ( *s == '0' && isdigit(s[1]) )
+ return NULL; /* leading zeros are not allowed */
+ for ( ; isdigit(*s); s++ ) {
+ val *= 10;
+ val += *s - '0';
+ }
+ *number = val;
+ return val < 0? NULL : s;
+}
+
+
+static const char *
+parse_version_string( const char *s, int *major, int *minor, int *micro )
+{
+ s = parse_version_number ( s, major );
+ if ( !s || *s != '.' )
+ return NULL;
+ s++;
+ s = parse_version_number ( s, minor );
+ if ( !s || *s != '.' )
+ return NULL;
+ s++;
+ s = parse_version_number ( s, micro );
+ if ( !s )
+ return NULL;
+ return s; /* patchlevel */
+}
+
+/**
+ * gpgme_check_version:
+ * @req_version: A string with a version
+ *
+ * Check that the the version of the library is at minimum the requested one
+ * and return the version string; return NULL if the condition is not
+ * met. If a NULL is passed to this function, no check is done and
+ * the version string is simply returned.
+ *
+ * Return value: The version string or NULL
+ **/
+const char *
+gpgme_check_version ( const char *req_version )
+{
+ const char *ver = VERSION;
+ int my_major, my_minor, my_micro;
+ int rq_major, rq_minor, rq_micro;
+ const char *my_plvl, *rq_plvl;
+
+ if ( !req_version )
+ return ver;
+
+ my_plvl = parse_version_string ( ver, &my_major, &my_minor, &my_micro );
+ if ( !my_plvl )
+ return NULL; /* very strange: our own version is bogus */
+ rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor,
+ &rq_micro );
+ if ( !rq_plvl )
+ return NULL; /* req version string is invalid */
+
+ if ( my_major > rq_major
+ || (my_major == rq_major && my_minor > rq_minor)
+ || (my_major == rq_major && my_minor == rq_minor
+ && my_micro > rq_micro)
+ || (my_major == rq_major && my_minor == rq_minor
+ && my_micro == rq_micro
+ && strcmp( my_plvl, rq_plvl ) >= 0) ) {
+ return ver;
+ }
+ return NULL;
+}
+
+
+
#include "util.h"
#include "io.h"
-#define DEBUG_SELECT_ENABLED 1
+#define DEBUG_SELECT_ENABLED 0
#if DEBUG_SELECT_ENABLED
# define DEBUG_SELECT(a) fprintf a
/*
- * We assume that a HANDLE can be represented by an int which should be true
+ * We assume that a HANDLE can be represented by an int which should be true
* for all i386 systems (HANDLE is defined as void *) and these are the only
* systems for which Windows is available.
* Further we assume that -1 denotes an invalid handle.
int nread = 0;
HANDLE h = fd_to_handle (fd);
+ DEBUG_SELECT ((stderr,"** fd %d: about to read %d bytes\n", fd, (int)count ));
if ( !ReadFile ( h, buffer, count, &nread, NULL) ) {
fprintf (stderr, "** ReadFile failed: ec=%d\n", (int)GetLastError ());
return -1;
}
+ DEBUG_SELECT ((stderr,"** fd %d: got %d bytes\n", fd, nread ));
return nread;
}
int nwritten;
HANDLE h = fd_to_handle (fd);
+ DEBUG_SELECT ((stderr,"** fd %d: about to write %d bytes\n", fd, (int)count ));
if ( !WriteFile ( h, buffer, count, &nwritten, NULL) ) {
fprintf (stderr, "** WriteFile failed: ec=%d\n", (int)GetLastError ());
return -1;
}
+ DEBUG_SELECT ((stderr,"** fd %d: wrote %d bytes\n", fd, nwritten ));
return nwritten;
}
int
-_gpgme_io_pipe ( int filedes[2] )
+_gpgme_io_pipe ( int filedes[2], int inherit_idx )
{
HANDLE r, w;
+ SECURITY_ATTRIBUTES sec_attr;
+
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
- if (!CreatePipe ( &r, &w, NULL, 0))
+ if (!CreatePipe ( &r, &w, &sec_attr, 0))
return -1;
+ /* make one end inheritable */
+ if ( inherit_idx == 0 ) {
+ HANDLE h;
+ if (!DuplicateHandle( GetCurrentProcess(), r,
+ GetCurrentProcess(), &h, 0,
+ TRUE, DUPLICATE_SAME_ACCESS ) ) {
+ fprintf (stderr, "** DuplicateHandle failed: ec=%d\n",
+ (int)GetLastError());
+ CloseHandle (r);
+ CloseHandle (w);
+ return -1;
+ }
+ CloseHandle (r);
+ r = h;
+ }
+ else if ( inherit_idx == 1 ) {
+ HANDLE h;
+ if (!DuplicateHandle( GetCurrentProcess(), w,
+ GetCurrentProcess(), &h, 0,
+ TRUE, DUPLICATE_SAME_ACCESS ) ) {
+ fprintf (stderr, "** DuplicateHandle failed: ec=%d\n",
+ (int)GetLastError());
+ CloseHandle (r);
+ CloseHandle (w);
+ return -1;
+ }
+ CloseHandle (w);
+ w = h;
+ }
+
filedes[0] = handle_to_fd (r);
filedes[1] = handle_to_fd (w);
+ DEBUG_SELECT ((stderr,"** create pipe %p %p %d %d inherit=%d\n", r, w,
+ filedes[0], filedes[1], inherit_idx ));
return 0;
}
{
if ( fd == -1 )
return -1;
- return CloseHandle (fd_to_handle(fd)) ? 0 : -1;
+
+ DEBUG_SELECT ((stderr,"** closing handle for fd %d\n", fd));
+ if ( !CloseHandle (fd_to_handle (fd)) ) {
+ fprintf (stderr, "** CloseHandle for fd %d failed: ec=%d\n",
+ fd, (int)GetLastError ());
+ return -1;
+ }
+
+ return 0;
}
* program parses the commandline and does some unquoting */
for (i=0; argv[i]; i++)
n += strlen (argv[i]) + 1;
- n += 5; /* "gpg " */
buf = p = xtrymalloc (n);
if ( !buf )
return NULL;
- p = stpcpy (p, "gpg");
- for (i = 0; argv[i]; i++)
+ *buf = 0;
+ if ( argv[0] )
+ p = stpcpy (p, argv[0]);
+ for (i = 1; argv[i]; i++)
p = stpcpy (stpcpy (p, " "), argv[i]);
return buf;
0, /* returns pid */
0 /* returns tid */
};
- STARTUPINFO si = {
- 0, NULL, NULL, NULL,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- NULL, NULL, NULL, NULL
- };
+ STARTUPINFO si;
char *envblock = NULL;
int cr_flags = CREATE_DEFAULT_ERROR_MODE
| GetPriorityClass (GetCurrentProcess ());
- int i, rc;
+ int i;
char *arg_string;
- HANDLE save_stdout;
- HANDLE outputfd[2], statusfd[2], inputfd[2];
+ int duped_stdin = 0;
+ int duped_stderr = 0;
+ HANDLE hnul = INVALID_HANDLE_VALUE;
- sec_attr.nLength = sizeof (sec_attr);
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
- sec_attr.lpSecurityDescriptor = NULL;
-
arg_string = build_commandline ( argv );
if (!arg_string )
return -1;
+ memset (&si, 0, sizeof si);
si.cb = sizeof (si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
- if (!SetHandleInformation (si.hStdOutput,
- HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
- fprintf (stderr, "** SHI 1 failed: ec=%d\n", (int) GetLastError ());
+
+ for (i=0; fd_child_list[i].fd != -1; i++ ) {
+ if (fd_child_list[i].dup_to == 0 ) {
+ si.hStdInput = fd_to_handle (fd_child_list[i].fd);
+ DEBUG_SELECT ((stderr,"** using %d for stdin\n", fd_child_list[i].fd ));
+ duped_stdin=1;
+ }
+ else if (fd_child_list[i].dup_to == 1 ) {
+ si.hStdOutput = fd_to_handle (fd_child_list[i].fd);
+ DEBUG_SELECT ((stderr,"** using %d for stdout\n", fd_child_list[i].fd ));
+ }
+ else if (fd_child_list[i].dup_to == 2 ) {
+ si.hStdError = fd_to_handle (fd_child_list[i].fd);
+ DEBUG_SELECT ((stderr,"** using %d for stderr\n", fd_child_list[i].fd ));
+ duped_stderr = 1;
+ }
}
- if (!SetHandleInformation (si.hStdError,
- HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
- fprintf (stderr, "** SHI 2 failed: ec=%d\n", (int) GetLastError ());
+
+ if( !duped_stdin || !duped_stderr ) {
+ SECURITY_ATTRIBUTES sa;
+
+ memset (&sa, 0, sizeof sa );
+ sa.nLength = sizeof sa;
+ sa.bInheritHandle = TRUE;
+ hnul = CreateFile ( "/dev/nul",
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if ( hnul == INVALID_HANDLE_VALUE ) {
+ fprintf (stderr,"can't open `/dev/nul': ec=%d\n",
+ (int)GetLastError () );
+ xfree (arg_string);
+ return -1;
+ }
+ /* Make sure that the process has a connected stdin */
+ if ( !duped_stdin ) {
+ si.hStdInput = hnul;
+ DEBUG_SELECT ((stderr,"** using %d for stdin\n", (int)hnul ));
+ }
+ /* We normally don't want all the normal output */
+ if ( !duped_stderr ) {
+ if (!getenv ("GPGME_DEBUG") ) {
+ si.hStdError = hnul;
+ DEBUG_SELECT ((stderr,"** using %d for stderr\n", (int)hnul ));
+ }
+ }
}
-
- fputs ("** CreateProcess ...\n", stderr);
- fprintf (stderr, "** args=`%s'\n", arg_string);
- fflush (stderr);
+ DEBUG_SELECT ((stderr,"** CreateProcess ...\n"));
+ DEBUG_SELECT ((stderr,"** args=`%s'\n", arg_string));
+ cr_flags |= CREATE_SUSPENDED;
if ( !CreateProcessA (GPG_PATH,
arg_string,
&sec_attr, /* process security attributes */
) ) {
fprintf (stderr, "** CreateProcess failed: ec=%d\n",
(int) GetLastError ());
- fflush (stderr);
xfree (arg_string);
return -1;
}
- /* .dup_to is not used in the parent list */
+ /* close the /dev/nul handle if used */
+ if (hnul != INVALID_HANDLE_VALUE ) {
+ if ( !CloseHandle ( hnul ) )
+ fprintf (stderr, "** CloseHandle(hnul) failed: ec=%d\n",
+ (int)GetLastError());
+ }
+
+ /* Close the other ends of the pipes */
for (i=0; fd_parent_list[i].fd != -1; i++ ) {
- CloseHandle ( fd_to_handle (fd_parent_list[i].fd) );
+ DEBUG_SELECT ((stderr,"** Closing fd %d\n", fd_parent_list[i].fd ));
+ if ( !CloseHandle ( fd_to_handle (fd_parent_list[i].fd) ) )
+ fprintf (stderr, "** CloseHandle failed: ec=%d\n",
+ (int)GetLastError());
}
- fprintf (stderr, "** CreateProcess ready\n");
- fprintf (stderr, "** hProcess=%p hThread=%p\n",
- pi.hProcess, pi.hThread);
- fprintf (stderr, "** dwProcessID=%d dwThreadId=%d\n",
- (int) pi.dwProcessId, (int) pi.dwThreadId);
- fflush (stderr);
+ DEBUG_SELECT ((stderr,"** CreateProcess ready\n"
+ "** hProcess=%p hThread=%p\n"
+ "** dwProcessID=%d dwThreadId=%d\n",
+ pi.hProcess, pi.hThread,
+ (int) pi.dwProcessId, (int) pi.dwThreadId));
+
+ if ( ResumeThread ( pi.hThread ) < 0 ) {
+ fprintf (stderr, "** ResumeThread failed: ec=%d\n",
+ (int)GetLastError ());
+ }
+
+ if ( !CloseHandle (pi.hThread) ) {
+ fprintf (stderr, "** CloseHandle of thread failed: ec=%d\n",
+ (int)GetLastError ());
+ }
return handle_to_pid (pi.hProcess);
}
+
+
int
_gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
{
*r_status = 4;
}
else {
- fprintf (stderr, "** GECP pid=%d exit code=%d\n",
- (int)pid, exc);
+ DEBUG_SELECT ((stderr,"** GECP pid=%d exit code=%d\n",
+ (int)pid, exc));
*r_status = exc;
}
ret = 1;
break;
case WAIT_TIMEOUT:
- fprintf (stderr, "** WFSO pid=%d timed out\n", (int)pid);
+ DEBUG_SELECT ((stderr,"** WFSO pid=%d timed out\n", (int)pid));
break;
default:
int
_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
{
+#if 0 /* We can't use WFMO becaus a pipe handle is not a suitable object */
HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
int code, nwait;
- int i, any, ret;
+ int i, any, any_write;
+ int count;
+ restart:
DEBUG_SELECT ((stderr, "gpgme:select on [ "));
- any = 0;
+ any = any_write = 0;
nwait = 0;
for ( i=0; i < nfds; i++ ) {
if ( fds[i].fd == -1 )
continue;
if ( fds[i].for_read || fds[i].for_write ) {
if ( nwait >= DIM (waitbuf) ) {
- DEBUG_SELECT ((stderr, "oops ]\n" ));
+ DEBUG_SELECT ((stderr,stderr, "oops ]\n" ));
fprintf (stderr, "** Too many objects for WFMO!\n" );
return -1;
}
else {
- waitbuf[nwait++] = fd_to_handle (fds[i].fd);
+ if ( fds[i].for_read )
+ waitbuf[nwait++] = fd_to_handle (fds[i].fd);
DEBUG_SELECT ((stderr, "%c%d ",
fds[i].for_read? 'r':'w',fds[i].fd ));
any = 1;
fds[i].signaled = 0;
}
DEBUG_SELECT ((stderr, "]\n" ));
- if (!any)
+ if (!any)
return 0;
- ret = 0;
- code = WaitForMultipleObjects ( nwait, waitbuf, 0, 1000 );
+ count = 0;
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ if ( fds[i].for_write ) {
+ fds[i].signaled = 1;
+ any_write =1;
+ count++;
+ }
+ }
+ code = WaitForMultipleObjects ( nwait, waitbuf, 0, any_write? 0:1000);
if (code == WAIT_FAILED ) {
- fprintf (stderr, "** WFMO failed: %d\n", (int)GetLastError () );
- ret = -1;
+ int le = (int)GetLastError ();
+ if ( le == ERROR_INVALID_HANDLE || le == ERROR_INVALID_EVENT_COUNT ) {
+ any = 0;
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ if ( fds[i].for_read /*|| fds[i].for_write*/ ) {
+ int navail;
+ if (PeekNamedPipe (fd_to_handle (fds[i].fd),
+ NULL, 0, NULL,
+ &navail, NULL) && navail ) {
+ fds[i].signaled = 1;
+ any = 1;
+ count++;
+ }
+ }
+ }
+ if (any)
+ return count;
+ /* find that handle and remove it from the list*/
+ for (i=0; i < nwait; i++ ) {
+ code = WaitForSingleObject ( waitbuf[i], NULL );
+ if (!code) {
+ int k, j = handle_to_fd (waitbuf[i]);
+
+ fprintf (stderr, "** handle meanwhile signaled %d\n", j);
+ for (k=0 ; k < nfds; k++ ) {
+ if ( fds[k].fd == j ) {
+ fds[k].signaled = 1;
+ count++;
+ return count;
+ }
+ }
+ fprintf (stderr, "** oops, or not???\n");
+ }
+ if ( GetLastError () == ERROR_INVALID_HANDLE) {
+ int k, j = handle_to_fd (waitbuf[i]);
+
+ fprintf (stderr, "** WFMO invalid handle %d removed\n", j);
+ for (k=0 ; k < nfds; i++ ) {
+ if ( fds[k].fd == j ) {
+ fds[k].for_read = fds[k].for_write = 0;
+ goto restart;
+ }
+ }
+ fprintf (stderr, "** oops, or not???\n");
+ }
+ }
+ }
+
+ fprintf (stderr, "** WFMO failed: %d\n", le );
+ count = -1;
}
else if ( code == WAIT_TIMEOUT ) {
fprintf (stderr, "** WFMO timed out\n" );
if (WaitForSingleObject ( waitbuf[i], NULL ) == WAIT_OBJECT_0) {
fds[i].signaled = 1;
any = 1;
+ count++;
}
}
- if (any)
- ret = 1;
- else {
+ if (!any) {
fprintf (stderr,
"** Oops: No signaled objects found after WFMO\n");
- ret = -1;
+ count = -1;
}
}
else {
fprintf (stderr, "** WFMO returned %d\n", code );
- ret = -1;
+ count = -1;
}
- return ret;
+ return count;
+#else /* This is the code we use */
+ int i, any, count;
+ int once_more = 0;
+
+ DEBUG_SELECT ((stderr, "gpgme:fakedselect on [ "));
+ any = 0;
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ if ( fds[i].for_read || fds[i].for_write ) {
+ DEBUG_SELECT ((stderr, "%c%d ",
+ fds[i].for_read? 'r':'w',fds[i].fd ));
+ any = 1;
+ }
+ fds[i].signaled = 0;
+ }
+ DEBUG_SELECT ((stderr, "]\n" ));
+ if (!any)
+ return 0;
+
+ restart:
+ count = 0;
+ /* no way to see whether a handle is ready fro writing, signal all */
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ if ( fds[i].for_write ) {
+ fds[i].signaled = 1;
+ count++;
+ }
+ }
+
+ /* now peek on all read handles */
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ if ( fds[i].for_read ) {
+ int navail;
+
+ if ( !PeekNamedPipe (fd_to_handle (fds[i].fd),
+ NULL, 0, NULL, &navail, NULL) ) {
+ fprintf (stderr, "** select: PeekFile failed: ec=%d\n",
+ (int)GetLastError ());
+ }
+ else if ( navail ) {
+ fprintf (stderr, "** fd %d has %d bytes to read\n",
+ fds[i].fd, navail );
+ fds[i].signaled = 1;
+ count++;
+ }
+ }
+ }
+ if ( !once_more && !count ) {
+ once_more = 1;
+ Sleep (300);
+ goto restart;
+ }
+
+ if ( count ) {
+ DEBUG_SELECT ((stderr, "gpgme: signaled [ "));
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) {
+ DEBUG_SELECT ((stderr, "%c%d ",
+ fds[i].for_read? 'r':'w',fds[i].fd ));
+ }
+ }
+ DEBUG_SELECT ((stderr, "]\n" ));
+ }
+
+ return count;
+#endif
}
#endif /*HAVE_DOSISH_SYSTEM*/
return count;
}
+static void
+clear_active_fds ( int pid )
+{
+ struct wait_item_s *q;
+ int i;
+
+ for (i=0; i < fd_table_size; i++ ) {
+ if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque)
+ && q->active && q->pid == pid )
+ q->active = 0;
+ }
+}
+
/* remove the given process from the queue */
static void
if (fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->pid == pid ) {
xfree (q);
fd_table[i].opaque = NULL;
- _gpgme_io_close (fd_table[i].fd);
+
+ if ( !fd_table[i].is_closed ) {
+ _gpgme_io_close (fd_table[i].fd);
+ fd_table[i].is_closed = 1;
+ }
fd_table[i].fd = -1;
}
}
q = queue_item_from_context ( c );
assert (q);
- if (q->exited)
- ;
+ if (q->exited) {
+ /* this is the second time we reached this and we got no
+ * more data from the pipe (which may happen to to buffering).
+ * Set all FDs inactive.
+ */
+ clear_active_fds (q->pid);
+ }
else if ( _gpgme_io_waitpid (q->pid, 0,
&q->exit_status, &q->exit_signal)){
q->exited = 1;
{
struct wait_item_s *q;
int i, n;
+ int any=0;
n = _gpgme_io_select ( fd_table, fd_table_size );
if ( n <= 0 )
return 0; /* error or timeout */
- for (i=0; i < fd_table_size && n; i++ ) {
+ for (i=0; i < fd_table_size /*&& n*/; i++ ) {
if ( fd_table[i].fd != -1 && fd_table[i].signaled ) {
q = fd_table[i].opaque;
assert (n);
n--;
+ if ( q->active )
+ any = 1;
if ( q->active && q->handler (q->handler_value,
q->pid, fd_table[i].fd ) ) {
q->active = 0;
fd_table[i].for_read = 0;
fd_table[i].for_write = 0;
+ fd_table[i].is_closed = 1;
}
}
}
- return 1;
+ return any;
}
for (i=0; i < fd_table_size; i++ ) {
if ( fd_table[i].fd == -1 ) {
fd_table[i].fd = fd;
+ fd_table[i].is_closed = 0;
fd_table[i].for_read = inbound;
fd_table[i].for_write = !inbound;
fd_table[i].signaled = 0;
#include "../gpgme/gpgme.h"
+struct passphrase_cb_info_s {
+ GpgmeCtx c;
+ int did_it;
+};
+
+
#define fail_if_err(a) do { if(a) { int my_errno = errno; \
fprintf (stderr, "%s:%d: GpgmeError %s\n", \
__FILE__, __LINE__, gpgme_strerror(a)); \
fail_if_err (err);
}
-#if 0
-static GpgmeData
-passphrase_cb ( void *opaque, const char *description )
-{
- GpgmeData dh;
- assert (NULL);
- gpgme_data_new_from_mem ( &dh, "abc", 3, 0 );
- return dh;
+static int
+passphrase_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
+{
+ struct passphrase_cb_info_s *info = opaque;
+ const char *desc;
+
+ assert (info);
+ assert (info->c);
+ if ( !buffer || !length || !nread )
+ return 0; /* those values are reserved for extensions */
+ if ( info->did_it )
+ return -1; /* eof */
+
+ desc = gpgme_get_prompt (info->c, 1);
+ if (desc)
+ fprintf (stderr, "Request passphrase for '%s'\n", desc );
+ if ( length < 3 )
+ return -1; /* FIXME - sending an EOF here is wrong */
+ memcpy (buffer, "abc", 3 );
+ *nread = 3;
+ info->did_it = 1;
+ return 0;
}
-#endif
+
static char *
mk_fname ( const char *fname )
{
GpgmeCtx ctx;
GpgmeError err;
- GpgmeData in, out;
+ GpgmeData in, out, pwdata = NULL;
+ struct passphrase_cb_info_s info;
const char *cipher_1_asc = mk_fname ("cipher-1.asc");
do {
err = gpgme_new (&ctx);
fail_if_err (err);
-#if 0
- if ( !getenv("GPG_AGENT_INFO") {
- gpgme_set_passphrase_cb ( ctx, passphrase_cb, NULL );
+ if ( 0 && !getenv("GPG_AGENT_INFO") ) {
+ memset ( &info, 0, sizeof info );
+ info.c = ctx;
+ gpgme_data_new_with_read_cb ( &pwdata, passphrase_cb, &info );
}
-#endif
err = gpgme_data_new_from_file ( &in, cipher_1_asc, 1 );
fail_if_err (err);
err = gpgme_data_new ( &out );
fail_if_err (err);
- err = gpgme_op_decrypt (ctx, in, out );
+ err = gpgme_op_decrypt (ctx, pwdata, in, out );
fail_if_err (err);
fflush (NULL);
gpgme_data_release (in);
gpgme_data_release (out);
+ gpgme_data_release (pwdata);
gpgme_release (ctx);
} while ( argc > 1 && !strcmp( argv[1], "--loop" ) );