From 93e9f5ffe4465dec99991369db06f1326d92d7c2 Mon Sep 17 00:00:00 2001 From: Repo Admin Date: Mon, 20 Nov 2000 20:17:36 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create tag 'V0-1-0'. --- tags/V0-1-0/AUTHORS | 0 tags/V0-1-0/ChangeLog | 0 tags/V0-1-0/INSTALL | 182 ++++++ tags/V0-1-0/Makefile.am | 6 + tags/V0-1-0/NEWS | 0 tags/V0-1-0/README | 23 + tags/V0-1-0/README-alpha | 1 + tags/V0-1-0/acconfig.h | 54 ++ tags/V0-1-0/acinclude.m4 | 23 + tags/V0-1-0/configure.in | 110 ++++ tags/V0-1-0/gpgme/ChangeLog | 0 tags/V0-1-0/gpgme/Makefile.am | 38 ++ tags/V0-1-0/gpgme/context.h | 119 ++++ tags/V0-1-0/gpgme/data.c | 488 ++++++++++++++++ tags/V0-1-0/gpgme/decrypt.c | 196 +++++++ tags/V0-1-0/gpgme/encrypt.c | 132 +++++ tags/V0-1-0/gpgme/gpgme-config.in | 93 +++ tags/V0-1-0/gpgme/gpgme-memory.h | 36 ++ tags/V0-1-0/gpgme/gpgme-types.h | 38 ++ tags/V0-1-0/gpgme/gpgme.c | 138 +++++ tags/V0-1-0/gpgme/gpgme.h | 176 ++++++ tags/V0-1-0/gpgme/gpgme.m4 | 170 ++++++ tags/V0-1-0/gpgme/key.c | 287 +++++++++ tags/V0-1-0/gpgme/key.h | 54 ++ tags/V0-1-0/gpgme/keylist.c | 384 ++++++++++++ tags/V0-1-0/gpgme/mkerrors | 83 +++ tags/V0-1-0/gpgme/mkstatus | 55 ++ tags/V0-1-0/gpgme/ops.h | 77 +++ tags/V0-1-0/gpgme/recipient.c | 94 +++ tags/V0-1-0/gpgme/rungpg.c | 942 ++++++++++++++++++++++++++++++ tags/V0-1-0/gpgme/rungpg.h | 111 ++++ tags/V0-1-0/gpgme/sign.c | 190 ++++++ tags/V0-1-0/gpgme/types.h | 66 +++ tags/V0-1-0/gpgme/util.c | 63 ++ tags/V0-1-0/gpgme/util.h | 49 ++ tags/V0-1-0/gpgme/verify.c | 243 ++++++++ tags/V0-1-0/gpgme/wait.c | 391 +++++++++++++ tags/V0-1-0/gpgme/wait.h | 42 ++ tags/V0-1-0/tests/Makefile.am | 40 ++ tags/V0-1-0/tests/cipher-1.asc | 15 + tags/V0-1-0/tests/geheim.txt | 2 + tags/V0-1-0/tests/mkdemodirs | 44 ++ tags/V0-1-0/tests/t-decrypt.c | 121 ++++ tags/V0-1-0/tests/t-encrypt.c | 95 +++ tags/V0-1-0/tests/t-keylist.c | 87 +++ tags/V0-1-0/tests/t-sign.c | 89 +++ tags/V0-1-0/tests/t-verify.c | 144 +++++ 47 files changed, 5791 insertions(+) create mode 100644 tags/V0-1-0/AUTHORS create mode 100644 tags/V0-1-0/ChangeLog create mode 100644 tags/V0-1-0/INSTALL create mode 100644 tags/V0-1-0/Makefile.am create mode 100644 tags/V0-1-0/NEWS create mode 100644 tags/V0-1-0/README create mode 100644 tags/V0-1-0/README-alpha create mode 100644 tags/V0-1-0/acconfig.h create mode 100644 tags/V0-1-0/acinclude.m4 create mode 100644 tags/V0-1-0/configure.in create mode 100644 tags/V0-1-0/gpgme/ChangeLog create mode 100644 tags/V0-1-0/gpgme/Makefile.am create mode 100644 tags/V0-1-0/gpgme/context.h create mode 100644 tags/V0-1-0/gpgme/data.c create mode 100644 tags/V0-1-0/gpgme/decrypt.c create mode 100644 tags/V0-1-0/gpgme/encrypt.c create mode 100644 tags/V0-1-0/gpgme/gpgme-config.in create mode 100644 tags/V0-1-0/gpgme/gpgme-memory.h create mode 100644 tags/V0-1-0/gpgme/gpgme-types.h create mode 100644 tags/V0-1-0/gpgme/gpgme.c create mode 100644 tags/V0-1-0/gpgme/gpgme.h create mode 100644 tags/V0-1-0/gpgme/gpgme.m4 create mode 100644 tags/V0-1-0/gpgme/key.c create mode 100644 tags/V0-1-0/gpgme/key.h create mode 100644 tags/V0-1-0/gpgme/keylist.c create mode 100755 tags/V0-1-0/gpgme/mkerrors create mode 100755 tags/V0-1-0/gpgme/mkstatus create mode 100644 tags/V0-1-0/gpgme/ops.h create mode 100644 tags/V0-1-0/gpgme/recipient.c create mode 100644 tags/V0-1-0/gpgme/rungpg.c create mode 100644 tags/V0-1-0/gpgme/rungpg.h create mode 100644 tags/V0-1-0/gpgme/sign.c create mode 100644 tags/V0-1-0/gpgme/types.h create mode 100644 tags/V0-1-0/gpgme/util.c create mode 100644 tags/V0-1-0/gpgme/util.h create mode 100644 tags/V0-1-0/gpgme/verify.c create mode 100644 tags/V0-1-0/gpgme/wait.c create mode 100644 tags/V0-1-0/gpgme/wait.h create mode 100644 tags/V0-1-0/tests/Makefile.am create mode 100644 tags/V0-1-0/tests/cipher-1.asc create mode 100644 tags/V0-1-0/tests/geheim.txt create mode 100755 tags/V0-1-0/tests/mkdemodirs create mode 100644 tags/V0-1-0/tests/t-decrypt.c create mode 100644 tags/V0-1-0/tests/t-encrypt.c create mode 100644 tags/V0-1-0/tests/t-keylist.c create mode 100644 tags/V0-1-0/tests/t-sign.c create mode 100644 tags/V0-1-0/tests/t-verify.c diff --git a/tags/V0-1-0/AUTHORS b/tags/V0-1-0/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/tags/V0-1-0/ChangeLog b/tags/V0-1-0/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/tags/V0-1-0/INSTALL b/tags/V0-1-0/INSTALL new file mode 100644 index 0000000..b42a17a --- /dev/null +++ b/tags/V0-1-0/INSTALL @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/tags/V0-1-0/Makefile.am b/tags/V0-1-0/Makefile.am new file mode 100644 index 0000000..1b9784b --- /dev/null +++ b/tags/V0-1-0/Makefile.am @@ -0,0 +1,6 @@ + +EXTRA_DIST = README-alpha + +SUBDIRS = gpgme tests + + diff --git a/tags/V0-1-0/NEWS b/tags/V0-1-0/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/tags/V0-1-0/README b/tags/V0-1-0/README new file mode 100644 index 0000000..03cb718 --- /dev/null +++ b/tags/V0-1-0/README @@ -0,0 +1,23 @@ + GPGME - GnuPG Made Easy + --------------------------- + + !!!! THIS IS WORK IN PROGRESS !!! + +If you want to hack on it, start with one of the tests/t-foo programs. +You need the latest CVS version of GnuPG 1.0, see +http://www.gnupg.org/cvs-access.html . If you use passphrases for +your keys, you should get the gpg-agent which comes with the GnuPG +unstable version (either CVS HEAD or +ftp.gnupg.org/pub/gcrypt/alpha/gnupg/gnupg-1.1.2.tar.gz) and install +the agent from the agent subdirectory. + +Please subscribe to the gnupg-devel@gnupg.org mailing list if you want +to do serious work. + + + + + + + + diff --git a/tags/V0-1-0/README-alpha b/tags/V0-1-0/README-alpha new file mode 100644 index 0000000..0f748e3 --- /dev/null +++ b/tags/V0-1-0/README-alpha @@ -0,0 +1 @@ + THIS IS WORK IN PROGRESS !!!! \ No newline at end of file diff --git a/tags/V0-1-0/acconfig.h b/tags/V0-1-0/acconfig.h new file mode 100644 index 0000000..724fd6f --- /dev/null +++ b/tags/V0-1-0/acconfig.h @@ -0,0 +1,54 @@ +/* acconfig.h - used by autoheader to make config.h.in + * 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 GPGME_CONFIG_H +#define GPGME_CONFIG_H + +/* need this, because some autoconf tests rely on this (e.g. stpcpy) + * and it should be used for new programs */ +#define _GNU_SOURCE 1 +/* To allow the use of gpgme in multithreaded programs we have to use + * special features from the library. + * IMPORTANT: gpgme is not yet fully reentrant and you should use it + * only from one thread. */ +#define _REENTRANT 1 + +@TOP@ + + + +#undef HAVE_DRIVE_LETTERS +/* defined if we run on some of the PCDOS like systems (DOS, Windoze. OS/2) + * with special properties like no file modes */ +#undef HAVE_DOSISH_SYSTEM +/* because the Unix gettext has to much overhead on MingW32 systems + * and these systems lack Posix functions, we use a simplified version + * of gettext */ +#undef USE_SIMPLE_GETTEXT +/* Some systems have mkdir that takes a single argument. */ +#undef MKDIR_TAKES_ONE_ARG + +/* path to the gpg binary */ +#undef GPG_PATH + +@BOTTOM@ + +/* not yet needed #include "gpgme-defs.h"*/ + +#endif /*GPGME_CONFIG_H*/ diff --git a/tags/V0-1-0/acinclude.m4 b/tags/V0-1-0/acinclude.m4 new file mode 100644 index 0000000..296639b --- /dev/null +++ b/tags/V0-1-0/acinclude.m4 @@ -0,0 +1,23 @@ +dnl Macros to configure gpgme + +dnl GNUPG_FIX_HDR_VERSION(FILE, NAME) +dnl (wk 2000-11-17) +AC_DEFUN(GNUPG_FIX_HDR_VERSION, + [ sed "s/^#define $2 \".*/#define $2 \"$VERSION\"/" $srcdir/$1 > $srcdir/$1.tmp + if cmp -s $srcdir/$1 $srcdir/$1.tmp 2>/dev/null; then + rm -f $srcdir/$1.tmp + else + rm -f $srcdir/$1 + if mv $srcdir/$1.tmp $srcdir/$1 ; then + : + else + AC_MSG_ERROR([[ +*** Failed to fix the version string macro $2 in $1. +*** The old file has been saved as $1.tmp + ]]) + fi + AC_MSG_WARN([fixed the $2 macro in $1]) + fi + ]) + + diff --git a/tags/V0-1-0/configure.in b/tags/V0-1-0/configure.in new file mode 100644 index 0000000..3e23edf --- /dev/null +++ b/tags/V0-1-0/configure.in @@ -0,0 +1,110 @@ +# configure.in for GPGME +# +dnl (Process this file with autoconf to produce a configure script.) +AC_REVISION($Revision$)dnl + +AC_INIT(gpgme/gpgme.h) +AM_CONFIG_HEADER(config.h) +AM_MAINTAINER_MODE +############################################# +# Version numbers (Remember to change them just before a release) +# 1. No interfaces changed, only implementations (good): Increment REVISION. +# 2. Interfaces added, none removed (good): Increment CURRENT, increment +# 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) +LIBGPGME_LT_CURRENT=0 +LIBGPGME_LT_AGE=0 +LIBGPGME_LT_REVISION=2 +############################################## + +AC_SUBST(LIBGPGME_LT_CURRENT) +AC_SUBST(LIBGPGME_LT_AGE) +AC_SUBST(LIBGPGME_LT_REVISION) + +dnl +dnl Checks for programs +dnl +AC_ARG_PROGRAM + +dnl Don't default to build static libs +AM_DISABLE_STATIC +AM_PROG_LIBTOOL + +if test "$GCC" = yes; then + CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes" +fi + + +dnl +dnl Checks for libraries +dnl + +dnl +dnl Checks for header files +dnl + + +dnl +dnl Checks for typedefs and structures +dnl + +dnl +dnl Checks for compiler features +dnl + +dnl +dnl Checks for library functions +dnl + + +dnl +dnl Checks for system services +dnl + +AC_PATH_PROG(GPG, gpg) +if test -z "$GPG"; then + AC_MSG_ERROR([[ +*** +*** GnuPG not found. Please install GnuPG first. +*** See http://www.gnupg.org/download.html +*** +]]) +fi +AC_DEFINE_UNQUOTED(GPG_PATH, "$GPG") + + +dnl +dnl Create config files +dnl +dnl + +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) + +dnl Substitution used for gpgme-config +GPGME_LIBS="-L${libdir} -lgpgme" +GPGME_CFLAGS="" +AC_SUBST(GPGME_LIBS) +AC_SUBST(GPGME_CFLAGS) + +AC_OUTPUT_COMMANDS([ +chmod +x gpgme/gpgme-config +]) + +AC_OUTPUT([ +Makefile +gpgme/Makefile +gpgme/gpgme-config +tests/Makefile +]) + + + + + + + + diff --git a/tags/V0-1-0/gpgme/ChangeLog b/tags/V0-1-0/gpgme/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/tags/V0-1-0/gpgme/Makefile.am b/tags/V0-1-0/gpgme/Makefile.am new file mode 100644 index 0000000..b65157a --- /dev/null +++ b/tags/V0-1-0/gpgme/Makefile.am @@ -0,0 +1,38 @@ +# Process this file with automake to produce Makefile.in + +EXTRA_DIST = gpgme-config.in gpgme.m4 mkerrors mkstatus +BUILT_SOURCES = errors.c status-table.h +bin_SCRIPTS = gpgme-config +m4datadir = $(datadir)/aclocal +m4data_DATA = gpgme.m4 +include_HEADERS = gpgme.h +lib_LTLIBRARIES = libgpgme.la + +libgpgme_la_LDFLAGS = -version-info \ + @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ +libgpgme_la_INCLUDES = -I$(top_srcdir)/lib + +libgpgme_la_SOURCES = \ + gpgme.h types.h util.h util.c \ + context.h ops.h \ + data.c recipient.c \ + wait.c wait.h \ + encrypt.c \ + decrypt.c \ + verify.c \ + sign.c \ + key.c key.h \ + keylist.c \ + rungpg.c rungpg.h status-table.h \ + gpgme.c version.c errors.c + + +errors.c : gpgme.h + $(srcdir)/mkerrors < $(srcdir)/gpgme.h > errors.c + +status-table.h : rungpg.h + $(srcdir)/mkstatus < $(srcdir)/rungpg.h > status-table.h + + + + diff --git a/tags/V0-1-0/gpgme/context.h b/tags/V0-1-0/gpgme/context.h new file mode 100644 index 0000000..e888aa8 --- /dev/null +++ b/tags/V0-1-0/gpgme/context.h @@ -0,0 +1,119 @@ +/* context.h + * 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 CONTEXT_H +#define CONTEXT_H + +#include "gpgme.h" +#include "types.h" +#include "rungpg.h" /* for GpgObject */ + +typedef enum { + RESULT_TYPE_NONE = 0, + RESULT_TYPE_VERIFY, + RESULT_TYPE_DECRYPT, + RESULT_TYPE_SIGN, +} ResultType; + + +struct key_queue_item_s { + struct key_queue_item_s *next; + GpgmeKey key; +}; + + +/* Currently we need it at several places, so we put the definition + * into this header file */ +struct gpgme_context_s { + int initialized; + int pending; /* a gpg request is still pending */ + + /* at some points we need to allocate memory but we are not + * able to handle a malloc problem at that point, so we set this + * flag to indicate this condition */ + int out_of_core; + + GpgObject gpg; /* the running gpg process */ + + int verbosity; /* level of verbosity to use */ + int use_armor; + int use_textmode; + + /* GpgmePassphraseCb passphrase_cb;*/ + /* void * passphrase_cb_value;*/ + + ResultType result_type; + union { + VerifyResult verify; + DecryptResult decrypt; + SignResult sign; + } result; + + GpgmeData notation; /* last signature notation */ + + GpgmeKey tmp_key; /* used by keylist.c */ + volatile int key_cond; /* something new is available */ + struct key_queue_item_s *key_queue; +}; + + +struct gpgme_data_s { + size_t len; + const char *data; + GpgmeDataType type; + GpgmeDataMode mode; + size_t readpos; + size_t writepos; + size_t private_len; + char *private_buffer; +}; + +struct user_id_s { + struct user_id_s *next; + int validity; /* 0 = undefined, 1 = not, 2 = marginal, + 3 = full, 4 = ultimate */ + char name[1]; +}; + +struct gpgme_recipients_s { + struct user_id_s *list; + int checked; /* wether the recipients are all valid */ +}; + + +#define fail_on_pending_request(c) \ + do { \ + if (!(c)) return GPGME_Invalid_Value; \ + if ((c)->pending) return GPGME_Busy; \ + } while (0) + +#define wait_on_request_or_fail(c) \ + do { \ + if (!(c)) return GPGME_Invalid_Value;\ + if (!(c)->pending) return GPGME_No_Request; \ + gpgme_wait ((c), 1); \ + } while (0) + + + +#endif /* CONTEXT_H */ + + + diff --git a/tags/V0-1-0/gpgme/data.c b/tags/V0-1-0/gpgme/data.c new file mode 100644 index 0000000..1037166 --- /dev/null +++ b/tags/V0-1-0/gpgme/data.c @@ -0,0 +1,488 @@ +/* data.c + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" + +#define ALLOC_CHUNK 1024 +#define my_isdigit(a) ( (a) >='0' && (a) <= '9' ) +#define my_isxdigit(a) ( my_isdigit((a)) \ + || ((a) >= 'A' && (a) <= 'F') \ + || ((a) >= 'f' && (a) <= 'f') ) + + +GpgmeError +gpgme_data_new ( GpgmeData *r_dh ) +{ + GpgmeData dh; + + if (!r_dh) + return mk_error (Invalid_Value); + *r_dh = NULL; + dh = xtrycalloc ( 1, sizeof *dh ); + if (!dh) + return mk_error (Out_Of_Core); + dh->mode = GPGME_DATA_MODE_INOUT; + *r_dh = dh; + return 0; +} + + +/** + * gpgme_data_new_from_mem: + * @r_dh: Returns a new data object. + * @buffer: Initialize with this. + * @size: Size of the buffer + * @copy: Flag wether a copy of the buffer should be used. + * + * Create a new data object and initialize with data + * from the memory. A @copy with value %TRUE creates a copy of the + * memory, a value of %FALSE uses the original memory of @buffer and the + * caller has to make sure that this buffer is valid until gpgme_release_data() + * is called. + * + * Return value: + **/ +GpgmeError +gpgme_data_new_from_mem ( GpgmeData *r_dh, + const char *buffer, size_t size, int copy ) +{ + GpgmeData dh; + GpgmeError err; + + if (!r_dh || !buffer) + return mk_error (Invalid_Value); + *r_dh = NULL; + err = gpgme_data_new ( &dh ); + if (err) + return err; + dh->len = size; + if (copy) { + dh->private_buffer = xtrymalloc ( size ); + if ( !dh->private_buffer ) { + gpgme_data_release (dh); + return mk_error (Out_Of_Core); + } + dh->private_len = size; + memcpy (dh->private_buffer, buffer, size ); + dh->data = dh->private_buffer; + dh->writepos = size; + } + else { + dh->data = buffer; + } + dh->type = GPGME_DATA_TYPE_MEM; + + *r_dh = dh; + return 0; +} + +GpgmeError +gpgme_data_new_from_file ( GpgmeData *r_dh, const char *fname, int copy ) +{ + GpgmeData dh; + GpgmeError err; + struct stat st; + FILE *fp; + + if (!r_dh) + return mk_error (Invalid_Value); + *r_dh = NULL; + /* We only support copy for now - in future we might want to honor the + * copy flag and just store a file pointer */ + if (!copy) + return mk_error (Not_Implemented); + if (!fname) + return mk_error (Invalid_Value); + + err = gpgme_data_new ( &dh ); + if (err) + return err; + + fp = fopen (fname, "rb"); + if (!fp) { + int save_errno = errno; + gpgme_data_release (dh); + errno = save_errno; + return mk_error (File_Error); + } + + if( fstat(fileno(fp), &st) ) { + int save_errno = errno; + fclose (fp); + gpgme_data_release (dh); + errno = save_errno; + return mk_error (File_Error); + } + + /* We should check the length of the file and don't allow for to + * large files */ + dh->private_buffer = xtrymalloc ( st.st_size ); + if ( !dh->private_buffer ) { + fclose (fp); + gpgme_data_release (dh); + return mk_error (Out_Of_Core); + } + dh->private_len = st.st_size; + + if ( fread ( dh->private_buffer, dh->private_len, 1, fp ) != 1 ) { + int save_errno = errno; + fclose (fp); + gpgme_data_release (dh); + errno = save_errno; + return mk_error (File_Error); + } + + fclose (fp); + + dh->len = dh->private_len; + dh->data = dh->private_buffer; + dh->writepos = dh->len; + dh->type = GPGME_DATA_TYPE_MEM; + + *r_dh = dh; + return 0; +} + + + +/** + * gpgme_data_release: + * @dh: Data object + * + * Release the data object @dh. @dh may be NULL in which case nothing + * happens. + **/ +void +gpgme_data_release ( GpgmeData dh ) +{ + if (dh) { + xfree (dh->private_buffer); + xfree (dh); + } +} + +char * +_gpgme_data_release_and_return_string ( GpgmeData dh ) +{ + char *val = NULL; + + if (dh) { + if ( _gpgme_data_append ( dh, "", 0 ) ) /* append EOS */ + xfree (dh->private_buffer ); + else { + val = dh->private_buffer; + if ( !val && dh->data ) { + val = xtrymalloc ( dh->len ); + if ( val ) + memcpy ( val, dh->data, dh->len ); + } + } + xfree (dh); + } + return val; +} + +char * +gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len ) +{ + char *val = NULL; + + if (r_len) + *r_len = 0; + if (dh) { + size_t len = dh->len; + val = dh->private_buffer; + if ( !val && dh->data ) { + val = xtrymalloc ( len ); + if ( val ) + memcpy ( val, dh->data, len ); + } + xfree (dh); + if (val && r_len ) + *r_len = len; + } + return val; +} + + +GpgmeDataType +gpgme_data_get_type ( GpgmeData dh ) +{ + if ( !dh || !dh->data ) + return GPGME_DATA_TYPE_NONE; + + return dh->type; +} + +void +_gpgme_data_set_mode ( GpgmeData dh, GpgmeDataMode mode ) +{ + assert (dh); + dh->mode = mode; +} + + +GpgmeDataMode +_gpgme_data_get_mode ( GpgmeData dh ) +{ + assert (dh); + return dh->mode; +} + +GpgmeError +gpgme_data_rewind ( GpgmeData dh ) +{ + if ( !dh ) + return mk_error (Invalid_Value); + /* Fixme: We should check whether rewinding does make sense for the + * data type */ + dh->readpos = 0; + return 0; +} + +GpgmeError +gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread ) +{ + size_t nbytes; + + if ( !dh ) + return mk_error (Invalid_Value); + 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; + return 0; +} + +/* + * This function does make sense when we know that it contains no nil chars. + */ +char * +_gpgme_data_get_as_string ( GpgmeData dh ) +{ + char *val = NULL; + + if (dh) { + val = xtrymalloc ( dh->len+1 ); + if ( val ) { + memcpy ( val, dh->data, dh->len ); + val[dh->len] = 0; + } + } + return val; +} + + + +GpgmeError +_gpgme_data_append ( GpgmeData dh, const char *buffer, size_t length ) +{ + assert (dh); + + if ( dh->type == GPGME_DATA_TYPE_NONE ) { + /* convert it to a mem data type */ + assert (!dh->private_buffer); + dh->type = GPGME_DATA_TYPE_MEM; + dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length; + dh->private_buffer = xtrymalloc ( dh->private_len ); + if (!dh->private_buffer) { + dh->private_len = 0; + return mk_error (Out_Of_Core); + } + dh->writepos = 0; + dh->data = dh->private_buffer; + } + else if ( dh->type != GPGME_DATA_TYPE_MEM ) + return mk_error (Invalid_Type); + + if ( dh->mode != GPGME_DATA_MODE_INOUT + && dh->mode != GPGME_DATA_MODE_IN ) + return mk_error (Invalid_Mode); + + if ( !dh->private_buffer ) { + /* we have to copy it now */ + assert (dh->data); + dh->private_len = dh->len+length; + if (dh->private_len < ALLOC_CHUNK) + dh->private_len = ALLOC_CHUNK; + dh->private_buffer = xtrymalloc ( dh->private_len ); + if (!dh->private_buffer) { + dh->private_len = 0; + return mk_error (Out_Of_Core); + } + memcpy ( dh->private_buffer, dh->data, dh->len ); + dh->writepos = dh->len; + dh->data = dh->private_buffer; + } + + /* allocate more memory if needed */ + if ( dh->writepos + length > dh->private_len ) { + char *p; + size_t newlen = dh->private_len + + (dh->len < ALLOC_CHUNK? ALLOC_CHUNK : length); + p = xtryrealloc ( dh->private_buffer, newlen ); + if ( !p ) + return mk_error (Out_Of_Core); + dh->private_buffer = p; + dh->private_len = newlen; + dh->data = dh->private_buffer; + assert ( !(dh->writepos + length > dh->private_len) ); + } + + memcpy ( dh->private_buffer + dh->writepos, buffer, length ); + dh->writepos += length; + dh->len += length; + + return 0; +} + +GpgmeError +_gpgme_data_append_string ( GpgmeData dh, const char *s ) +{ + return _gpgme_data_append ( dh, s, s? strlen(s):0 ); +} + + +GpgmeError +_gpgme_data_append_for_xml ( GpgmeData dh, + const char *buffer, size_t len ) +{ + const char *text, *s; + size_t n; + int rc = 0; + + if ( !dh || !buffer ) + return mk_error (Invalid_Value); + + do { + for (text=NULL, s=buffer, n=len; n && !text; s++, n-- ) { + if ( *s == '<' ) + text = "<"; + else if ( *s == '>' ) + text = ">"; /* not sure whether this is really needed */ + else if ( *s == '&' ) + text = "&"; + else if ( !*s ) + text = "�"; + } + if (text) { + s--; n++; + } + if (s != buffer) + rc = _gpgme_data_append ( dh, buffer, s-buffer ); + if ( !rc && text) { + rc = _gpgme_data_append_string ( dh, text ); + s++; n--; + } + buffer = s; + len = n; + } while ( !rc && len ); + return rc; +} + + +/* + * Append a string to DATA and convert it so that the result will be + * valid XML. + */ +GpgmeError +_gpgme_data_append_string_for_xml ( GpgmeData dh, const char *string ) +{ + return _gpgme_data_append_for_xml ( dh, string, strlen (string) ); +} + + +static int +hextobyte( const byte *s ) +{ + int c; + + if( *s >= '0' && *s <= '9' ) + c = 16 * (*s - '0'); + else if( *s >= 'A' && *s <= 'F' ) + c = 16 * (10 + *s - 'A'); + else if( *s >= 'a' && *s <= 'f' ) + c = 16 * (10 + *s - 'a'); + else + return -1; + s++; + if( *s >= '0' && *s <= '9' ) + c += *s - '0'; + else if( *s >= 'A' && *s <= 'F' ) + c += 10 + *s - 'A'; + else if( *s >= 'a' && *s <= 'f' ) + c += 10 + *s - 'a'; + else + return -1; + return c; +} + + + + +/* + * Append a string with percent style (%XX) escape characters as XML + */ +GpgmeError +_gpgme_data_append_percentstring_for_xml ( GpgmeData dh, const char *string ) +{ + const byte *s; + byte *buf, *d; + int val; + GpgmeError err; + + d = buf = xtrymalloc ( strlen (string) ); + for (s=string; *s; s++ ) { + if ( *s == '%' && (val=hextobyte (s+1)) != -1 ) { + *d++ = val; + s += 2; + } + else + *d++ = *s; + } + + err = _gpgme_data_append_for_xml ( dh, buf, d - buf ); + xfree (buf); + return err; +} + + + + + + + diff --git a/tags/V0-1-0/gpgme/decrypt.c b/tags/V0-1-0/gpgme/decrypt.c new file mode 100644 index 0000000..017cbf9 --- /dev/null +++ b/tags/V0-1-0/gpgme/decrypt.c @@ -0,0 +1,196 @@ +/* decrypt.c - decrypt functions + * 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 +#include +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" + + +struct decrypt_result_s { + int no_passphrase; + int okay; + int failed; +}; + + +void +_gpgme_release_decrypt_result ( DecryptResult res ) +{ + xfree (res); +} + + + +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 ) { + ctx->out_of_core = 1; + return; + } + ctx->result_type = RESULT_TYPE_DECRYPT; + } + assert ( ctx->result_type == RESULT_TYPE_DECRYPT ); + + switch (code) { + case STATUS_EOF: + break; + + case STATUS_NEED_PASSPHRASE: + case STATUS_NEED_PASSPHRASE_SYM: + fprintf (stderr, "Ooops: Need a passphrase - use the agent\n"); + break; + + case STATUS_MISSING_PASSPHRASE: + fprintf (stderr, "Missing passphrase - stop\n");; + ctx->result.decrypt->no_passphrase = 1; + break; + + case STATUS_DECRYPTION_OKAY: + ctx->result.decrypt->okay = 1; + break; + + case STATUS_DECRYPTION_FAILED: + ctx->result.decrypt->failed = 1; + break; + + + default: + /* ignore all other codes */ + fprintf (stderr, "decrypt_status: code=%d not handled\n", code ); + break; + } +} + + + +GpgmeError +gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData ciph, GpgmeData plain ) +{ + int rc = 0; + int i; + + fail_on_pending_request( c ); + c->pending = 1; + + _gpgme_release_result (c); + c->out_of_core = 0; + + /* do some checks */ + assert ( !c->gpg ); + + /* create a process object */ + rc = _gpgme_gpg_new ( &c->gpg ); + if (rc) + goto leave; + + _gpgme_gpg_set_status_handler ( c->gpg, decrypt_status_handler, c ); + + /* build the commandline */ + _gpgme_gpg_add_arg ( c->gpg, "--decrypt" ); + for ( i=0; i < c->verbosity; i++ ) + _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); + + /* 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_data_set_mode (plain, GPGME_DATA_MODE_IN ); + + /* Tell the gpg object about the data */ + _gpgme_gpg_add_arg ( c->gpg, "--output" ); + _gpgme_gpg_add_arg ( c->gpg, "-" ); + _gpgme_gpg_add_data ( c->gpg, plain, 1 ); + _gpgme_gpg_add_data ( c->gpg, ciph, 0 ); + + /* and kick off the process */ + rc = _gpgme_gpg_spawn ( c->gpg, c ); + + leave: + if (rc) { + c->pending = 0; + _gpgme_gpg_release ( c->gpg ); c->gpg = NULL; + } + return rc; +} + + +/** + * gpgme_op_decrypt: + * @c: The context + * @in: ciphertext input + * @out: plaintext output + * + * This function decrypts @in to @out. + * Other parameters are take from the context @c. + * The function does wait for the result. + * + * Return value: 0 on success or an errorcode. + **/ +GpgmeError +gpgme_op_decrypt ( GpgmeCtx c, GpgmeData in, GpgmeData out ) +{ + GpgmeError err = gpgme_op_decrypt_start ( c, in, out ); + if ( !err ) { + gpgme_wait (c, 1); + if ( c->result_type != RESULT_TYPE_DECRYPT ) + err = mk_error (General_Error); + else if ( c->out_of_core ) + err = mk_error (Out_Of_Core); + else { + assert ( c->result.decrypt ); + if ( c->result.decrypt->no_passphrase ) + err = mk_error (No_Passphrase); + else if ( c->result.decrypt->failed ) + err = mk_error (Decryption_Failed); + else if (!c->result.decrypt->okay) + err = mk_error (No_Data); + } + c->pending = 0; + } + return err; +} + + + + + + + + + diff --git a/tags/V0-1-0/gpgme/encrypt.c b/tags/V0-1-0/gpgme/encrypt.c new file mode 100644 index 0000000..8307a24 --- /dev/null +++ b/tags/V0-1-0/gpgme/encrypt.c @@ -0,0 +1,132 @@ +/* encrypt.c - encrypt functions + * 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 +#include +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" + +static void +encrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ + fprintf (stderr, "encrypt_status: code=%d args=`%s'\n", + code, args ); + +} + + + +GpgmeError +gpgme_op_encrypt_start ( GpgmeCtx c, GpgmeRecipients recp, + GpgmeData plain, GpgmeData ciph ) +{ + int rc = 0; + int i; + + fail_on_pending_request( c ); + c->pending = 1; + + /* do some checks */ + assert ( !c->gpg ); + if ( !gpgme_recipients_count ( recp ) ) { + /* Fixme: In this case we should do symmentric encryption */ + rc = mk_error (No_Recipients); + goto leave; + } + + /* create a process object */ + rc = _gpgme_gpg_new ( &c->gpg ); + if (rc) + goto leave; + + _gpgme_gpg_set_status_handler ( c->gpg, encrypt_status_handler, c ); + + /* build the commandline */ + _gpgme_gpg_add_arg ( c->gpg, "--encrypt" ); + if ( c->use_armor ) + _gpgme_gpg_add_arg ( c->gpg, "--armor" ); + for ( i=0; i < c->verbosity; i++ ) + _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); + + _gpgme_append_gpg_args_from_recipients ( recp, c->gpg ); + + /* Check the supplied data */ + if ( gpgme_data_get_type (plain) == GPGME_DATA_TYPE_NONE ) { + rc = mk_error (No_Data); + goto leave; + } + _gpgme_data_set_mode (plain, GPGME_DATA_MODE_OUT ); + if ( !ciph || gpgme_data_get_type (ciph) != GPGME_DATA_TYPE_NONE ) { + rc = mk_error (Invalid_Value); + goto leave; + } + _gpgme_data_set_mode (ciph, GPGME_DATA_MODE_IN ); + /* Tell the gpg object about the data */ + _gpgme_gpg_add_arg ( c->gpg, "--output" ); + _gpgme_gpg_add_arg ( c->gpg, "-" ); + _gpgme_gpg_add_data ( c->gpg, ciph, 1 ); + _gpgme_gpg_add_arg ( c->gpg, "--" ); + _gpgme_gpg_add_data ( c->gpg, plain, 0 ); + + /* and kick off the process */ + rc = _gpgme_gpg_spawn ( c->gpg, c ); + + leave: + if (rc) { + c->pending = 0; + _gpgme_gpg_release ( c->gpg ); c->gpg = NULL; + } + return rc; +} + + +/** + * gpgme_op_encrypt: + * @c: The context + * @recp: A set of recipients + * @in: plaintext input + * @out: ciphertext output + * + * This function encrypts @in to @out for all recipients from + * @recp. Other parameters are take from the context @c. + * The function does wait for the result. + * + * Return value: 0 on success or an errorcode. + **/ +GpgmeError +gpgme_op_encrypt ( GpgmeCtx c, GpgmeRecipients recp, + GpgmeData in, GpgmeData out ) +{ + int rc = gpgme_op_encrypt_start ( c, recp, in, out ); + if ( !rc ) { + gpgme_wait (c, 1); + c->pending = 0; + } + return rc; +} + + + + diff --git a/tags/V0-1-0/gpgme/gpgme-config.in b/tags/V0-1-0/gpgme/gpgme-config.in new file mode 100644 index 0000000..67bce0f --- /dev/null +++ b/tags/V0-1-0/gpgme/gpgme-config.in @@ -0,0 +1,93 @@ +#!/bin/sh + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +exec_prefix_set=no + +gpgme_libs="@GPGME_LIBS@" +gpgme_cflags="@GPGME_CFLAGS@" + + +usage() +{ + cat <&2 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + if test $exec_prefix_set = no ; then + exec_prefix=$optarg + fi + ;; + --prefix) + echo_prefix=yes + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + ;; + --exec-prefix) + echo_exec_prefix=yes + ;; + --version) + echo "@VERSION@" + exit 0 + ;; + --cflags) + echo_cflags=yes + ;; + --libs) + echo_libs=yes + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + +if test "$echo_prefix" = "yes"; then + echo $prefix +fi + +if test "$echo_exec_prefix" = "yes"; then + echo $exec_prefix +fi + +if test "$echo_cflags" = "yes"; then + if test "@includedir@" != "/usr/include" ; then + includes="-I@includedir@" + for i in $gpgme_cflags ; do + if test "$i" = "-I@includedir@" ; then + includes="" + fi + done + fi + echo $includes $gpgme_cflags +fi + +if test "$echo_libs" = "yes"; then + echo ${gpgme_libs} +fi + + diff --git a/tags/V0-1-0/gpgme/gpgme-memory.h b/tags/V0-1-0/gpgme/gpgme-memory.h new file mode 100644 index 0000000..76ff388 --- /dev/null +++ b/tags/V0-1-0/gpgme/gpgme-memory.h @@ -0,0 +1,36 @@ +/* gpgme-memory.h + * 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 GPGME_MEMORY_H +#define GPGME_MEMORY_H + +void *xmalloc ( size_t n ); +void *xtrymalloc (size_t n ); +void *xcalloc ( size_t n, size_t m ); +void *xtrycalloc (size_t n, size_t m ); +void *xrealloc (void *p, size_t n); +void *xtryrealloc (void *p, size_t n); +void xfree ( void *a ); + +#endif /* GPGME_MEMORY_H */ + + + + diff --git a/tags/V0-1-0/gpgme/gpgme-types.h b/tags/V0-1-0/gpgme/gpgme-types.h new file mode 100644 index 0000000..e20e758 --- /dev/null +++ b/tags/V0-1-0/gpgme/gpgme-types.h @@ -0,0 +1,38 @@ +/* gpgme-types.h - GnuPG Made Easy + * 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 GPGME_TYPES_H +#define GPGME_TYPES_H + +#include "gpgme.h" + +struct gpgme_context_s { + int initialized; +}; + + + + +#endif /* GPGME_TYPES_H */ + + + + + diff --git a/tags/V0-1-0/gpgme/gpgme.c b/tags/V0-1-0/gpgme/gpgme.c new file mode 100644 index 0000000..165f03c --- /dev/null +++ b/tags/V0-1-0/gpgme/gpgme.c @@ -0,0 +1,138 @@ +/* gpgme.c - GnuPG Made Easy + * 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 +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" + +#define my_isdigit(a) ( (a) >='0' && (a) <= '9' ) +#define my_isxdigit(a) ( my_isdigit((a)) \ + || ((a) >= 'A' && (a) <= 'F') \ + || ((a) >= 'f' && (a) <= 'f') ) + +/** + * gpgme_new: + * @r_ctx: Returns the new context + * + * Create a new context to be used with most of the other GPGME + * functions. Use gpgme_release_contect() to release all resources + * + * Return value: An error code + **/ +GpgmeError +gpgme_new (GpgmeCtx *r_ctx) +{ + GpgmeCtx c; + + c = xtrycalloc ( 1, sizeof *c ); + if (!c) + return mk_error (Out_Of_Core); + c->verbosity = 1; + c->use_armor = 1; /* fixme: reset this to 0 */ + *r_ctx = c; + return 0; +} + +/** + * gpgme_release: + * @c: Context to be released. + * + * Release all resources associated with the given context. + **/ +void +gpgme_release ( GpgmeCtx c ) +{ + + _gpgme_gpg_release ( c->gpg ); + _gpgme_release_result ( c ); + _gpgme_key_release ( c->tmp_key ); + gpgme_data_release ( c->notation ); + /* fixme: release the key_queue */ + xfree ( c ); +} + + +void +_gpgme_release_result ( GpgmeCtx c ) +{ + switch (c->result_type) { + case RESULT_TYPE_NONE: + break; + case RESULT_TYPE_VERIFY: + _gpgme_release_verify_result ( c->result.verify ); + break; + case RESULT_TYPE_DECRYPT: + _gpgme_release_decrypt_result ( c->result.decrypt ); + break; + case RESULT_TYPE_SIGN: + _gpgme_release_sign_result ( c->result.sign ); + break; + } + + c->result.verify = NULL; + c->result_type = RESULT_TYPE_NONE; +} + + +char * +gpgme_get_notation ( GpgmeCtx c ) +{ + if ( !c->notation ) + return NULL; + return _gpgme_data_get_as_string ( c->notation ); +} + + +void +gpgme_set_armor ( GpgmeCtx c, int yes ) +{ + if ( !c ) + return; /* oops */ + c->use_armor = yes; +} + +void +gpgme_set_textmode ( GpgmeCtx c, int yes ) +{ + if ( !c ) + return; /* oops */ + c->use_textmode = yes; +} + +#if 0 +void +gpgme_set_passphrase_cb ( GpgmeCtx c, GpgmePassphraseCb fnc, void *fncval ) +{ + if ( c ) { + c->passphrase_cb = fnc; + c->passphrase_cb_value = fncval; + } +} +#endif + + + + + + diff --git a/tags/V0-1-0/gpgme/gpgme.h b/tags/V0-1-0/gpgme/gpgme.h new file mode 100644 index 0000000..692362b --- /dev/null +++ b/tags/V0-1-0/gpgme/gpgme.h @@ -0,0 +1,176 @@ +/* gpgme.h - GnuPG Made Easy + * 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 GPGME_H +#define GPGME_H +#ifdef __cplusplus +extern "C" { +#if 0 /* just to make Emacs auto-indent happy */ +} +#endif +#endif + +/* + * The version of this header should match the one of the library + * It should not be used by a program because gpgme_check_version(NULL) + * does return the same version. The purpose of this macro is to + * 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" + + + +struct gpgme_context_s; +typedef struct gpgme_context_s *GpgmeCtx; + +struct gpgme_data_s; +typedef struct gpgme_data_s *GpgmeData; + +struct gpgme_recipients_s; +typedef struct gpgme_recipients_s *GpgmeRecipients; + +struct gpgme_key_s; +typedef struct gpgme_key_s *GpgmeKey; + + +typedef enum { + GPGME_EOF = -1, + GPGME_No_Error = 0, + GPGME_General_Error = 1, + GPGME_Out_Of_Core = 2, + GPGME_Invalid_Value = 3, + GPGME_Busy = 4, + GPGME_No_Request = 5, + GPGME_Exec_Error = 6, + GPGME_Too_Many_Procs = 7, + GPGME_Pipe_Error = 8, + GPGME_No_Recipients = 9, + GPGME_No_Data = 10, + GPGME_Conflict = 11, + GPGME_Not_Implemented = 12, + GPGME_Read_Error = 13, + GPGME_Write_Error = 14, + GPGME_Invalid_Type = 15, + GPGME_Invalid_Mode = 16, + GPGME_File_Error = 17, /* errno is set in this case */ + GPGME_Decryption_Failed = 18, + GPGME_No_Passphrase = 19, +} GpgmeError; + +typedef enum { + GPGME_DATA_TYPE_NONE = 0, + GPGME_DATA_TYPE_MEM = 1, + GPGME_DATA_TYPE_FD = 2, + GPGME_DATA_TYPE_FILE = 3 +} GpgmeDataType; + +typedef enum { + GPGME_SIG_STAT_NONE = 0, + GPGME_SIG_STAT_GOOD = 1, + GPGME_SIG_STAT_BAD = 2, + GPGME_SIG_STAT_NOKEY = 3, + GPGME_SIG_STAT_NOSIG = 4, + GPGME_SIG_STAT_ERROR = 5 +} GpgmeSigStat; + +/*typedef GpgmeData (*GpgmePassphraseCb)( void *opaque, const char *desc );*/ + + +/* Context management */ +GpgmeError gpgme_new (GpgmeCtx *r_ctx); +void gpgme_release ( GpgmeCtx c ); +GpgmeCtx gpgme_wait ( GpgmeCtx c, int hang ); + +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_recipients_new (GpgmeRecipients *r_rset); +void gpgme_recipients_release ( GpgmeRecipients rset); +GpgmeError gpgme_recipients_add_name (GpgmeRecipients rset, + const char *name); +unsigned int gpgme_recipients_count ( const GpgmeRecipients rset ); + +/* Functions to handle data sources */ +GpgmeError gpgme_data_new ( GpgmeData *r_dh ); +GpgmeError gpgme_data_new_from_mem ( GpgmeData *r_dh, + const char *buffer, size_t size, + int copy ); +GpgmeError gpgme_data_new_from_file ( GpgmeData *r_dh, + const char *fname, + int copy ); +void gpgme_data_release ( GpgmeData dh ); +char * gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len ); +GpgmeDataType gpgme_data_get_type ( GpgmeData dh ); +GpgmeError gpgme_data_rewind ( GpgmeData dh ); +GpgmeError gpgme_data_read ( GpgmeData dh, + char *buffer, size_t length, size_t *nread ); + +/* Key functions */ +char *gpgme_key_get_as_xml ( GpgmeKey key ); + + +/* Basic GnuPG functions */ +GpgmeError gpgme_op_encrypt_start ( GpgmeCtx c, + GpgmeRecipients recp, + GpgmeData in, GpgmeData out ); +GpgmeError gpgme_op_decrypt_start ( GpgmeCtx c, + GpgmeData ciph, GpgmeData plain ); +GpgmeError gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out ); +GpgmeError gpgme_op_verify_start ( GpgmeCtx c, + GpgmeData sig, GpgmeData text ); + + +/* Key management functions */ +GpgmeError gpgme_op_keylist_start ( GpgmeCtx c, + const char *pattern, int secret_only ); +GpgmeError gpgme_op_keylist_next ( GpgmeCtx c, GpgmeKey *r_key ); + + +/* 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_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); + + +#ifdef __cplusplus +} +#endif +#endif /* GPGME_H */ + + + + + + + diff --git a/tags/V0-1-0/gpgme/gpgme.m4 b/tags/V0-1-0/gpgme/gpgme.m4 new file mode 100644 index 0000000..c00071a --- /dev/null +++ b/tags/V0-1-0/gpgme/gpgme.m4 @@ -0,0 +1,170 @@ +dnl Autoconf macros for libgpgme +dnl $Id$ + +# Configure paths for GPGME +# Shamelessly stolen from the one of XDELTA by Owen Taylor +# Werner Koch 2000-11-17 + +dnl AM_PATH_GPGME([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for gpgme, and define GPGME_CFLAGS and GPGME_LIBS +dnl +AC_DEFUN(AM_PATH_GPGME, +[dnl +dnl Get the cflags and libraries from the gpgme-config script +dnl + AC_ARG_WITH(gpgme-prefix, + [ --with-gpgme-prefix=PFX Prefix where gpgme is installed (optional)], + gpgme_config_prefix="$withval", gpgme_config_prefix="") + AC_ARG_ENABLE(gpgmetest, + [ --disable-gpgmetest Do not try to compile and run a test gpgme program], + , enable_gpgmetest=yes) + + if test x$gpgme_config_prefix != x ; then + gpgme_config_args="$gpgme_config_args --prefix=$gpgme_config_prefix" + if test x${GPGME_CONFIG+set} != xset ; then + GPGME_CONFIG=$gpgme_config_prefix/bin/gpgme-config + fi + fi + + AC_PATH_PROG(GPGME_CONFIG, gpgme-config, no) + min_gpgme_version=ifelse([$1], ,1.0.0,$1) + AC_MSG_CHECKING(for gpgme - version >= $min_gpgme_version) + no_gpgme="" + if test "$GPGME_CONFIG" = "no" ; then + no_gpgme=yes + else + GPGME_CFLAGS=`$GPGME_CONFIG $gpgme_config_args --cflags` + GPGME_LIBS=`$GPGME_CONFIG $gpgme_config_args --libs` + gpgme_config_version=`$GPGME_CONFIG $gpgme_config_args --version` + if test "x$enable_gpgmetest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GPGME_CFLAGS" + LIBS="$LIBS $GPGME_LIBS" +dnl +dnl Now check if the installed gpgme is sufficiently new. Also sanity +dnl checks the results of gpgme-config to some extent +dnl + rm -f conf.gpgmetest + AC_TRY_RUN([ +#include +#include +#include +#include + +int +main () +{ + system ("touch conf.gpgmetest"); + + if( strcmp( gpgme_check_version(NULL), "$gpgme_config_version" ) ) + { + printf("\n" +"*** 'gpgme-config --version' returned %s, but GPGME (%s) was found!\n", + "$gpgme_config_version", gpgme_check_version(NULL) ); + printf( +"*** If gpgme-config was correct, then it is best to remove the old\n" +"*** version of GPGME. You may also be able to fix the error\n" +"*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n" +"*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n" +"*** required on your system.\n" +"*** If gpgme-config was wrong, set the environment variable GPGME_CONFIG\n" +"*** to point to the correct copy of gpgme-config, \n" +"*** and remove the file config.cache before re-running configure\n" + ); + } + else if ( strcmp(gpgme_check_version(NULL), GPGME_VERSION ) ) + { + printf("\n*** GPGME header file (version %s) does not match\n", + GPGME_VERSION); + printf("*** library (version %s)\n", gpgme_check_version(NULL) ); + } + else + { + if ( gpgme_check_version( "$min_gpgme_version" ) ) + return 0; + printf("no\n" +"*** An old version of GPGME (%s) was found.\n", gpgme_check_version(NULL) ); + printf( +"*** You need a version of GPGME newer than %s.\n", "$min_gpgme_version" ); + printf( +"*** The latest version of GPGME is always available at\n" +"*** ftp://ftp.gnupg.org/pub/gcrypt/alpha/gpgme/\n" +"*** \n" +"*** If you have already installed a sufficiently new version, this error\n" +"*** probably means that the wrong copy of the gpgme-config shell script is\n" +"*** being found. The easiest way to fix this is to remove the old version\n" +"*** of GPGME, but you can also set the GPGME_CONFIG environment to point to\n" +"*** the correct copy of gpgme-config. (In this case, you will have to\n" +"*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n" +"*** so that the correct libraries are found at run-time).\n" + ); + } + return 1; +} +],, no_gpgme=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_gpgme" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + if test -f conf.gpgmetest ; then + : + else + AC_MSG_RESULT(no) + fi + if test "$GPGME_CONFIG" = "no" ; then + echo "*** The gpgme-config script installed by GPGME could not be found" + echo "*** If GPGME was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the GPGME_CONFIG environment variable to the" + echo "*** full path to gpgme-config." + else + if test -f conf.gpgmetest ; then + : + else + echo "*** Could not run gpgme test program, checking why..." + CFLAGS="$CFLAGS $GPGME_CFLAGS" + LIBS="$LIBS $GPGME_LIBS" + AC_TRY_LINK([ +#include +#include +#include +#include +], [ gpgme_check_version(NULL); return 0 ], + [ +echo "*** The test program compiled, but did not run. This usually means" +echo "*** that the run-time linker is not finding GPGME or finding the wrong" +echo "*** version of GPGME. If it is not finding GPGME, you'll need to set your" +echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" +echo "*** to the installed location Also, make sure you have run ldconfig if" +echo "*** that is required on your system" +echo "***" +echo "*** If you have an old version installed, it is best to remove it," +echo "*** although you may also be able to get things to work by" +echo "*** modifying LD_LIBRARY_PATH" +echo "***" + ], + [ +echo "*** The test program failed to compile or link. See the file config.log" +echo "*** for the exact error that occured. This usually means GPGME was" +echo "*** incorrectly installed or that you have moved GPGME since it was" +echo "*** installed. In the latter case, you may want to edit the" +echo "*** gpgme-config script: $GPGME_CONFIG" + ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GPGME_CFLAGS="" + GPGME_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGME_CFLAGS) + AC_SUBST(GPGME_LIBS) + rm -f conf.gpgmetest +]) + diff --git a/tags/V0-1-0/gpgme/key.c b/tags/V0-1-0/gpgme/key.c new file mode 100644 index 0000000..c58e859 --- /dev/null +++ b/tags/V0-1-0/gpgme/key.c @@ -0,0 +1,287 @@ +/* key.c - Key and keyList objects + * 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 +#include +#include +#include + +#include "util.h" +#include "ops.h" +#include "key.h" + +#define ALLOC_CHUNK 1024 +#define my_isdigit(a) ( (a) >='0' && (a) <= '9' ) + + +GpgmeError +_gpgme_key_new( GpgmeKey *r_key ) +{ + GpgmeKey key; + + *r_key = NULL; + key = xtrycalloc ( 1, sizeof *key ); + if (!key) + return mk_error (Out_Of_Core); + + *r_key = key; + return 0; +} + +void +_gpgme_key_release ( GpgmeKey key ) +{ + struct user_id_s *u, *u2; + + if (!key) + return; + + xfree (key->fingerprint); + for ( u = key->uids; u; u = u2 ) { + u2 = u->next; + xfree (u); + } + xfree (key); +} + +/* + * Take a name from the --with-colon listing, remove certain escape sequences + * sequences and put it into the list of UIDs + */ +GpgmeError +_gpgme_key_append_name ( GpgmeKey key, const char *s ) +{ + struct user_id_s *uid; + char *d; + + assert (key); + /* we can malloc a buffer of the same length, because the converted + * string will never be larger */ + uid = xtrymalloc ( sizeof *uid + strlen (s) ); + if ( !uid ) + return mk_error (Out_Of_Core); + uid->validity = 0; + d = uid->name; + + while ( *s ) { + if ( *s != '\\' ) + *d++ = *s++; + else if ( s[1] == '\\' ) { + s++; + *d++ = *s++; + } + else if ( s[1] == 'n' ) { + s += 2; + *d++ = '\n'; + } + else if ( s[1] == 'r' ) { + s += 2; + *d++ = '\r'; + } + else if ( s[1] == 'v' ) { + s += 2; + *d++ = '\v'; + } + else if ( s[1] == 'b' ) { + s += 2; + *d++ = '\b'; + } + else if ( s[1] == '0' ) { + /* Hmmm: no way to express this */ + s += 2; + *d++ = '\\'; + *d++ = '\0'; + } + else if ( s[1] == 'x' && my_isdigit (s[2]) && my_isdigit (s[3]) ) { + unsigned int val = (s[2]-'0')*16 + (s[3]-'0'); + if ( !val ) { + *d++ = '\\'; + *d++ = '\0'; + } + else + *(byte*)d++ = val; + s += 3; + } + else { /* should not happen */ + s++; + *d++ = '\\'; + *d++ = *s++; + } + } + + uid->next = key->uids; + key->uids = uid; + return 0; +} + + +static void +add_otag ( GpgmeData d, const char *tag ) +{ + _gpgme_data_append_string ( d, " <" ); + _gpgme_data_append_string ( d, tag ); + _gpgme_data_append_string ( d, ">" ); +} + +static void +add_ctag ( GpgmeData d, const char *tag ) +{ + _gpgme_data_append_string ( d, "\n" ); +} + +static void +add_tag_and_string ( GpgmeData d, const char *tag, const char *string ) +{ + add_otag (d, tag); + _gpgme_data_append_string_for_xml ( d, string ); + add_ctag (d, tag); +} + +static void +add_user_id_name ( GpgmeData d, const char *buf, size_t len ) +{ + while ( len && (buf[len-1] == ' ' || buf[len-1] == '\t') ) + len--; + if (len) { + add_otag (d, "name" ); + _gpgme_data_append_for_xml ( d, buf, len ); + add_ctag (d, "name"); + } +} + + +static void +add_user_id ( GpgmeData d, const char *string ) +{ + const char *s, *start=NULL; + int in_name = 0; + int in_email = 0; + int in_comment = 0; + + for (s=string; *s; s++ ) { + if ( in_email ) { + if ( *s == '<' ) + in_email++; /* not legal but anyway */ + else if (*s== '>') { + if ( !--in_email ) { + _gpgme_data_append_for_xml ( d, start, s-start ); + add_ctag (d, "email"); + } + } + } + else if ( in_comment ) { + if ( *s == '(' ) + in_comment++; + else if (*s== ')') { + if ( !--in_comment ) { + _gpgme_data_append_for_xml ( d, start, s-start ); + add_ctag (d, "comment"); + } + } + } + else if ( *s == '<' ) { + if ( in_name ) { + add_user_id_name (d, start, s-start ); + in_name = 0; + } + in_email = 1; + add_otag ( d, "email" ); + start = s+1; + } + else if ( *s == '(' ) { + if ( in_name ) { + add_user_id_name (d, start, s-start ); + in_name = 0; + } + in_comment = 1; + add_otag ( d, "comment" ); + start = s+1; + } + else if ( !in_name && *s != ' ' && *s != '\t' ) { + in_name = 1; + start = s; + } + } + + if ( in_name ) + add_user_id_name (d, start, s-start ); +} + +static void +add_tag_and_uint ( GpgmeData d, const char *tag, unsigned int val ) +{ + char buf[30]; + sprintf (buf, "%u", val ); + add_tag_and_string ( d, tag, buf ); +} + +static void +add_tag_and_time ( GpgmeData d, const char *tag, time_t val ) +{ + char buf[30]; + + if (!val || val == (time_t)-1 ) + return; + sprintf (buf, "%lu", (unsigned long)val ); + add_tag_and_string ( d, tag, buf ); +} + +char * +gpgme_key_get_as_xml ( GpgmeKey key ) +{ + GpgmeData d; + struct user_id_s *u; + + if ( !key ) + return NULL; + + if ( gpgme_data_new ( &d ) ) + return NULL; + + _gpgme_data_append_string ( d, "\n" + " \n" ); + add_tag_and_string (d, "keyid", key->keyid ); + if (key) + add_tag_and_string (d, "fpr", key->fingerprint ); + add_tag_and_uint (d, "algo", key->key_algo ); + add_tag_and_uint (d, "len", key->key_len ); + add_tag_and_time (d, "created", key->timestamp ); + /*add_tag_and_time (d, "expires", key->expires );*/ + _gpgme_data_append_string (d, " \n"); + + /* No the user IDs */ + for ( u = key->uids; u; u = u->next ) { + _gpgme_data_append_string (d, " \n"); + add_tag_and_string ( d, "raw", u->name ); + add_user_id ( d, u->name ); + _gpgme_data_append_string (d, " \n"); + } + _gpgme_data_append_string (d, " \n"); + _gpgme_data_append_string (d, " \n"); + + _gpgme_data_append_string ( d, "\n" ); + + return _gpgme_data_release_and_return_string (d); +} + + + diff --git a/tags/V0-1-0/gpgme/key.h b/tags/V0-1-0/gpgme/key.h new file mode 100644 index 0000000..f95c909 --- /dev/null +++ b/tags/V0-1-0/gpgme/key.h @@ -0,0 +1,54 @@ +/* key.h + * 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 KEY_H +#define KEY_H + +#include +#include "types.h" +#include "context.h" + + +struct gpgme_key_s { + struct { + unsigned int revoked:1 ; + unsigned int expired:1 ; + unsigned int disabled:1 ; + } flags; + unsigned int key_algo; + unsigned int key_len; + char keyid[16+1]; + char *fingerprint; /* malloced hex digits */ + time_t timestamp; /* -1 for invalid, 0 for not available */ + struct user_id_s *uids; + +}; + + +GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s ); + + + +#endif /* KEY_H */ + + + + + diff --git a/tags/V0-1-0/gpgme/keylist.c b/tags/V0-1-0/gpgme/keylist.c new file mode 100644 index 0000000..cbd7cb4 --- /dev/null +++ b/tags/V0-1-0/gpgme/keylist.c @@ -0,0 +1,384 @@ +/* keylist.c - key listing + * 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 +#include +#include +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" +#include "key.h" + +#define my_isdigit(a) ( (a) >='0' && (a) <= '9' ) + +static void finish_key ( GpgmeCtx ctx ); + + +static void +keylist_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ + if ( ctx->out_of_core ) + return; + + switch (code) { + case STATUS_EOF: + if (ctx->tmp_key) + finish_key (ctx); + break; + + default: + /* ignore all other codes */ + fprintf (stderr, "keylist_status: code=%d not handled\n", code ); + break; + } +} + + +static time_t +parse_timestamp ( char *p ) +{ + struct tm tm; + int i; + + if (!*p ) + return 0; + + if (strlen(p) < 10 || p[4] != '-' || p[7] != '-' ) + return (time_t)-1; + p[4] = 0; + p[7] = 0; + p[10] = 0; /* just in case the time part follows */ + memset (&tm, 0, sizeof tm); + + i = atoi (p); + if ( i < 1900 ) + return (time_t)-1; + tm.tm_year = i - 1900; + + i = atoi (p+5); + if ( i < 1 || i > 12 ) + return (time_t)-1; + tm.tm_mon = i-1; + + i = atoi (p+8); + if ( i < 1 || i > 31 ) + return (time_t)-1; + tm.tm_mday = i; + + return mktime (&tm); +} + + +static void +set_trust_info ( GpgmeKey key, const char *s ) +{ + /* look at letters and stop at the first digit */ + for (; *s && !my_isdigit (*s); s++ ) { + switch (*s) { + case 'e': key->flags.expired = 1; break; + case 'r': key->flags.revoked = 1; break; + case 'd': key->flags.disabled = 1; break; + case 'n': key->uids->validity = 1; break; + case 'm': key->uids->validity = 2; break; + case 'f': key->uids->validity = 3; break; + case 'u': key->uids->validity = 4; break; + } + } +} + + +/* Note: we are allowed to modify line */ +static void +keylist_colon_handler ( GpgmeCtx ctx, char *line ) +{ + char *p, *pend; + int field = 0; + enum { + RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC + } rectype = RT_NONE; + GpgmeKey key = ctx->tmp_key; + int i; + const char *trust_info = NULL; + + + if ( ctx->out_of_core ) + return; + if (!line) + return; /* EOF */ + + /*fprintf (stderr, "line=`%s'\n", line );*/ + + for (p = line; p; p = pend) { + field++; + pend = strchr (p, ':'); + if (pend) + *pend++ = 0; + + if ( field == 1 ) { + if ( !strcmp ( p, "sig" ) ) + rectype = RT_SIG; + else if ( !strcmp ( p, "uid" ) && key ) { + rectype = RT_UID; + key = ctx->tmp_key; + } + else if ( !strcmp ( p, "sub" ) ) + rectype = RT_SUB; + else if ( !strcmp ( p, "pub" ) ) { + /* start a new keyblock */ + if ( _gpgme_key_new ( &key ) ) { + ctx->out_of_core=1; /* the only kind of error we can get */ + return; + } + rectype = RT_PUB; + if ( ctx->tmp_key ) + finish_key ( ctx ); + assert ( !ctx->tmp_key ); + ctx->tmp_key = key; + } + else if ( !strcmp ( p, "fpr" ) && key ) + rectype = RT_FPR; + else if ( !strcmp ( p, "ssb" ) ) + rectype = RT_SSB; + else if ( !strcmp ( p, "sec" ) ) + rectype = RT_SEC; + else + rectype = RT_NONE; + + } + else if ( rectype == RT_PUB /*|| rectype == RT_SUB*/ ) { + switch (field) { + case 2: /* trust info */ + if ( rectype == RT_PUB ) + trust_info = p; /*save for later */ + break; + case 3: /* key length */ + i = atoi (p); + if ( i > 1 ) /* ignore invalid values */ + key->key_len = i; + break; + case 4: /* pubkey algo */ + i = atoi (p); + if ( i > 1 && i < 128 ) + key->key_algo = i; + break; + case 5: /* long keyid */ + if ( strlen (p) == DIM(key->keyid)-1 ) + strcpy (key->keyid, p); + break; + case 6: /* timestamp (1998-02-28) */ + key->timestamp = parse_timestamp (p); + break; + case 7: /* valid for n days */ + break; + case 8: /* reserved (LID) */ + break; + case 9: /* ownertrust */ + break; + case 10: /* This is the first name listed */ + if ( rectype == RT_PUB ) { + if ( _gpgme_key_append_name ( key, p) ) + ctx->out_of_core = 1; + else { + if (trust_info) + set_trust_info (key, trust_info); + } + } + break; + case 11: /* signature class */ + break; + case 12: + pend = NULL; /* we can stop here */ + break; + } + } + else if ( rectype == RT_UID ) { + switch (field) { + case 2: /* trust info */ + trust_info = p; /*save for later */ + break; + case 10: /* the 2nd, 3rd,... user ID */ + if ( _gpgme_key_append_name ( key, p) ) + ctx->out_of_core = 1; + else { + if (trust_info) + set_trust_info (key, trust_info); + } + pend = NULL; /* we can stop here */ + break; + } + } + else if ( rectype == RT_FPR ) { + switch (field) { + case 10: /* fingerprint (take only the first one)*/ + if ( !key->fingerprint && *p ) { + key->fingerprint = xtrystrdup (p); + if ( !key->fingerprint ) + ctx->out_of_core = 1; + } + pend = NULL; /* that is all we want */ + break; + } + } + } + +} + + +/* + * We have read an entire key into ctx->tmp_key and should now finish + * it. It is assumed that this releases ctx->tmp_key. + */ +static void +finish_key ( GpgmeCtx ctx ) +{ + GpgmeKey key = ctx->tmp_key; + struct key_queue_item_s *q, *q2; + + assert (key); + ctx->tmp_key = NULL; + + q = xtrymalloc ( sizeof *q ); + if ( !q ) { + _gpgme_key_release (key); + ctx->out_of_core = 1; + return; + } + q->key = key; + q->next = NULL; + /* fixme: lock queue */ + if ( !(q2 = ctx->key_queue) ) + ctx->key_queue = q; + else { + for ( ; q2->next; q2 = q2->next ) + ; + q2->next = q; + } + ctx->key_cond = 1; + /* fixme: unlock queue */ +} + + + + +GpgmeError +gpgme_op_keylist_start ( GpgmeCtx c, const char *pattern, int secret_only ) +{ + GpgmeError rc = 0; + int i; + + fail_on_pending_request( c ); + c->pending = 1; + + _gpgme_release_result (c); + c->out_of_core = 0; + + if ( c->gpg ) { + _gpgme_gpg_release ( c->gpg ); + c->gpg = NULL; + } + _gpgme_key_release (c->tmp_key); + c->tmp_key = NULL; + /* Fixme: release key_queue */ + + rc = _gpgme_gpg_new ( &c->gpg ); + if (rc) + goto leave; + + _gpgme_gpg_set_status_handler ( c->gpg, keylist_status_handler, c ); + + rc = _gpgme_gpg_set_colon_line_handler ( c->gpg, + keylist_colon_handler, c ); + if (rc) + goto leave; + + /* build the commandline */ + for ( i=0; i < c->verbosity; i++ ) + _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); + _gpgme_gpg_add_arg ( c->gpg, "--with-colons" ); + _gpgme_gpg_add_arg ( c->gpg, "--with-fingerprint" ); + /*_gpgme_gpg_add_arg ( c->gpg, "--fast-list-mode" );*/ + _gpgme_gpg_add_arg ( c->gpg, secret_only? + "--list-secret-keys":"--list-keys" ); + + /* Tell the gpg object about the data */ + _gpgme_gpg_add_arg ( c->gpg, "--" ); + if (pattern && *pattern) + _gpgme_gpg_add_arg ( c->gpg, pattern ); + + /* and kick off the process */ + rc = _gpgme_gpg_spawn ( c->gpg, c ); + + leave: + if (rc) { + c->pending = 0; + _gpgme_gpg_release ( c->gpg ); c->gpg = NULL; + } + return rc; +} + + +GpgmeError +gpgme_op_keylist_next ( GpgmeCtx c, GpgmeKey *r_key ) +{ + struct key_queue_item_s *q; + + if (!r_key) + return mk_error (Invalid_Value); + *r_key = NULL; + if (!c) + return mk_error (Invalid_Value); + if ( !c->pending ) + return mk_error (No_Request); + if ( c->out_of_core ) + return mk_error (Out_Of_Core); + + if ( !c->key_queue ) { + _gpgme_wait_on_condition (c, 1, &c->key_cond ); + if ( c->out_of_core ) + return mk_error (Out_Of_Core); + if ( !c->key_cond ) + return mk_error (EOF); + c->key_cond = 0; + assert ( c->key_queue ); + } + q = c->key_queue; + c->key_queue = q->next; + + *r_key = q->key; + xfree (q); + return 0; +} + + + + + + + + + + + + + diff --git a/tags/V0-1-0/gpgme/mkerrors b/tags/V0-1-0/gpgme/mkerrors new file mode 100755 index 0000000..4ad5812 --- /dev/null +++ b/tags/V0-1-0/gpgme/mkerrors @@ -0,0 +1,83 @@ +#!/bin/sh +# mkerrors - Extract error strings from gpgme.h +# and create C source for gpgme_strerror +# 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 + +cat < +#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) { +EOF + +awk ' +/GPGME_No_Error/ { okay=1 } +!okay {next} +/}/ { exit 0 } +/GPGME_[A-Za-z_]*/ { print_code($1) } + + +function print_code( s ) +{ +printf " case %s: s=\"", s ; +gsub(/_/, " ", s ); +printf "%s\"; break;\n", substr(s,7); +} +' + +cat < +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "rungpg.h" + +GpgmeError +gpgme_recipients_new (GpgmeRecipients *r_rset) +{ + GpgmeRecipients rset; + + rset = xtrycalloc ( 1, sizeof *rset ); + if (!rset) + return mk_error (Out_Of_Core); + *r_rset = rset; + return 0; +} + +void +gpgme_recipients_release ( GpgmeRecipients rset ) +{ + /* fixme: release the linked list */ + xfree ( rset ); +} + + +GpgmeError +gpgme_recipients_add_name (GpgmeRecipients rset, const char *name ) +{ + struct user_id_s *r; + + if (!name || !rset ) + return mk_error (Invalid_Value); + r = xtrymalloc ( sizeof *r + strlen (name) ); + if (!r) + return mk_error (Out_Of_Core); + strcpy (r->name, name ); + r->next = rset->list; + rset->list = r; + return 0; +} + +unsigned int +gpgme_recipients_count ( const GpgmeRecipients rset ) +{ + struct user_id_s *r; + unsigned int count = 0; + + if ( rset ) { + for (r=rset->list ; r; r = r->next ) + count++; + } + return count; +} + + +void +_gpgme_append_gpg_args_from_recipients ( + const GpgmeRecipients rset, + GpgObject gpg ) +{ + struct user_id_s *r; + + assert (rset); + for (r=rset->list ; r; r = r->next ) { + _gpgme_gpg_add_arg ( gpg, "-r" ); + _gpgme_gpg_add_arg ( gpg, r->name ); + } +} + + diff --git a/tags/V0-1-0/gpgme/rungpg.c b/tags/V0-1-0/gpgme/rungpg.c new file mode 100644 index 0000000..f75b8b1 --- /dev/null +++ b/tags/V0-1-0/gpgme/rungpg.c @@ -0,0 +1,942 @@ +/* rungpg.c + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpgme.h" +#include "util.h" +#include "ops.h" +#include "wait.h" +#include "rungpg.h" +#include "context.h" /*temp hack until we have GpmeData methods to do I/O */ + +#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; + char arg[1]; /* .. this is used */ +}; + +struct fd_data_map_s { + GpgmeData data; + int inbound; /* true if this is used for reading from gpg */ + int dup_to; + int fd; /* the fd to use */ + int peer_fd; /* the outher side of the pipe */ +}; + + +struct gpg_object_s { + struct arg_and_data_s *arglist; + struct arg_and_data_s **argtail; + int arg_error; + + struct { + int fd[2]; + size_t bufsize; + char *buffer; + size_t readpos; + int eof; + GpgStatusHandler fnc; + void *fnc_value; + } status; + + /* This is a kludge - see the comment at gpg_colon_line_handler */ + struct { + int fd[2]; + size_t bufsize; + char *buffer; + size_t readpos; + int eof; + GpgColonLineHandler fnc; /* this indicate use of this structrue */ + void *fnc_value; + } colon; + + char **argv; + struct fd_data_map_s *fd_data_map; + + pid_t pid; + + int running; + int exit_status; + int exit_signal; +}; + +static void kill_gpg ( GpgObject gpg ); +static void free_argv ( char **argv ); +static void free_fd_data_map ( struct fd_data_map_s *fd_data_map ); + +static int gpg_inbound_handler ( void *opaque, pid_t pid, int fd ); +static int gpg_outbound_handler ( void *opaque, pid_t pid, int fd ); + +static int gpg_status_handler ( void *opaque, pid_t pid, int fd ); +static GpgmeError read_status ( GpgObject gpg ); + +static int gpg_colon_line_handler ( void *opaque, pid_t pid, int fd ); +static GpgmeError read_colon_line ( GpgObject gpg ); + + + +GpgmeError +_gpgme_gpg_new ( GpgObject *r_gpg ) +{ + GpgObject gpg; + int rc = 0; + + gpg = xtrycalloc ( 1, sizeof *gpg ); + if ( !gpg ) { + rc = mk_error (Out_Of_Core); + goto leave; + } + gpg->argtail = &gpg->arglist; + + gpg->status.fd[0] = -1; + gpg->status.fd[1] = -1; + gpg->colon.fd[0] = -1; + gpg->colon.fd[1] = -1; + + /* allocate the read buffer for the status pipe */ + gpg->status.bufsize = 1024; + gpg->status.readpos = 0; + gpg->status.buffer = xtrymalloc (gpg->status.bufsize); + if (!gpg->status.buffer) { + rc = mk_error (Out_Of_Core); + goto leave; + } + /* In any case we need a status pipe - create it right here and + * don't handle it with our generic GpgmeData mechanism */ + if (pipe (gpg->status.fd) == -1) { + rc = mk_error (Pipe_Error); + goto leave; + } + gpg->status.eof = 0; + _gpgme_gpg_add_arg ( gpg, "--status-fd" ); + { + char buf[25]; + sprintf ( buf, "%d", gpg->status.fd[1]); + _gpgme_gpg_add_arg ( gpg, buf ); + } + _gpgme_gpg_add_arg ( gpg, "--batch" ); + _gpgme_gpg_add_arg ( gpg, "--no-tty" ); + + leave: + if (rc) { + _gpgme_gpg_release (gpg); + *r_gpg = NULL; + } + else + *r_gpg = gpg; + return rc; +} + +void +_gpgme_gpg_release ( GpgObject gpg ) +{ + if ( !gpg ) + return; + xfree (gpg->status.buffer); + xfree (gpg->colon.buffer); + if ( gpg->argv ) + free_argv (gpg->argv); + if (gpg->status.fd[0] != -1 ) + close (gpg->status.fd[0]); + if (gpg->status.fd[1] != -1 ) + close (gpg->status.fd[1]); + if (gpg->colon.fd[0] != -1 ) + close (gpg->colon.fd[0]); + if (gpg->colon.fd[1] != -1 ) + close (gpg->colon.fd[1]); + free_fd_data_map (gpg->fd_data_map); + kill_gpg (gpg); /* fixme: should be done asyncronously */ + xfree (gpg); +} + +static void +kill_gpg ( GpgObject gpg ) +{ + #if 0 + if ( gpg->running ) { + /* still running? Must send a killer */ + kill ( gpg->pid, SIGTERM); + sleep (2); + if ( !waitpid (gpg->pid, NULL, WNOHANG) ) { + /* pay the murderer better and then forget about it */ + kill (gpg->pid, SIGKILL); + } + gpg->running = 0; + } + #endif +} + + + +static int +set_nonblocking ( int fd ) +{ + int flags; + + flags = fcntl (fd, F_GETFL, 0); + if (flags == -1) + return -1; + flags |= O_NONBLOCK; + return fcntl (fd, F_SETFL, flags); +} + + +GpgmeError +_gpgme_gpg_add_arg ( GpgObject gpg, const char *arg ) +{ + struct arg_and_data_s *a; + + assert (gpg); + assert (arg); + a = xtrymalloc ( sizeof *a + strlen (arg) ); + if ( !a ) { + gpg->arg_error = 1; + return mk_error(Out_Of_Core); + } + a->next = NULL; + a->data = NULL; + a->dup_to = -1; + strcpy ( a->arg, arg ); + *gpg->argtail = a; + gpg->argtail = &a->next; + return 0; +} + +GpgmeError +_gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to ) +{ + struct arg_and_data_s *a; + + assert (gpg); + assert (data); + a = xtrymalloc ( sizeof *a - 1 ); + if ( !a ) { + gpg->arg_error = 1; + return mk_error(Out_Of_Core); + } + a->next = NULL; + a->data = data; + a->dup_to = dup_to; + *gpg->argtail = a; + gpg->argtail = &a->next; + return 0; +} + +/* + * Note, that the status_handler is allowed to modifiy the args value + */ +void +_gpgme_gpg_set_status_handler ( GpgObject gpg, + GpgStatusHandler fnc, void *fnc_value ) +{ + assert (gpg); + gpg->status.fnc = fnc; + gpg->status.fnc_value = fnc_value; +} + +/* Kludge to process --with-colon output */ +GpgmeError +_gpgme_gpg_set_colon_line_handler ( GpgObject gpg, + GpgColonLineHandler fnc, void *fnc_value ) +{ + assert (gpg); + + gpg->colon.bufsize = 1024; + gpg->colon.readpos = 0; + gpg->colon.buffer = xtrymalloc (gpg->colon.bufsize); + if (!gpg->colon.buffer) { + return mk_error (Out_Of_Core); + } + if (pipe (gpg->colon.fd) == -1) { + xfree (gpg->colon.buffer); gpg->colon.buffer = NULL; + return mk_error (Pipe_Error); + } + gpg->colon.eof = 0; + gpg->colon.fnc = fnc; + gpg->colon.fnc_value = fnc_value; + return 0; +} + + +static void +free_argv ( char **argv ) +{ + int i; + + for (i=0; argv[i]; i++ ) + xfree (argv[i]); + xfree (argv); +} + +static void +free_fd_data_map ( struct fd_data_map_s *fd_data_map ) +{ + int i; + + for (i=0; fd_data_map[i].data; i++ ) { + if ( fd_data_map[i].fd != -1 ) + close (fd_data_map[i].fd); + if ( fd_data_map[i].peer_fd != -1 ) + close (fd_data_map[i].peer_fd); + /* don't realease data because this is only a reference */ + } + xfree (fd_data_map); +} + + +static GpgmeError +build_argv ( GpgObject gpg ) +{ + struct arg_and_data_s *a; + struct fd_data_map_s *fd_data_map; + size_t datac=0, argc=0; + char **argv; + int need_special = 0; + int use_agent = !!getenv ("GPG_AGENT_INFO"); + + if ( gpg->argv ) { + free_argv ( gpg->argv ); + gpg->argv = NULL; + } + if (gpg->fd_data_map) { + free_fd_data_map (gpg->fd_data_map); + gpg->fd_data_map = NULL; + } + + argc++; /* for argv[0] */ + for ( a=gpg->arglist; a; a = a->next ) { + argc++; + if (a->data) { + /*fprintf (stderr, "build_argv: data\n" );*/ + datac++; + if ( a->dup_to == -1 ) + need_special = 1; + } + else { + /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ + } + } + if ( need_special ) + argc++; + if (use_agent) + argc++; + + argv = xtrycalloc ( argc+1, sizeof *argv ); + if (!argv) + return mk_error (Out_Of_Core); + fd_data_map = xtrycalloc ( datac+1, sizeof *fd_data_map ); + if (!fd_data_map) { + free_argv (argv); + return mk_error (Out_Of_Core); + } + + argc = datac = 0; + argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */ + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + argc++; + if ( need_special ) { + argv[argc] = xtrystrdup ( "--enable-special-filenames" ); + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + argc++; + } + if ( use_agent ) { + argv[argc] = xtrystrdup ( "--use-agent" ); + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + argc++; + } + for ( a=gpg->arglist; a; a = a->next ) { + if ( a->data ) { + switch ( _gpgme_data_get_mode (a->data) ) { + case GPGME_DATA_MODE_NONE: + case GPGME_DATA_MODE_INOUT: + xfree (fd_data_map); + free_argv (argv); + return mk_error (Invalid_Mode); + case GPGME_DATA_MODE_IN: + /* create a pipe to read from gpg */ + fd_data_map[datac].inbound = 1; + break; + case GPGME_DATA_MODE_OUT: + /* create a pipe to pass it down to gpg */ + fd_data_map[datac].inbound = 0; + break; + } + + switch ( gpgme_data_get_type (a->data) ) { + case GPGME_DATA_TYPE_NONE: + if ( fd_data_map[datac].inbound ) + break; /* allowed */ + xfree (fd_data_map); + free_argv (argv); + return mk_error (Invalid_Type); + case GPGME_DATA_TYPE_MEM: + break; + case GPGME_DATA_TYPE_FD: + case GPGME_DATA_TYPE_FILE: + xfree (fd_data_map); + free_argv (argv); + return mk_error (Not_Implemented); + } + + /* create a pipe */ + { + int fds[2]; + + if (pipe (fds) == -1) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Pipe_Error); + } + /* if the data_type is FD, we have to do a dup2 here */ + if (fd_data_map[datac].inbound) { + fd_data_map[datac].fd = fds[0]; + fd_data_map[datac].peer_fd = fds[1]; + } + else { + fd_data_map[datac].fd = fds[1]; + fd_data_map[datac].peer_fd = fds[0]; + } + } + fd_data_map[datac].data = a->data; + fd_data_map[datac].dup_to = a->dup_to; + if ( a->dup_to == -1 ) { + argv[argc] = xtrymalloc ( 25 ); + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + sprintf ( argv[argc], "-&%d", fd_data_map[datac].peer_fd ); + argc++; + } + datac++; + } + else { + argv[argc] = xtrystrdup ( a->arg ); + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + argc++; + } + } + + gpg->argv = argv; + gpg->fd_data_map = fd_data_map; + return 0; +} + +GpgmeError +_gpgme_gpg_spawn( GpgObject gpg, void *opaque ) +{ + int rc; + int i; + pid_t pid; + + if ( !gpg ) + return mk_error (Invalid_Value); + + /* Kludge, so that we don't need to check the return code of + * all the gpgme_gpg_add_arg(). we bail out here instead */ + if ( gpg->arg_error ) + return mk_error (Out_Of_Core); + + rc = build_argv ( gpg ); + if ( rc ) + return rc; + + fflush (stderr); + pid = fork (); + if (pid == -1) { + return mk_error (Exec_Error); + } + + if ( !pid ) { /* child */ + int duped_stdin = 0; + int duped_stderr = 0; + + close (gpg->status.fd[0]); + + if (gpg->colon.fnc) { + /* dup it to stdout */ + if ( dup2 ( gpg->colon.fd[1], 1 ) == -1 ) { + fprintf (stderr,"dup2(colon, 1) failed: %s\n", + strerror (errno) ); + _exit (8); + } + close (gpg->colon.fd[0]); + close (gpg->colon.fd[1]); + } + + for (i=0; gpg->fd_data_map[i].data; i++ ) { + close (gpg->fd_data_map[i].fd); + gpg->fd_data_map[i].fd = -1; + if ( gpg->fd_data_map[i].dup_to != -1 ) { + if ( dup2 (gpg->fd_data_map[i].peer_fd, + gpg->fd_data_map[i].dup_to ) == -1 ) { + fprintf (stderr, "dup2 failed in child: %s\n", + strerror (errno)); + _exit (8); + } + if ( gpg->fd_data_map[i].dup_to == 0 ) + duped_stdin=1; + if ( gpg->fd_data_map[i].dup_to == 2 ) + duped_stderr=1; + close ( gpg->fd_data_map[i].peer_fd ); + } + } + + if( !duped_stdin || !duped_stderr ) { + int fd = open ( "/dev/null", O_RDONLY ); + if ( fd == -1 ) { + fprintf (stderr,"can't open `/dev/null': %s\n", + strerror (errno) ); + _exit (8); + } + /* Make sure that gpg has a connected stdin */ + if ( !duped_stdin ) { + if ( dup2 ( fd, 0 ) == -1 ) { + fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n", + strerror (errno) ); + _exit (8); + } + } + /* We normally don't want all the normal output */ + if ( !duped_stderr ) { + if (!getenv ("GPGME_DEBUG") ) { + if ( dup2 ( fd, 2 ) == -1 ) { + fprintf (stderr,"dup2(dev/null, 2) failed: %s\n", + strerror (errno) ); + _exit (8); + } + } + } + close (fd); + } + + execv ( GPG_PATH, gpg->argv ); + fprintf (stderr,"exec of gpg failed\n"); + _exit (8); + } + /* parent */ + gpg->pid = pid; + + /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ + + if ( gpg->status.fd[1] != -1 ) { + close (gpg->status.fd[1]); + gpg->status.fd[1] = -1; + } + if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler, + gpg, pid, gpg->status.fd[0], 1 ) ) { + /* FIXME: kill the child */ + return mk_error (General_Error); + + } + + if ( gpg->colon.fd[1] != -1 ) { + close (gpg->colon.fd[1]); + gpg->colon.fd[1] = -1; + assert ( gpg->colon.fd[0] != -1 ); + if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler, + gpg, pid, gpg->colon.fd[0], 1 ) ) { + /* FIXME: kill the child */ + return mk_error (General_Error); + + } + } + + for (i=0; gpg->fd_data_map[i].data; i++ ) { + close (gpg->fd_data_map[i].peer_fd); + gpg->fd_data_map[i].peer_fd = -1; + + /* Due to problems with select and write we set outbound pipes + * to non-blocking */ + if (!gpg->fd_data_map[i].inbound) { + set_nonblocking (gpg->fd_data_map[i].fd); + } + + if ( _gpgme_register_pipe_handler ( + opaque, + gpg->fd_data_map[i].inbound? + gpg_inbound_handler:gpg_outbound_handler, + gpg->fd_data_map[i].data, + pid, gpg->fd_data_map[i].fd, + gpg->fd_data_map[i].inbound ) + ) { + /* FIXME: kill the child */ + return mk_error (General_Error); + } + } + + /* fixme: check what data we can release here */ + + gpg->running = 1; + return 0; +} + + +static int +gpg_inbound_handler ( void *opaque, pid_t pid, int fd ) +{ + GpgmeData dh = opaque; + GpgmeError err; + int nread; + char buf[200]; + + assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN ); + + do { + nread = read (fd, buf, 200 ); + } while ( nread == -1 && errno == EINTR); + 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) ); + return 1; + } + else if (!nread) + return 1; /* eof */ + + /* We could improve this with a GpgmeData function which takes + * the read function or provides a memory area for writing to it. + */ + + err = _gpgme_data_append ( dh, buf, nread ); + if ( err ) { + fprintf (stderr, "_gpgme_append_data failed: %s\n", + gpgme_strerror(err)); + /* Fixme: we should close the pipe or read it to /dev/null in + * this case. Returnin EOF is not sufficient */ + return 1; + } + + return 0; +} + + +static int +write_mem_data ( GpgmeData dh, int fd ) +{ + size_t nbytes; + int nwritten; + + nbytes = dh->len - dh->readpos; + if ( !nbytes ) { + fprintf (stderr, "write_mem_data(%d): closing\n", fd ); + close (fd); + return 1; + } + + /* FIXME: Arggg, the pipe blocks on large write request, although + * select told us that it is okay to write - need to figure out + * why this happens? Stevens says nothing about this problem (or + * is it my Linux kernel 2.4.0test1) + * To avoid that we have set the pipe to nonblocking. + */ + + + do { + 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 = write ( fd, dh->data+dh->readpos, nbytes ); + fprintf (stderr, "write_mem_data(%d): wrote %d bytes\n", fd, nwritten ); + } while ( nwritten == -1 && errno == EINTR ); + if (nwritten == -1 && errno == EAGAIN ) + return 0; + if ( nwritten < 1 ) { + fprintf (stderr, "write_mem_data(%d): write failed (n=%d): %s\n", + fd, nwritten, strerror (errno) ); + close (fd); + return 1; + } + + dh->readpos += nwritten; + return 0; +} + + +static int +gpg_outbound_handler ( void *opaque, pid_t pid, int fd ) +{ + GpgmeData dh = opaque; + + assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT ); + switch ( gpgme_data_get_type (dh) ) { + case GPGME_DATA_TYPE_MEM: + if ( write_mem_data ( dh, fd ) ) + return 1; /* ready */ + break; + default: + assert (0); + } + + + return 0; +} + + + +static int +gpg_status_handler ( void *opaque, pid_t pid, int fd ) +{ + GpgObject gpg = opaque; + int rc = 0; + + assert ( fd == gpg->status.fd[0] ); + rc = read_status ( gpg ); + if ( rc ) { + fprintf (stderr, "gpg_handler: read_status problem %d\n - stop", rc); + return 1; + } + + return gpg->status.eof; +} + + +static int +status_cmp (const void *ap, const void *bp) +{ + const struct status_table_s *a = ap; + const struct status_table_s *b = bp; + + return strcmp (a->name, b->name); +} + + + +/* + * Handle the status output of GnuPG. This function does read entire + * lines and passes them as C strings to the callback function (we can + * use C Strings because the status output is always UTF-8 encoded). + * Of course we have to buffer the lines to cope with long lines + * e.g. with a large user ID. Note: We can optimize this to only cope + * with status line code we know about and skip all other stuff + * without buffering (i.e. without extending the buffer). */ +static GpgmeError +read_status ( GpgObject gpg ) +{ + char *p; + int nread; + size_t bufsize = gpg->status.bufsize; + char *buffer = gpg->status.buffer; + size_t readpos = gpg->status.readpos; + + assert (buffer); + if (bufsize - readpos < 256) { + /* need more room for the read */ + bufsize += 1024; + buffer = xtryrealloc (buffer, bufsize); + if ( !buffer ) + return mk_error (Out_Of_Core); + } + + + do { + nread = read ( gpg->status.fd[0], buffer+readpos, bufsize-readpos ); + } while (nread == -1 && errno == EINTR); + + if (nread == -1) + return mk_error(Read_Error); + + if (!nread) { + gpg->status.eof = 1; + if (gpg->status.fnc) + gpg->status.fnc ( gpg->status.fnc_value, STATUS_EOF, "" ); + return 0; + } + + while (nread > 0) { + for (p = buffer + readpos; nread; nread--, p++) { + if ( *p == '\n' ) { + /* (we require that the last line is terminated by a LF) */ + *p = 0; + fprintf (stderr, "read_status: `%s'\n", buffer); + if (!strncmp (buffer, "[GNUPG:] ", 9 ) + && buffer[9] >= 'A' && buffer[9] <= 'Z' + && gpg->status.fnc ) { + struct status_table_s t, *r; + char *rest; + + rest = strchr (buffer+9, ' '); + if ( !rest ) + rest = p; /* set to an empty string */ + else + *rest++ = 0; + + t.name = buffer+9; + /* (the status table as one extra element) */ + r = bsearch ( &t, status_table, DIM(status_table)-1, + sizeof t, status_cmp ); + if ( r ) { + gpg->status.fnc ( gpg->status.fnc_value, + r->code, rest); + } + } + /* To reuse the buffer for the next line we have to + * shift the remaining data to the buffer start and + * restart the loop Hmmm: We can optimize this + * function by looking forward in the buffer to see + * whether a second complete line is available and in + * this case avoid the memmove for this line. */ + nread--; p++; + if (nread) + memmove (buffer, p, nread); + readpos = 0; + break; /* the for loop */ + } + else + readpos++; + } + } + + /* Update the gpg object. */ + gpg->status.bufsize = bufsize; + gpg->status.buffer = buffer; + gpg->status.readpos = readpos; + return 0; +} + + +/* + * This colonline handler thing is not the clean way to do it. + * It might be better to enhance the GpgmeData object to act as + * a wrapper for a callback. Same goes for the status thing. + * For now we use this thing here becuase it is easier to implement. + */ +static int +gpg_colon_line_handler ( void *opaque, pid_t pid, int fd ) +{ + GpgObject gpg = opaque; + GpgmeError rc = 0; + + assert ( fd == gpg->colon.fd[0] ); + rc = read_colon_line ( gpg ); + if ( rc ) { + fprintf (stderr, "gpg_colon_line_handler: " + "read problem %d\n - stop", rc); + return 1; + } + + return gpg->status.eof; +} + +static GpgmeError +read_colon_line ( GpgObject gpg ) +{ + char *p; + int nread; + size_t bufsize = gpg->colon.bufsize; + char *buffer = gpg->colon.buffer; + size_t readpos = gpg->colon.readpos; + + assert (buffer); + if (bufsize - readpos < 256) { + /* need more room for the read */ + bufsize += 1024; + buffer = xtryrealloc (buffer, bufsize); + if ( !buffer ) + return mk_error (Out_Of_Core); + } + + + do { + nread = read ( gpg->colon.fd[0], buffer+readpos, bufsize-readpos ); + } while (nread == -1 && errno == EINTR); + + if (nread == -1) + return mk_error(Read_Error); + + if (!nread) { + gpg->colon.eof = 1; + assert (gpg->colon.fnc); + gpg->colon.fnc ( gpg->colon.fnc_value, NULL ); + return 0; + } + + while (nread > 0) { + for (p = buffer + readpos; nread; nread--, p++) { + if ( *p == '\n' ) { + /* (we require that the last line is terminated by a + * LF) and we skip empty lines. Note: we use UTF8 + * encoding and escaping of special characters + * We require at least one colon to cope with + * some other printed information. + */ + *p = 0; + if ( *buffer && strchr (buffer, ':') ) { + assert (gpg->colon.fnc); + gpg->colon.fnc ( gpg->colon.fnc_value, buffer ); + } + + /* To reuse the buffer for the next line we have to + * shift the remaining data to the buffer start and + * restart the loop Hmmm: We can optimize this + * function by looking forward in the buffer to see + * whether a second complete line is available and in + * this case avoid the memmove for this line. */ + nread--; p++; + if (nread) + memmove (buffer, p, nread); + readpos = 0; + break; /* the for loop */ + } + else + readpos++; + } + } + + /* Update the gpg object. */ + gpg->colon.bufsize = bufsize; + gpg->colon.buffer = buffer; + gpg->colon.readpos = readpos; + return 0; +} + diff --git a/tags/V0-1-0/gpgme/rungpg.h b/tags/V0-1-0/gpgme/rungpg.h new file mode 100644 index 0000000..3ab0904 --- /dev/null +++ b/tags/V0-1-0/gpgme/rungpg.h @@ -0,0 +1,111 @@ +/* rungpg.h - gpg calling functions + * 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 RUNGPG_H +#define RUNGPG_H + +#include "types.h" + + +typedef enum { + STATUS_EOF , + /* mkstatus starts here */ + STATUS_ENTER , + STATUS_LEAVE , + STATUS_ABORT , + STATUS_GOODSIG , + STATUS_BADSIG , + STATUS_ERRSIG , + STATUS_BADARMOR , + STATUS_RSA_OR_IDEA , + STATUS_SIGEXPIRED , + STATUS_KEYREVOKED , + STATUS_TRUST_UNDEFINED , + STATUS_TRUST_NEVER , + STATUS_TRUST_MARGINAL , + STATUS_TRUST_FULLY , + STATUS_TRUST_ULTIMATE , + STATUS_SHM_INFO , + STATUS_SHM_GET , + STATUS_SHM_GET_BOOL , + STATUS_SHM_GET_HIDDEN , + STATUS_NEED_PASSPHRASE , + STATUS_VALIDSIG , + STATUS_SIG_ID , + STATUS_ENC_TO , + STATUS_NODATA , + STATUS_BAD_PASSPHRASE , + STATUS_NO_PUBKEY , + STATUS_NO_SECKEY , + STATUS_NEED_PASSPHRASE_SYM, + STATUS_DECRYPTION_FAILED , + STATUS_DECRYPTION_OKAY , + STATUS_MISSING_PASSPHRASE , + STATUS_GOOD_PASSPHRASE , + STATUS_GOODMDC , + STATUS_BADMDC , + STATUS_ERRMDC , + STATUS_IMPORTED , + STATUS_IMPORT_RES , + STATUS_FILE_START , + STATUS_FILE_DONE , + STATUS_FILE_ERROR , + STATUS_BEGIN_DECRYPTION , + STATUS_END_DECRYPTION , + STATUS_BEGIN_ENCRYPTION , + STATUS_END_ENCRYPTION , + STATUS_DELETE_PROBLEM , + STATUS_GET_BOOL , + STATUS_GET_LINE , + STATUS_GET_HIDDEN , + STATUS_GOT_IT , + STATUS_PROGRESS , + STATUS_SIG_CREATED , + STATUS_SESSION_KEY , + STATUS_NOTATION_NAME , + STATUS_NOTATION_DATA , + STATUS_POLICY_URL +} GpgStatusCode; + +typedef void (*GpgStatusHandler)( GpgmeCtx, GpgStatusCode code, char *args ); +typedef void (*GpgColonLineHandler)( GpgmeCtx, char *line ); + +GpgmeError _gpgme_gpg_new ( GpgObject *r_gpg ); +void _gpgme_gpg_release ( GpgObject gpg ); +GpgmeError _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg ); +GpgmeError _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to ); +void _gpgme_gpg_set_status_handler ( GpgObject gpg, + GpgStatusHandler fnc, + void *fnc_value ); +GpgmeError _gpgme_gpg_set_colon_line_handler ( GpgObject gpg, + GpgColonLineHandler fnc, + void *fnc_value ); + +GpgmeError _gpgme_gpg_spawn ( GpgObject gpg, void *opaque ); + + + +#endif /* RUNGPG_H */ + + + + + + diff --git a/tags/V0-1-0/gpgme/sign.c b/tags/V0-1-0/gpgme/sign.c new file mode 100644 index 0000000..3274f11 --- /dev/null +++ b/tags/V0-1-0/gpgme/sign.c @@ -0,0 +1,190 @@ +/* sign.c - signing functions + * 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 +#include +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" + + +struct sign_result_s { + int no_passphrase; + int okay; +}; + + +void +_gpgme_release_sign_result ( SignResult res ) +{ + xfree (res); +} + + + +static void +sign_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ + if ( ctx->out_of_core ) + return; + if ( ctx->result_type == RESULT_TYPE_NONE ) { + assert ( !ctx->result.sign ); + ctx->result.sign = xtrycalloc ( 1, sizeof *ctx->result.sign ); + if ( !ctx->result.sign ) { + ctx->out_of_core = 1; + return; + } + ctx->result_type = RESULT_TYPE_SIGN; + } + assert ( ctx->result_type == RESULT_TYPE_SIGN ); + + switch (code) { + case STATUS_EOF: + break; + + case STATUS_NEED_PASSPHRASE: + case STATUS_NEED_PASSPHRASE_SYM: + fprintf (stderr, "Ooops: Need a passphrase - use the agent\n"); + break; + + case STATUS_MISSING_PASSPHRASE: + fprintf (stderr, "Missing passphrase - stop\n");; + ctx->result.sign->no_passphrase = 1; + break; + + case STATUS_SIG_CREATED: + /* fixme: we have no error return for multible signatures */ + ctx->result.sign->okay =1; + break; + + default: + fprintf (stderr, "sign_status: code=%d not handled\n", code ); + break; + } +} + + + +GpgmeError +gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out ) +{ + int rc = 0; + int i; + + fail_on_pending_request( c ); + c->pending = 1; + + _gpgme_release_result (c); + c->out_of_core = 0; + + /* do some checks */ + assert ( !c->gpg ); + + /* create a process object */ + rc = _gpgme_gpg_new ( &c->gpg ); + if (rc) + goto leave; + + _gpgme_gpg_set_status_handler ( c->gpg, sign_status_handler, c ); + + /* build the commandline */ + _gpgme_gpg_add_arg ( c->gpg, "--sign" ); + _gpgme_gpg_add_arg ( c->gpg, "--detach" ); + if ( c->use_armor ) + _gpgme_gpg_add_arg ( c->gpg, "--armor" ); + if ( c->use_textmode ) + _gpgme_gpg_add_arg ( c->gpg, "--textmode" ); + for ( i=0; i < c->verbosity; i++ ) + _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); + + /* Check the supplied data */ + if ( gpgme_data_get_type (in) == GPGME_DATA_TYPE_NONE ) { + rc = mk_error (No_Data); + goto leave; + } + _gpgme_data_set_mode (in, GPGME_DATA_MODE_OUT ); + if ( !out || gpgme_data_get_type (out) != GPGME_DATA_TYPE_NONE ) { + rc = mk_error (Invalid_Value); + goto leave; + } + _gpgme_data_set_mode (out, GPGME_DATA_MODE_IN ); + + /* Tell the gpg object about the data */ + _gpgme_gpg_add_data ( c->gpg, in, 0 ); + _gpgme_gpg_add_data ( c->gpg, out, 1 ); + + /* and kick off the process */ + rc = _gpgme_gpg_spawn ( c->gpg, c ); + + leave: + if (rc) { + c->pending = 0; + _gpgme_gpg_release ( c->gpg ); c->gpg = NULL; + } + return rc; +} + + +/** + * gpgme_op_sign: + * @c: The context + * @in: Data to be signed + * @out: Detached signature + * + * Create a detached signature for @in and write it to @out. + * The data will be signed using either the default key or the ones + * defined through @c. + * + * Return value: 0 on success or an error code. + **/ +GpgmeError +gpgme_op_sign ( GpgmeCtx c, GpgmeData in, GpgmeData out ) +{ + GpgmeError err = gpgme_op_sign_start ( c, in, out ); + if ( !err ) { + gpgme_wait (c, 1); + if ( c->result_type != RESULT_TYPE_SIGN ) + err = mk_error (General_Error); + else if ( c->out_of_core ) + err = mk_error (Out_Of_Core); + else { + assert ( c->result.sign ); + if ( c->result.sign->no_passphrase ) + err = mk_error (No_Passphrase); + else if (!c->result.sign->okay) + err = mk_error (No_Data); /* Hmmm: choose a better error? */ + } + c->pending = 0; + } + return err; +} + + + + + + + + + diff --git a/tags/V0-1-0/gpgme/types.h b/tags/V0-1-0/gpgme/types.h new file mode 100644 index 0000000..38d83b2 --- /dev/null +++ b/tags/V0-1-0/gpgme/types.h @@ -0,0 +1,66 @@ +/* types.h - Some type definitions + * 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 TYPES_H +#define TYPES_H + +#include "gpgme.h" /* external objects and prototypes */ + +typedef unsigned char byte; + + +typedef enum { + GPGME_DATA_MODE_NONE = 0, + GPGME_DATA_MODE_IN = 1, + GPGME_DATA_MODE_OUT = 2, + GPGME_DATA_MODE_INOUT = 3 +} GpgmeDataMode; + + +/* + * Declaration of internal objects + */ + +/*-- rungpg.c --*/ +struct gpg_object_s; +typedef struct gpg_object_s *GpgObject; + + +/*-- verify.c --*/ +struct verify_result_s; +typedef struct verify_result_s *VerifyResult; + +/*-- decrypt.c --*/ +struct decrypt_result_s; +typedef struct decrypt_result_s *DecryptResult; + +/*-- sign.c --*/ +struct sign_result_s; +typedef struct sign_result_s *SignResult; + +/*-- key.c --*/ + + +#endif /* TYPES_H */ + + + + + diff --git a/tags/V0-1-0/gpgme/util.c b/tags/V0-1-0/gpgme/util.c new file mode 100644 index 0000000..2711f6b --- /dev/null +++ b/tags/V0-1-0/gpgme/util.c @@ -0,0 +1,63 @@ +/* util.c + * 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 +#include +#include +#include +#include + +#include "util.h" + +void * +_gpgme_malloc (size_t n ) +{ + return malloc (n); +} + +void * +_gpgme_calloc (size_t n, size_t m ) +{ + return calloc (n, m); +} + +void * +_gpgme_realloc (void *p, size_t n) +{ + return realloc (p, n ); +} + + +char * +_gpgme_strdup (const char *p) +{ + return strdup (p); +} + + +void +_gpgme_free ( void *a ) +{ + free (a); +} + + + + diff --git a/tags/V0-1-0/gpgme/util.h b/tags/V0-1-0/gpgme/util.h new file mode 100644 index 0000000..c755773 --- /dev/null +++ b/tags/V0-1-0/gpgme/util.h @@ -0,0 +1,49 @@ +/* util.h + * 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 UTIL_H +#define UTIL_H + +#include "types.h" + +void *_gpgme_malloc (size_t n ); +void *_gpgme_calloc (size_t n, size_t m ); +void *_gpgme_realloc (void *p, size_t n); +char *_gpgme_strdup (const char *p); +void _gpgme_free ( void *a ); + +#define xtrymalloc(a) _gpgme_malloc((a)) +#define xtrycalloc(a,b) _gpgme_calloc((a),(b)) +#define xtryrealloc(a,b) _gpgme_realloc((a),(b)) +#define xtrystrdup(a) _gpgme_strdup((a)) +#define xfree(a) _gpgme_free((a)) + + +#define mk_error(a) ( GPGME_##a ) + +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + + +#endif /* UTIL_H */ + + + + diff --git a/tags/V0-1-0/gpgme/verify.c b/tags/V0-1-0/gpgme/verify.c new file mode 100644 index 0000000..a9f14ba --- /dev/null +++ b/tags/V0-1-0/gpgme/verify.c @@ -0,0 +1,243 @@ +/* verify.c - signature verification + * 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 +#include +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" + +struct verify_result_s { + GpgmeSigStat status; + GpgmeData notation; /* we store an XML fragment here */ + + int notation_in_data; /* private to add_notation() */ +}; + + +void +_gpgme_release_verify_result ( VerifyResult res ) +{ + gpgme_data_release ( res->notation ); + xfree (res); +} + + +static void +add_notation ( GpgmeCtx ctx, GpgStatusCode code, const char *data ) +{ + GpgmeData dh = ctx->result.verify->notation; + + if ( !dh ) { + if ( gpgme_data_new ( &dh ) ) { + ctx->out_of_core = 1; + return; + } + ctx->result.verify->notation = dh; + _gpgme_data_append_string (dh, " \n"); + } + + if ( code == STATUS_NOTATION_DATA ) { + if ( !ctx->result.verify->notation_in_data ) + _gpgme_data_append_string (dh, " "); + _gpgme_data_append_percentstring_for_xml (dh, data); + ctx->result.verify->notation_in_data = 1; + return; + } + + if ( ctx->result.verify->notation_in_data ) { + _gpgme_data_append_string (dh, "\n"); + ctx->result.verify->notation_in_data = 0; + } + + if ( code == STATUS_NOTATION_NAME ) { + _gpgme_data_append_string (dh, " "); + _gpgme_data_append_percentstring_for_xml (dh, data); + _gpgme_data_append_string (dh, "\n"); + } + else if ( code == STATUS_POLICY_URL ) { + _gpgme_data_append_string (dh, " "); + _gpgme_data_append_percentstring_for_xml (dh, data); + _gpgme_data_append_string (dh, "\n"); + } + else { + assert (0); + } +} + +static void +verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ + if ( ctx->out_of_core ) + return; + if ( ctx->result_type == RESULT_TYPE_NONE ) { + assert ( !ctx->result.verify ); + ctx->result.verify = xtrycalloc ( 1, sizeof *ctx->result.verify ); + if ( !ctx->result.verify ) { + ctx->out_of_core = 1; + return; + } + ctx->result_type = RESULT_TYPE_VERIFY; + } + assert ( ctx->result_type == RESULT_TYPE_VERIFY ); + + /* FIXME: For now we handle only one signature */ + /* FIXME: Collect useful information + and return them as XML */ + switch (code) { + case STATUS_GOODSIG: + ctx->result.verify->status = GPGME_SIG_STAT_GOOD; + break; + case STATUS_BADSIG: + ctx->result.verify->status = GPGME_SIG_STAT_BAD; + break; + case STATUS_ERRSIG: + ctx->result.verify->status = GPGME_SIG_STAT_ERROR; + /* FIXME: distinguish between a regular error and a missing key. + * this is encoded in the args. */ + break; + + case STATUS_NOTATION_NAME: + case STATUS_NOTATION_DATA: + case STATUS_POLICY_URL: + add_notation ( ctx, code, args ); + break; + + default: + /* ignore all other codes */ + fprintf (stderr, "verify_status: code=%d not handled\n", code ); + break; + } +} + + + +GpgmeError +gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text ) +{ + int rc = 0; + int i; + + fail_on_pending_request( c ); + c->pending = 1; + + _gpgme_release_result (c); + c->out_of_core = 0; + + /* create a process object. + * To optimize this, we should reuse an existing one and + * run gpg in the new --pipemode (I started with this but it is + * not yet finished) */ + if ( c->gpg ) { + _gpgme_gpg_release ( c->gpg ); + c->gpg = NULL; + } + rc = _gpgme_gpg_new ( &c->gpg ); + if (rc) + goto leave; + + _gpgme_gpg_set_status_handler ( c->gpg, verify_status_handler, c ); + + /* build the commandline */ + _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 ) { + rc = mk_error (No_Data); + goto leave; + } + if ( text && gpgme_data_get_type (text) == GPGME_DATA_TYPE_NONE ) { + rc = mk_error (No_Data); + goto leave; + } + _gpgme_data_set_mode (sig, GPGME_DATA_MODE_OUT ); + if (text) /* detached signature */ + _gpgme_data_set_mode (text, GPGME_DATA_MODE_OUT ); + /* Tell the gpg object about the data */ + _gpgme_gpg_add_arg ( c->gpg, "--" ); + _gpgme_gpg_add_data ( c->gpg, sig, -1 ); + if (text) + _gpgme_gpg_add_data ( c->gpg, text, 0 ); + + /* and kick off the process */ + rc = _gpgme_gpg_spawn ( c->gpg, c ); + + leave: + if (rc) { + c->pending = 0; + _gpgme_gpg_release ( c->gpg ); c->gpg = NULL; + } + return rc; +} + + +GpgmeError +gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text, + GpgmeSigStat *r_stat ) +{ + int rc; + + if ( !r_stat ) + return mk_error (Invalid_Value); + + gpgme_data_release (c->notation); + c->notation = NULL; + + *r_stat = GPGME_SIG_STAT_NONE; + rc = gpgme_op_verify_start ( c, sig, text ); + if ( !rc ) { + gpgme_wait (c, 1); + if ( c->result_type != RESULT_TYPE_VERIFY ) + rc = mk_error (General_Error); + else if ( c->out_of_core ) + rc = mk_error (Out_Of_Core); + else { + assert ( c->result.verify ); + if ( c->result.verify->notation ) { + GpgmeData dh = c->result.verify->notation; + + if ( c->result.verify->notation_in_data ) { + _gpgme_data_append_string (dh, "\n"); + c->result.verify->notation_in_data = 0; + } + _gpgme_data_append_string (dh, "\n"); + c->notation = dh; + c->result.verify->notation = NULL; + } + *r_stat = c->result.verify->status; + } + c->pending = 0; + } + return rc; +} + + + + + + + diff --git a/tags/V0-1-0/gpgme/wait.c b/tags/V0-1-0/gpgme/wait.c new file mode 100644 index 0000000..f54209d --- /dev/null +++ b/tags/V0-1-0/gpgme/wait.c @@ -0,0 +1,391 @@ +/* wait.c + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" +#include "wait.h" + +#define DEBUG_SELECT_ENABLED 1 + +#if DEBUG_SELECT_ENABLED +# define DEBUG_SELECT(a) fprintf a +#else +# define DEBUG_SELECT(a) do { } while(0) +#endif + +/* Fixme: implement the following stuff to make the code MT safe. + * To avoid the need to link against a specific threads lib, such + * an implementation should require the caller to register a function + * which does this task. + * enter_crit() and leave_crit() are used to embrace an area of code + * which should be executed only by one thread at a time. + * lock_xxxx() and unlock_xxxx() protect access to an data object. + * */ +#define enter_crit() do { } while (0) +#define leave_crit() do { } while (0) +#define lock_queue() do { } while (0) +#define unlock_queue() do { } while (0) + +struct wait_queue_item_s { + struct wait_queue_item_s *next; + volatile int used; + volatile int active; + int (*handler)(void*,pid_t,int); + void *handler_value; + pid_t pid; + int fd; + int inbound; /* this is an inbound data handler fd */ + + int exited; + int exit_status; + int exit_signal; + + GpgmeCtx ctx; +}; + + +static struct wait_queue_item_s wait_queue[SIZEOF_WAIT_QUEUE]; + +static int the_big_select ( void ); + + +static void +init_wait_queue (void) +{ + int i; + static int initialized = 0; + + if ( initialized ) /* FIXME: This leads to a race */ + return; + + lock_queue (); + for (i=1; i < SIZEOF_WAIT_QUEUE; i++ ) + wait_queue[i-1].next = &wait_queue[i]; + initialized = 1; + unlock_queue(); +} + +static struct wait_queue_item_s * +queue_item_from_context ( GpgmeCtx ctx ) +{ + struct wait_queue_item_s *q; + + for (q=wait_queue; q; q = q->next) { + if ( q->used && q->ctx == ctx ) + return q; + } + return NULL; +} + + +static void +propagate_term_results ( const struct wait_queue_item_s *first_q ) +{ + struct wait_queue_item_s *q; + + for (q=wait_queue; q; q = q->next) { + if ( q->used && q != first_q && !q->exited + && q->pid == first_q->pid ) { + q->exited = first_q->exited; + q->exit_status = first_q->exit_status; + q->exit_signal = first_q->exit_signal; + } + } +} + +static int +count_active_fds ( pid_t pid ) +{ + struct wait_queue_item_s *q; + int count = 0; + + for (q=wait_queue; q; q = q->next) { + if ( q->used && q->active && q->pid == pid ) + count++; + } + return count; +} + + +/* remove the given process from the queue */ +static void +remove_process ( pid_t pid ) +{ + struct wait_queue_item_s *q; + + for (q=wait_queue; q; q = q->next) { + if ( q->used ) { + close (q->fd); + q->handler = NULL; + q->ctx = NULL; + q->used = 0; + } + } +} + + + +/** + * gpgme_wait: + * @c: + * @hang: + * + * Wait for a finished request, if @c is given the function does only + * wait on a finsihed request for that context, otherwise it will return + * on any request. When @hang is true the function will wait, otherwise + * it will return immediately when there is no pending finished request. + * + * Return value: Context of the finished request or NULL if @hang is false + * and no (or the given) request has finished. + **/ +GpgmeCtx +gpgme_wait ( GpgmeCtx c, int hang ) +{ + return _gpgme_wait_on_condition ( c, hang, NULL ); +} + +GpgmeCtx +_gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond ) +{ + struct wait_queue_item_s *q; + + init_wait_queue (); + do { + int did_work = the_big_select(); + + if ( cond && *cond ) + hang = 0; + + if ( !did_work ) { + int status; + + /* We did no read/write - see whether this process is still + * alive */ + assert (c); /* !c is not yet implemented */ + q = queue_item_from_context ( c ); + assert (q); + + if (q->exited) + ; + else if ( waitpid ( q->pid, &status, WNOHANG ) == q->pid ) { + q->exited = 1; + if ( WIFSIGNALED (status) ) { + q->exit_status = 4; /* Need some value here */ + q->exit_signal = WTERMSIG (status); + } + else if ( WIFEXITED (status) ) { + q->exit_status = WEXITSTATUS (status); + } + else { + q->exited++; + q->exit_status = 4; + } + propagate_term_results (q); + } + + if ( q->exited ) { + if ( !count_active_fds (q->pid) ) { + /* Hmmm, as long as we don't have a callback for + * the exit status, we have no use for these + * values and therefore we can remove this from + * the queue */ + remove_process (q->pid); + hang = 0; + } + } + } + } while (hang); + return c; +} + + + +/* + * We use this function to do the select stuff for all running + * gpgs. A future version might provide a facility to delegate + * those selects to the GDK select stuff. + * This function must be called only by one thread!! + * FIXME: The data structures and algorithms are stupid. + * Returns: 0 = nothing to run + * 1 = did run something + */ + +static int +the_big_select ( void ) +{ + static fd_set readfds; + static fd_set writefds; + struct wait_queue_item_s *q; + int max_fd, n; + struct timeval timeout = { 1, 0 }; /* Use a one second timeout */ + + FD_ZERO ( &readfds ); + FD_ZERO ( &writefds ); + max_fd = 0; + + + DEBUG_SELECT ((stderr, "gpgme:select on [ ")); + lock_queue (); + for ( q = wait_queue; q; q = q->next ) { + if ( q->used && q->active ) { + if (q->inbound) { + assert ( !FD_ISSET ( q->fd, &readfds ) ); + FD_SET ( q->fd, &readfds ); + DEBUG_SELECT ((stderr, "r%d ", q->fd )); + } + else { + assert ( !FD_ISSET ( q->fd, &writefds ) ); + FD_SET ( q->fd, &writefds ); + DEBUG_SELECT ((stderr, "w%d ", q->fd )); + } + if ( q->fd > max_fd ) + max_fd = q->fd; + } + } + unlock_queue (); + DEBUG_SELECT ((stderr, "]\n" )); + + n = select ( max_fd+1, &readfds, &writefds, NULL, &timeout ); + if ( n <= 0 ) { + if ( n && errno != EINTR ) { + fprintf (stderr, "the_big_select: select failed: %s\n", + strerror (errno) ); + } + return 0; + } + +#if DEBUG_SELECT_ENABLED + { + int i; + + fprintf (stderr, "gpgme:select OK [ " ); + for (i=0; i <= max_fd; i++ ) { + if (FD_ISSET (i, &readfds) ) + fprintf (stderr, "r%d ", i ); + if (FD_ISSET (i, &writefds) ) + fprintf (stderr, "w%d ", i ); + } + fprintf (stderr, "]\n" ); + } +#endif + + /* something has to be done. Go over the queue and call + * the handlers */ + restart: + while ( n ) { + lock_queue (); + for ( q = wait_queue; q; q = q->next ) { + if ( q->used && q->active && q->inbound + && FD_ISSET (q->fd, &readfds ) ) { + FD_CLR (q->fd, &readfds ); + assert (n); + n--; + unlock_queue (); + if ( q->handler (q->handler_value, q->pid, q->fd ) ) + q->active = 0; + goto restart; + } + if ( q->used && q->active && !q->inbound + && FD_ISSET (q->fd, &writefds ) ) { + FD_CLR (q->fd, &writefds ); + assert (n); + n--; + unlock_queue (); + if ( q->handler (q->handler_value, q->pid, q->fd ) ) + q->active = 0; + goto restart; + } + } + unlock_queue (); + } + return 1; +} + + + +/* + * called by rungpg.c to register something for select() + */ +GpgmeError +_gpgme_register_pipe_handler( void *opaque, + int (*handler)(void*,pid_t,int), + void *handler_value, + pid_t pid, int fd, int inbound ) +{ + GpgmeCtx ctx = opaque; + struct wait_queue_item_s *q; + + init_wait_queue(); + assert (opaque); + assert (handler); + + lock_queue (); + for ( q = wait_queue; q; q = q->next ) { + if ( !q->used ) { + q->used = 1; + q->active = 0; + break; + } + } + unlock_queue (); + if ( !q ) + return mk_error (Too_Many_Procs); + + q->fd = fd; + q->inbound = inbound; + q->handler = handler; + q->handler_value = handler_value; + q->pid = pid; + q->ctx = ctx; + + /* and enable this entry for the next select */ + q->exited = 0; + q->active = 1; + return 0; +} + + + + + + + + + + + + + + + + + diff --git a/tags/V0-1-0/gpgme/wait.h b/tags/V0-1-0/gpgme/wait.h new file mode 100644 index 0000000..f637414 --- /dev/null +++ b/tags/V0-1-0/gpgme/wait.h @@ -0,0 +1,42 @@ +/* wait.h - definitions for wait.c + * 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 WAIT_H +#define WAIT_H + +#include "gpgme.h" + +#define SIZEOF_WAIT_QUEUE 10 + + +GpgmeError _gpgme_register_pipe_handler( + void *opaque, + int (*handler)(void*,pid_t,int), + void *handler_value, + pid_t pid, int fd, int inbound ); + + + +#endif /* WAIT_H */ + + + + + diff --git a/tags/V0-1-0/tests/Makefile.am b/tags/V0-1-0/tests/Makefile.am new file mode 100644 index 0000000..5e03d45 --- /dev/null +++ b/tags/V0-1-0/tests/Makefile.am @@ -0,0 +1,40 @@ +## Process this file with automake to create Makefile.in + +TESTS_ENVIRONMENT = GNUPGHOME=. + +TESTS = t-encrypt t-sign t-decrypt t-verify t-keylist + +EXTRA_DIST = mkdemodirs pubdemo.asc secdemo.asc cipher-1.asc geheim.txt + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl + +INCLUDES = +LDADD = ../gpgme/libgpgme.la + +noinst_PROGRAMS = $(TESTS) + +distclean-local: + $(srcdir)/mkdemodirs --clean + +all-local: ./pubring.gpg ./secring.gpg + +./pubring.gpg: $(srcdir)/pubdemo.asc + -gpg --homedir . --import $(srcdir)/pubdemo.asc + +./secring.gpg: ./Alpha/Secret.gpg + -gpg --homedir . --import Alpha/Secret.gpg Zulu/Secret.gpg + +./Alpha/Secret.gpg: secdemo.asc + srcdir=$(srcdir) $(srcdir)/mkdemodirs + + + + + + + + + + + + diff --git a/tags/V0-1-0/tests/cipher-1.asc b/tags/V0-1-0/tests/cipher-1.asc new file mode 100644 index 0000000..f0a8ca4 --- /dev/null +++ b/tags/V0-1-0/tests/cipher-1.asc @@ -0,0 +1,15 @@ +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.0.4-2 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +hQEOA2rm1+5GqHH4EAP/Tcqiuhvrjj+RFBKnWn2A7f1ztV17U2EngYFy8TbZYGNp +JoMNdpA7GNZs7iqc/x1epaZDKfaQwWEtARZmK/4nlhB48N+oZeKTm7PXIkRPqrCZ +3fxJjCJaU0yrNGuO345DOr0QwDImVhubVEkfgs8yXK2Szx2G8X3LmiaILHAqA2oD +/1ZqjY8k+ovrLL/qe8un/NTwzSjKIPVGR6mhLFXmj8fnp2kSsbo+Bhh4MczTRR6l +SA32z25vcakKu2qn5Wa4yDcx9NcMt8RHXzmfMDLj6UFq99QqKeLK2ywcIpY9p/GL +fQyaf7r3HTVugBSaoOzegLJ+L7MfWohrStkMeLnJQnro0nYBjADVcUQuSS4N3lst +Df3XrxxA/iJvxt4F9K27u4tp5U1HDg1CIxVrkMs92LBri3S6ZtfjdoqQ7QghFwGP +Kw1lKiWayM6NH9rcCKSgk4kl4P/2l3f78XeFgiywN7UGeSoH3BLMSv9gSxl5KrAz +d2imhTMrfEvZ +=y4ng +-----END PGP MESSAGE----- diff --git a/tags/V0-1-0/tests/geheim.txt b/tags/V0-1-0/tests/geheim.txt new file mode 100644 index 0000000..99a5478 --- /dev/null +++ b/tags/V0-1-0/tests/geheim.txt @@ -0,0 +1,2 @@ +Wenn Sie dies lesen können, ist es wohl nicht +geheim genug. diff --git a/tags/V0-1-0/tests/mkdemodirs b/tags/V0-1-0/tests/mkdemodirs new file mode 100755 index 0000000..0808846 --- /dev/null +++ b/tags/V0-1-0/tests/mkdemodirs @@ -0,0 +1,44 @@ +#!/bin/sh + +set -e + +GPG="gpg --batch --quiet --no-secmem-warning" +NAMES='Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel India + Juliet Kilo Lima Mike November Oscar Papa Quebec Romeo + Sierra Tango Uniform Victor Whisky XRay Yankee Zulu' + +if [ "$1" = "--clean" ]; then + (for i in $NAMES; do + [ -d $i ] && rm -r $i + done) || true + exit 0 +fi + +[ -z "$srcdir" ] && srcdir="../tests" + + +$GPG --dearmor -o secdemo.gpg --yes $srcdir/secdemo.asc +$GPG --dearmor -o pubdemo.gpg --yes $srcdir/pubdemo.asc +[ -f ./tdb.tmp ] && rm ./tdb.tmp +GPGDEMO="$GPG --homedir . --trustdb-name ./tdb.tmp --no-default-keyring + --keyring pubdemo.gpg --secret-keyring secdemo.gpg" +echo -n "Creating:" +for name in $NAMES; do + echo -n " $name" + [ -d $name ] && rm -r $name + mkdir $name + $GPGDEMO --export-secret-key -o - $name > $name/Secret.gpg + $GPG --homedir $name --import $name/Secret.gpg + $GPGDEMO --export -o - $name > $name/Public.gpg + $GPG --homedir $name --import $name/Public.gpg + [ -f $name/pubring.gpg~ ] && rm $name/pubring.gpg~ +done +echo "." +[ -f ./tdb.tmp ] && rm ./tdb.tmp +rm pubdemo.gpg secdemo.gpg + + + + + + diff --git a/tags/V0-1-0/tests/t-decrypt.c b/tags/V0-1-0/tests/t-decrypt.c new file mode 100644 index 0000000..f98748d --- /dev/null +++ b/tags/V0-1-0/tests/t-decrypt.c @@ -0,0 +1,121 @@ +/* t-encrypt.c - regression test + * 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 +#include +#include +#include +#include + +#include "../gpgme/gpgme.h" + +#define fail_if_err(a) do { if(a) { int my_errno = errno; \ + fprintf (stderr, "%s:%d: GpgmeError %s\n", \ + __FILE__, __LINE__, gpgme_strerror(a)); \ + if ((a) == GPGME_File_Error) \ + fprintf (stderr, "\terrno=`%s'\n", strerror (my_errno)); \ + exit (1); } \ + } while(0) + +static void +print_data ( GpgmeData dh ) +{ + char buf[100]; + size_t nread; + GpgmeError err; + + err = gpgme_data_rewind ( dh ); + fail_if_err (err); + while ( !(err = gpgme_data_read ( dh, buf, 100, &nread )) ) { + fwrite ( buf, nread, 1, stdout ); + } + if (err != GPGME_EOF) + 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; +} +#endif + +static char * +mk_fname ( const char *fname ) +{ + const char *srcdir = getenv ("srcdir"); + char *buf; + + if (!srcdir) + srcdir = "."; + buf = malloc (strlen(srcdir) + strlen(fname) + 2 ); + if (!buf ) + exit (8); + strcpy (buf, srcdir); + strcat (buf, "/"); + strcat (buf, fname ); + return buf; +} + +int +main (int argc, char **argv ) +{ + GpgmeCtx ctx; + GpgmeError err; + GpgmeData in, out; + 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 ); + } +#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 ); + fail_if_err (err); + + fflush (NULL); + fputs ("Begin Result:\n", stdout ); + print_data (out); + fputs ("End Result.\n", stdout ); + + gpgme_data_release (in); + gpgme_data_release (out); + gpgme_release (ctx); + } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + + return 0; +} + + diff --git a/tags/V0-1-0/tests/t-encrypt.c b/tags/V0-1-0/tests/t-encrypt.c new file mode 100644 index 0000000..01c5379 --- /dev/null +++ b/tags/V0-1-0/tests/t-encrypt.c @@ -0,0 +1,95 @@ +/* t-encrypt.c - regression test + * 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 +#include +#include +#include + +#include "../gpgme/gpgme.h" + +#define fail_if_err(a) do { if(a) { \ + fprintf (stderr, "%s:%d: GpgmeError %s\n", \ + __FILE__, __LINE__, gpgme_strerror(a)); \ + exit (1); } \ + } while(0) + +static void +print_data ( GpgmeData dh ) +{ + char buf[100]; + size_t nread; + GpgmeError err; + + err = gpgme_data_rewind ( dh ); + fail_if_err (err); + while ( !(err = gpgme_data_read ( dh, buf, 100, &nread )) ) { + fwrite ( buf, nread, 1, stdout ); + } + if (err != GPGME_EOF) + fail_if_err (err); +} + + + +int +main (int argc, char **argv ) +{ + GpgmeCtx ctx; + GpgmeError err; + GpgmeData in, out; + GpgmeRecipients rset; + + do { + err = gpgme_new (&ctx); + fail_if_err (err); + + err = gpgme_data_new_from_mem ( &in, "Hallo Leute\n", 12, 0 ); + fail_if_err (err); + + err = gpgme_data_new ( &out ); + fail_if_err (err); + + err = gpgme_recipients_new (&rset); + fail_if_err (err); + err = gpgme_recipients_add_name (rset, "Bob"); + fail_if_err (err); + err = gpgme_recipients_add_name (rset, "Alpha"); + fail_if_err (err); + + + err = gpgme_op_encrypt (ctx, rset, in, out ); + fail_if_err (err); + + fflush (NULL); + fputs ("Begin Result:\n", stdout ); + print_data (out); + fputs ("End Result.\n", stdout ); + + gpgme_recipients_release (rset); + gpgme_data_release (in); + gpgme_data_release (out); + gpgme_release (ctx); + } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + + return 0; +} + + diff --git a/tags/V0-1-0/tests/t-keylist.c b/tags/V0-1-0/tests/t-keylist.c new file mode 100644 index 0000000..a67d1ee --- /dev/null +++ b/tags/V0-1-0/tests/t-keylist.c @@ -0,0 +1,87 @@ +/* t-keylist.c - regression test + * 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 +#include +#include +#include + +#include "../gpgme/gpgme.h" + +#define fail_if_err(a) do { if(a) { \ + fprintf (stderr, "%s:%d: GpgmeError %s\n", \ + __FILE__, __LINE__, gpgme_strerror(a)); \ + exit (1); } \ + } while(0) + +static void +doit ( GpgmeCtx ctx, const char *pattern ) +{ + GpgmeError err; + GpgmeKey key; + + err = gpgme_op_keylist_start (ctx, pattern, 0 ); + fail_if_err (err); + + while ( !(err = gpgme_op_keylist_next ( ctx, &key )) ) { + char *p; + printf ("\n", key ); + p = gpgme_key_get_as_xml ( key ); + if ( p ) + fputs ( p, stdout ); + else + fputs("\n", stdout ); + printf ("\n", key ); + } + if ( err != GPGME_EOF ) + fail_if_err (err); +} + + +int +main (int argc, char **argv ) +{ + GpgmeCtx ctx; + GpgmeError err; + int loop = 0; + const char *pattern; + + if( argc ) { + argc--; argv++; + } + + if (argc && !strcmp( *argv, "--loop" ) ) { + loop = 1; + argc--; argv++; + } + pattern = argc? *argv : NULL; + + err = gpgme_new (&ctx); + fail_if_err (err); + do { + doit ( ctx, pattern ); + } while ( loop ); + gpgme_release (ctx); + + return 0; +} + + + diff --git a/tags/V0-1-0/tests/t-sign.c b/tags/V0-1-0/tests/t-sign.c new file mode 100644 index 0000000..c09b2c9 --- /dev/null +++ b/tags/V0-1-0/tests/t-sign.c @@ -0,0 +1,89 @@ +/* t-sign.c - regression test + * 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 +#include +#include +#include + +#include "../gpgme/gpgme.h" + +#define fail_if_err(a) do { if(a) { \ + fprintf (stderr, "%s:%d: GpgmeError %s\n", \ + __FILE__, __LINE__, gpgme_strerror(a)); \ + exit (1); } \ + } while(0) + +static void +print_data ( GpgmeData dh ) +{ + char buf[100]; + size_t nread; + GpgmeError err; + + err = gpgme_data_rewind ( dh ); + fail_if_err (err); + while ( !(err = gpgme_data_read ( dh, buf, 100, &nread )) ) { + fwrite ( buf, nread, 1, stdout ); + } + if (err != GPGME_EOF) + fail_if_err (err); +} + + + +int +main (int argc, char **argv ) +{ + GpgmeCtx ctx; + GpgmeError err; + GpgmeData in, out; + + do { + err = gpgme_new (&ctx); + fail_if_err (err); + + err = gpgme_data_new_from_mem ( &in, "Hallo Leute\n", 12, 0 ); + fail_if_err (err); + + err = gpgme_data_new ( &out ); + fail_if_err (err); + + gpgme_set_textmode (ctx, 1); + gpgme_set_armor (ctx, 1); + err = gpgme_op_sign (ctx, in, out ); + fail_if_err (err); + + fflush (NULL); + fputs ("Begin Result:\n", stdout ); + print_data (out); + fputs ("End Result.\n", stdout ); + + gpgme_data_release (in); + gpgme_data_release (out); + gpgme_release (ctx); + } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + + return 0; +} + + + + diff --git a/tags/V0-1-0/tests/t-verify.c b/tags/V0-1-0/tests/t-verify.c new file mode 100644 index 0000000..ac9e337 --- /dev/null +++ b/tags/V0-1-0/tests/t-verify.c @@ -0,0 +1,144 @@ +/* t-verify.c - regression test + * 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 +#include +#include +#include + +#include "../gpgme/gpgme.h" + +static const char test_text1[] = "Just GNU it!\n"; +static const char test_text1f[]= "Just GNU it?\n"; +static const char test_sig1[] = +#if 0 +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iEYEABECAAYFAjoKgjIACgkQLXJ8x2hpdzQMSwCeO/xUrhysZ7zJKPf/FyXA//u1\n" +"ZgIAn0204PBR7yxSdQx6CFxugstNqmRv\n" +"=yku6\n" +"-----END PGP SIGNATURE-----\n" +#elif 0 +"-----BEGIN PGP SIGNATURE-----\n" +"Version: GnuPG v1.0.4-2 (GNU/Linux)\n" +"Comment: For info see http://www.gnupg.org\n" +"\n" +"iJcEABECAFcFAjoS8/E1FIAAAAAACAAkZm9vYmFyLjF0aGlzIGlzIGEgbm90YXRp\n" +"b24gZGF0YSB3aXRoIDIgbGluZXMaGmh0dHA6Ly93d3cuZ3Uub3JnL3BvbGljeS8A\n" +"CgkQLXJ8x2hpdzQLyQCbBW/fgU8ZeWSlWPM1F8umHX17bAAAoIfSNDSp5zM85XcG\n" +"iwxMrf+u8v4r\n" +"=88Zo\n" +"-----END PGP SIGNATURE-----\n" +#elif 1 +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt\n" +"bGF1dGUgdW5kIGpldHp0IGVpbiBwcm96ZW50JS1aZWljaGVuNRSAAAAAAAgAJGZv\n" +"b2Jhci4xdGhpcyBpcyBhIG5vdGF0aW9uIGRhdGEgd2l0aCAyIGxpbmVzGhpodHRw\n" +"Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc\n" +"dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaA==\n" +"=nts1\n" +"-----END PGP SIGNATURE-----\n" +#endif +; + + + +#define fail_if_err(a) do { if(a) { \ + fprintf (stderr, "%s:%d: GpgmeError %s\n", \ + __FILE__, __LINE__, gpgme_strerror(a)); \ + exit (1); } \ + } while(0) + +static void +print_sig_stat ( GpgmeSigStat status ) +{ + switch ( status ) { + case GPGME_SIG_STAT_NONE: + fputs ("Verification Status: None\n", stdout); + break; + case GPGME_SIG_STAT_NOSIG: + fputs ("Verification Status: No Signature\n", stdout); + break; + case GPGME_SIG_STAT_GOOD: + fputs ("Verification Status: Good\n", stdout); + break; + case GPGME_SIG_STAT_BAD: + fputs ("Verification Status: Bad\n", stdout); + break; + case GPGME_SIG_STAT_NOKEY: + fputs ("Verification Status: No Key\n", stdout); + break; + case GPGME_SIG_STAT_ERROR: + fputs ("Verification Status: Error\n", stdout); + break; + } +} + +int +main (int argc, char **argv ) +{ + GpgmeCtx ctx; + GpgmeError err; + GpgmeData sig, text; + GpgmeSigStat status; + char *nota; + + err = gpgme_new (&ctx); + fail_if_err (err); + + do { + err = gpgme_data_new_from_mem ( &text, + test_text1, strlen (test_text1), 0 ); + fail_if_err (err); + err = gpgme_data_new_from_mem ( &sig, + test_sig1, strlen (test_sig1), 0 ); + fail_if_err (err); + + puts ("checking a valid message:\n"); + err = gpgme_op_verify (ctx, sig, text, &status ); + print_sig_stat ( status ); + fail_if_err (err); + if ( (nota=gpgme_get_notation (ctx)) ) + printf ("---Begin Notation---\n%s---End Notation---\n", nota ); + + puts ("checking a manipulated message:\n"); + gpgme_data_release (text); + err = gpgme_data_new_from_mem ( &text, + test_text1f, strlen (test_text1f), 0 ); + fail_if_err (err); + gpgme_data_rewind ( sig ); + err = gpgme_op_verify (ctx, sig, text, &status ); + print_sig_stat ( status ); + fail_if_err (err); + if ( (nota=gpgme_get_notation (ctx)) ) + printf ("---Begin Notation---\n%s---End Notation---\n", nota ); + + gpgme_data_release (sig); + gpgme_data_release (text); + +} while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + gpgme_release (ctx); + + return 0; +} + + + -- 2.26.2