From: Repo Admin Date: Tue, 19 Dec 2000 10:09:11 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create tag 'GPGME-0-1-3'. X-Git-Tag: gpgme-1.2.0@1385~1357 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=9541ca1f7902fa9a9014c7b608df5a03715bbf6d;p=gpgme.git This commit was manufactured by cvs2svn to create tag 'GPGME-0-1-3'. --- diff --git a/tags/GPGME-0-1-3/AUTHORS b/tags/GPGME-0-1-3/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/tags/GPGME-0-1-3/ChangeLog b/tags/GPGME-0-1-3/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/tags/GPGME-0-1-3/INSTALL b/tags/GPGME-0-1-3/INSTALL new file mode 100644 index 0000000..b42a17a --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/Makefile.am b/tags/GPGME-0-1-3/Makefile.am new file mode 100644 index 0000000..13cb797 --- /dev/null +++ b/tags/GPGME-0-1-3/Makefile.am @@ -0,0 +1,18 @@ + +EXTRA_DIST = README-alpha build-w32 + +if BUILD_BONOBO +bonobo = bonobo +else +bonobo = +endif +if BUILD_COMPLUS +complus = complus +else +complus = +endif + + +SUBDIRS = jnlib gpgme tests ${bonobo} ${complus} + + diff --git a/tags/GPGME-0-1-3/NEWS b/tags/GPGME-0-1-3/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/tags/GPGME-0-1-3/README b/tags/GPGME-0-1-3/README new file mode 100644 index 0000000..b244fc5 --- /dev/null +++ b/tags/GPGME-0-1-3/README @@ -0,0 +1,25 @@ + 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 or use the new +gpgme_set_passphrase_cb() + + +Please subscribe to the gnupg-devel@gnupg.org mailing list if you want +to do serious work. + + + + + + + + diff --git a/tags/GPGME-0-1-3/README-alpha b/tags/GPGME-0-1-3/README-alpha new file mode 100644 index 0000000..0f748e3 --- /dev/null +++ b/tags/GPGME-0-1-3/README-alpha @@ -0,0 +1 @@ + THIS IS WORK IN PROGRESS !!!! \ No newline at end of file diff --git a/tags/GPGME-0-1-3/acconfig.h b/tags/GPGME-0-1-3/acconfig.h new file mode 100644 index 0000000..e8cd758 --- /dev/null +++ b/tags/GPGME-0-1-3/acconfig.h @@ -0,0 +1,58 @@ +/* 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@ + +/* 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 +/* defined if the filesystem uses driver letters */ +#undef HAVE_DRIVE_LETTERS +/* Some systems have a mkdir that takes a single argument. */ +#undef MKDIR_TAKES_ONE_ARG + +/* path to the gpg binary */ +#undef GPG_PATH + +/* stuff needed by lnlib/ */ +#undef HAVE_BYTE_TYPEDEF +#undef HAVE_USHORT_TYPEDEF +#undef HAVE_ULONG_TYPEDEF +#undef HAVE_U16_TYPEDEF +#undef HAVE_U32_TYPEDEF + + + +@BOTTOM@ + +/* not yet needed #include "gpgme-defs.h"*/ + +#endif /*GPGME_CONFIG_H*/ diff --git a/tags/GPGME-0-1-3/acinclude.m4 b/tags/GPGME-0-1-3/acinclude.m4 new file mode 100644 index 0000000..0952b2f --- /dev/null +++ b/tags/GPGME-0-1-3/acinclude.m4 @@ -0,0 +1,44 @@ +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 + ]) + +dnl GNUPG_CHECK_TYPEDEF(TYPE, HAVE_NAME) +dnl Check whether a typedef exists and create a #define $2 if it exists +dnl +AC_DEFUN(GNUPG_CHECK_TYPEDEF, + [ AC_MSG_CHECKING(for $1 typedef) + AC_CACHE_VAL(gnupg_cv_typedef_$1, + [AC_TRY_COMPILE([#include + #include ], [ + #undef $1 + int a = sizeof($1); + ], gnupg_cv_typedef_$1=yes, gnupg_cv_typedef_$1=no )]) + AC_MSG_RESULT($gnupg_cv_typedef_$1) + if test "$gnupg_cv_typedef_$1" = yes; then + AC_DEFINE($2) + fi + ]) + + + + + diff --git a/tags/GPGME-0-1-3/bonobo/Makefile.am b/tags/GPGME-0-1-3/bonobo/Makefile.am new file mode 100644 index 0000000..48bc03e --- /dev/null +++ b/tags/GPGME-0-1-3/bonobo/Makefile.am @@ -0,0 +1,11 @@ +## Process this file with automake to produce Makefile.in + +bin_PROGRAMS = gpgme + +INCLUDES = -I$(top_srcdir)/jnlib +LDADD = -L ../jnlib -ljnlib + +gpgme_SOURCES = main.c main.h + + + diff --git a/tags/GPGME-0-1-3/bonobo/gpgme.c b/tags/GPGME-0-1-3/bonobo/gpgme.c new file mode 100644 index 0000000..765de50 --- /dev/null +++ b/tags/GPGME-0-1-3/bonobo/gpgme.c @@ -0,0 +1,20 @@ +/* gpgme - Bonbobo component to access GnuPG + * Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + diff --git a/tags/GPGME-0-1-3/bonobo/main.c b/tags/GPGME-0-1-3/bonobo/main.c new file mode 100644 index 0000000..e42d20a --- /dev/null +++ b/tags/GPGME-0-1-3/bonobo/main.c @@ -0,0 +1,20 @@ +/* main.c - Bonbobo component to access GnuPG + * Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + diff --git a/tags/GPGME-0-1-3/bonobo/main.h b/tags/GPGME-0-1-3/bonobo/main.h new file mode 100644 index 0000000..41b56df --- /dev/null +++ b/tags/GPGME-0-1-3/bonobo/main.h @@ -0,0 +1,42 @@ +/* main.h - GPGME Bonobo component + * Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef MAIN_H +#define MAIN_H + + +struct { + int verbose; + int quiet; + unsigned int debug; + char *homedir; +} opt; + + + + +#endif /* MAIN_H */ + + + + + + + diff --git a/tags/GPGME-0-1-3/build-w32 b/tags/GPGME-0-1-3/build-w32 new file mode 100755 index 0000000..bb72045 --- /dev/null +++ b/tags/GPGME-0-1-3/build-w32 @@ -0,0 +1,11 @@ +#!/bin/sh + +target=i386--mingw32 +host=`./config.guess` + +CC="${target}-gcc" +CPP="${target}-gcc -E" +RANLIB="${target}-ranlib" + +export CC CPP RANLIB +./configure --host=${host} --target=${target} $* diff --git a/tags/GPGME-0-1-3/complus/Makefile.am b/tags/GPGME-0-1-3/complus/Makefile.am new file mode 100644 index 0000000..bbae8d5 --- /dev/null +++ b/tags/GPGME-0-1-3/complus/Makefile.am @@ -0,0 +1,17 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = WINE-LICENSE WINE-AUTHORS + +# No need to install this becuase we are cross-compiling anyway. +noinst_PROGRAMS = gpgcom + +INCLUDES = -I$(top_srcdir)/jnlib +LDADD = -L ../jnlib -ljnlib + +comheaders = obj_base.h basetsd.h guiddef.h wtypes.h + +gpgcom_SOURCES = main.c main.h \ + $(comheaders) \ + ignupg.c ignupg.h + + diff --git a/tags/GPGME-0-1-3/complus/WINE-AUTHORS b/tags/GPGME-0-1-3/complus/WINE-AUTHORS new file mode 100644 index 0000000..be51ca5 --- /dev/null +++ b/tags/GPGME-0-1-3/complus/WINE-AUTHORS @@ -0,0 +1,331 @@ +@c This file is processed by GNU's TeXinfo +@c If you modify it or move it to another location, make sure that +@c TeXinfo works (type `make' in directory documentation). + +@c This is a list of the Wine authors and copyright holders. + +Wine is available thanks to the work of: +James Abbatiello, +Michael Abd-El-Malek, +Howard Abrams, +Mark G. Adams, +Bruno Afonso, +Samir Al-Battran, +Guy Albertelli, +Gustavo Junior Alves, +Bob Amstadt, +Dag Asheim, +Jim Aston, +Martin Ayotte, +Viktor Babrian, +Karl Backström, +Bradley Baetz, +Peter Bajusz, +Andre Malafaya Baptista, +Aaron Barnes, +Jean-Claude Batista, +Marcel Baur, +Francis Beaudet, +Tom Bech, +Matthew Becker, +Georg Beyerle, +Ross Biro, +Dennis Björklund, +Zygo Blaxell, +Martin Boehme, +Francois Boisvert, +Pim Bollen, +Uwe Bonnes, +Peter Bortas, +Noel Borthwick, +Erik Bos, +Fons Botman, +Sylvain Bouchard, +Frederic Boulanger, +Justin Bradford, +John Brezak, +Andrew Bulhak, +John Burton, +Jonathan Buzzard, +Jose Marcos López Caravaca, +Eddie Carpenter, +Niels de Carpentier, +Mike Castle, +Ron Cemer, +Gordon Chaffee, +Gael de Chalendar, +Jimen Ching, +Geoff Clare, +Robert 'Admiral' Coeyman, +Richard Cohen, +Jean-Claude Cote, +Stephen Crowley, +Pascal Cuoq, +David A. Cuthbert, +Brian Joseph Czapiga, +Ulrich Czekalla, +Huw D. M. Davies, +Moses DeJong, +Petar Djukic, +Roman Dolejsi, +Frans van Dorsselaer, +Rikhardur Egilsson, +Morten Eriksen, +Chris Faherty, +Carsten Fallesen, +Paul Falstad, +David Faure, +Wesley Filardo, +Claus Fischer, +Olaf Flebbe, +Chad Fraleigh, +Matthew Francis, +Philippe Froidevaux, +Peter Galbavy, +Peter Ganten, +Ramon Garcia, +Jeff Garzik, +Julio Cesar Gazquez, +Klaas van Gend, +Abey George, +Brian Gerst, +Matthew Ghio, +Jody Goldberg, +David Golding, +François Gouget, +Hans de Graaff, +David Grant, +Albert den Haan, +Jess Haas, +Robert W Hall, +Noomen Hamza, +Charles M. Hannum, +Adrian Harvey, +John Harvey, +James Hatheway, +Kalevi J Hautaniemi, +Bill Hawes, +Lars Heete, +Cameron Heide, +Bernd Herd, +Theodore S. Hetke, +Haithem Hmida, +Jochen Hoenicke, +Henning Hoffmann, +Kevin Holbrook, +Nick Holloway, +Onno Hovers, +Jeffrey Hsu, +Peter Hunnisett, +Miguel de Icaza, +Jukka Iivonen, +Kostya Ivanov, +Serge Ivanov, +Lee Jaekil, +Gautam Jain, +Niels Kristian Bech Jensen, +Rajeev Jhangiani, +Bill Jin, +Jeff Johann, +Alexandre Julliard, +Bang Jun-Young, +James Juran, +Achim Kaiser, +Alexander Kanavin, +Jukka Kangas, +Pavel Kankovsky, +Michael Karcher, +Niclas Karlsson, +Jochen Karrer, +Don Kelly, +Andreas Kirschbaum, +Rein Klazes, +Albrecht Kleine, +Dietmar Kling, +Eric Kohl, +Jon Konrath, +Alex Korobka, +Zoltan Kovacs, +Greg Kreider, +Anand Kumria, +Ove Kåven, +Scott A. Laird, +David Lee Lambert, +Stephen Langasek, +Sean Langley, +Dan Langlois, +Alexander Larsson, +David Lassonde, +Stefan Leichter, +Karl Lessard, +Pascal Lessard, +Andrew Lewycky, +John Li, +Weisheng Li, +Xiang Li, +Per Lindström, +Brian Litzinger, +Juergen Lock, +Martin von Loewis, +Michiel van Loon, +Richard A Lough, +Alexander V. Lukyanov, +Jiuming Luo, +Stephane Lussier, +David Luyer, +José Marcos López, +Kenneth MacDonald, +Peter MacDonald, +Pierre Mageau, +William Magro, +Juergen Marquardt, +Ricardo Massaro, +Keith Matthews, +Joerg Mayer, +Michael McCormack, +Jason McMullan, +Caolan McNamara, +Marcus Meissner, +Graham Menhennitt, +David Metcalfe, +Toufic Milan, +Paul Millar, +Bruce Milner, +Steffen Moeller, +Andreas Mohr, +Slava Monich, +James Moody, +Chris Morgan, +Kai Morich, +Richard Mortimer, +Vasudev Mulchandani, +Rick Mutzke, +Philippe De Muyter, +Itai Nahshon, +Jonathan Naylor, +Tim Newsome, +Thuy Nguyen, +Kristian Nielsen, +Damien O'Neill, +Henrik Olsen, +Gerard Patel, +Michael Patra, +Murali Pattathe, +Dimitrie O. Paun, +Bernd Paysan, +Brad Pepers, +Jim Peterson, +Gerald Pfeifer, +Dave Pickles, +Ian Pilcher, +Brian Pirie, +Michael Poole, +Eric Pouech, +Robert Pouliot, +Vahid Pourlotfali, +Chad Powell, +Joseph Pranevich, +Alex Priem, +Paul Quinn, +Pete Ratzlaff, +Ron Record, +Petter Reinholdtsen, +Keith Reynolds, +Slaven Rezic, +John Richardson, +Rick Richardson, +Douglas Ridgway, +Robert Riggs, +Bernhard Rosenkraenzer, +Matthew Robertson, +Pavel Roskin, +Herbert Rosmanith, +Lilia Roumiantseva, +Johannes Ruscheinski, +Adam Sacarny, +Ivan de Saedeleer, +Thomas Sandford, +Constantine Sapuntzakis, +Pablo Saratxaga, +Carl van Schaik, +Daniel Schepler, +Christian Schlaile, +Peter Schlaile, +Ulrich Schmid, +Bernd Schmidt, +Ian Schmidt, +Juergen Schmied, +Ingo Schneider, +Victor Schneider, +John Sheets, +Yngvi Sigurjonsson, +Stephen Simmons, +Jesper Skov, +Rick Sladkey, +William Smith, +Jaroslaw Piotr Sobieszek, +Patrick Spinler, +Sylvain St-Germain, +Gavriel State, +Sheri Steeves, +Norman Stevens, +Dominik Strasser, +Patrik Stridvall, +Vadim Strizhevsky, +Bertho Stultiens, +Abraham Sudhakar, +Charles Suprin, +James Sutherland, +Erik Svendsen, +Tristan Tarrant, +Andrew Taylor, +Joshua Thielen, +Dirk Thierbach, +Jean-Louis Thirot, +Duncan C Thomson, +Adrian Thurston, +Goran Thyni, +Steve Tibbett, +Dmitry Timoshkov, +Jimmy Tirtawangsa, +Jon Tombs, +Linus Torvalds, +Luc Tourangeau, +Jeff Tranter, +Gregory Trubetskoy, +Petri Tuomola, +Sergey Turchanov, +Lionel Ulmer, +Moshe Vainer, +Michael Veksler, +Sven Verdoolaege, +Todd Vierling, +Erez Volk, +Jerome Vouillon, +Duc Vuong, +Ronan Waide, +Martin Walker, +Owen Wang, +Eric Warnke, +Leigh Wedding, +Randy Weems, +Manfred Weichel, +Ulrich Weigand, +Morten Welinder, +Jeremy White, +Len White, +Lawson Whitney, +Jan Willamowius, +Carl Williams, +Eric Williams, +Cliff Wright, +Karl Guenter Wuensch, +Eric Youngdale, +James Youngman, +Nikita V. Youshchenko, +Mikolaj Zalewski, +John Zero, +Yuxi Zhang, +Nathan Zorich, +Luiz Otavio L. Zorzella, +and Per Ångström. diff --git a/tags/GPGME-0-1-3/complus/WINE-LICENSE b/tags/GPGME-0-1-3/complus/WINE-LICENSE new file mode 100644 index 0000000..f3478fe --- /dev/null +++ b/tags/GPGME-0-1-3/complus/WINE-LICENSE @@ -0,0 +1,26 @@ +This is the license file as it appeared in the CVS version of +Wine at cvs@rhlx01.fht-esslingen.de:/home/wine as of 2000-12-04 +where only AUTHORS has been renamed to WINE-AUTHORS. It applies +to the header files establishing the COM+ framework + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS +for a complete list) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tags/GPGME-0-1-3/complus/basetsd.h b/tags/GPGME-0-1-3/complus/basetsd.h new file mode 100644 index 0000000..866c9b8 --- /dev/null +++ b/tags/GPGME-0-1-3/complus/basetsd.h @@ -0,0 +1,160 @@ +/* basetsd.h - Compilers that uses ILP32, LP64 or P64 type models + for both Win32 and Win64 are supported by this file. + + Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS + for a complete list) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __WINE_BASETSD_H +#define __WINE_BASETSD_H + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + +/* + * Win32 was easy to implement under Unix since most (all?) 32-bit + * Unices uses the same type model (ILP32) as Win32, where int, long + * and pointer are 32-bit. + * + * Win64, however, will cause some problems when implemented under Unix. + * Linux/{Alpha, Sparc64} and most (all?) other 64-bit Unices uses + * the LP64 type model where int is 32-bit and long and pointer are + * 64-bit. Win64 on the other hand uses the P64 (sometimes called LLP64) + * type model where int and long are 32 bit and pointer is 64-bit. + */ + +/* Type model indepent typedefs */ + +typedef char __int8; +typedef unsigned char __uint8; + +typedef short __int16; +typedef unsigned short __uint16; + +typedef int __int32; +typedef unsigned int __uint32; + +typedef long long __int64; +typedef unsigned long long __uint64; + +#if defined(_WIN64) + +typedef __uint32 __ptr32; +typedef void *__ptr64; + +#else /* FIXME: defined(_WIN32) */ + +typedef void *__ptr32; +typedef __uint64 __ptr64; + +#endif + +/* Always signed and 32 bit wide */ + +typedef __int32 LONG32; +typedef __int32 INT32; + +typedef LONG32 *PLONG32; +typedef INT32 *PINT32; + +/* Always unsigned and 32 bit wide */ + +typedef __uint32 ULONG32; +typedef __uint32 DWORD32; +typedef __uint32 UINT32; + +typedef ULONG32 *PULONG32; +typedef DWORD32 *PDWORD32; +typedef UINT32 *PUINT32; + +/* Always signed and 64 bit wide */ + +typedef __int64 LONG64; +typedef __int64 INT64; + +typedef LONG64 *PLONG64; +typedef INT64 *PINT64; + +/* Always unsigned and 64 bit wide */ + +typedef __uint64 ULONG64; +typedef __uint64 DWORD64; +typedef __uint64 UINT64; + +typedef ULONG64 *PULONG64; +typedef DWORD64 *PDWORD64; +typedef UINT64 *PUINT64; + +/* Win32 or Win64 dependent typedef/defines. */ + +#ifdef _WIN64 + +typedef __int64 INT_PTR, *PINT_PTR; +typedef __uint64 UINT_PTR, *PUINT_PTR; + +#define MAXINT_PTR 0x7fffffffffffffff +#define MININT_PTR 0x8000000000000000 +#define MAXUINT_PTR 0xffffffffffffffff + +typedef __int32 HALF_PTR, *PHALF_PTR; +typedef __int32 UHALF_PTR, *PUHALF_PTR; + +#define MAXHALF_PTR 0x7fffffff +#define MINHALF_PTR 0x80000000 +#define MAXUHALF_PTR 0xffffffff + +typedef __int64 LONG_PTR, *PLONG_PTR; +typedef __uint64 ULONG_PTR, *PULONG_PTR; +typedef __uint64 DWORD_PTR, *PDWORD_PTR; + +#else /* FIXME: defined(_WIN32) */ + +typedef __int32 INT_PTR, *PINT_PTR; +typedef __uint32 UINT_PTR, *PUINT_PTR; + +#define MAXINT_PTR 0x7fffffff +#define MININT_PTR 0x80000000 +#define MAXUINT_PTR 0xffffffff + +typedef __int16 HALF_PTR, *PHALF_PTR; +typedef __uint16 UHALF_PTR, *PUHALF_PTR; + +#define MAXUHALF_PTR 0xffff +#define MAXHALF_PTR 0x7fff +#define MINHALF_PTR 0x8000 + +typedef __int32 LONG_PTR, *PLONG_PTR; +typedef __uint32 ULONG_PTR, *PULONG_PTR; +typedef __uint32 DWORD_PTR, *PDWORD_PTR; + +#endif /* defined(_WIN64) || defined(_WIN32) */ + +typedef INT_PTR SSIZE_T, *PSSIZE_T; +typedef UINT_PTR SIZE_T, *PSIZE_T; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* !defined(__WINE_BASETSD_H) */ + + + diff --git a/tags/GPGME-0-1-3/complus/example.c b/tags/GPGME-0-1-3/complus/example.c new file mode 100644 index 0000000..a7d838d --- /dev/null +++ b/tags/GPGME-0-1-3/complus/example.c @@ -0,0 +1,598 @@ +/* + * Copyright 1999 Marcus Meissner + */ +#include +#include +#include + +#include "winbase.h" +#include "winnls.h" +#include "mmsystem.h" +#include "winerror.h" +#include "debugtools.h" + +#include "initguid.h" +#include "vfw.h" + +DEFAULT_DEBUG_CHANNEL(avifile); + +static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj); +static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface); +static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface); +static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size); +static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam); +static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi); +static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size); +static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size); +static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface); +static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam); + +struct ICOM_VTABLE(IAVIFile) iavift = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IAVIFile_fnQueryInterface, + IAVIFile_fnAddRef, + IAVIFile_fnRelease, + IAVIFile_fnInfo, + IAVIFile_fnGetStream, + IAVIFile_fnCreateStream, + IAVIFile_fnWriteData, + IAVIFile_fnReadData, + IAVIFile_fnEndRecord, + IAVIFile_fnDeleteStream +}; + +static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj); +static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream*iface); +static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface); +static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2); +static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size); +static LONG WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags); +static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize); +static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize); +static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread); +static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten); +static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples); +static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread); +static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size); +static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen); + +struct ICOM_VTABLE(IAVIStream) iavist = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IAVIStream_fnQueryInterface, + IAVIStream_fnAddRef, + IAVIStream_fnRelease, + IAVIStream_fnCreate, + IAVIStream_fnInfo, + IAVIStream_fnFindSample, + IAVIStream_fnReadFormat, + IAVIStream_fnSetFormat, + IAVIStream_fnRead, + IAVIStream_fnWrite, + IAVIStream_fnDelete, + IAVIStream_fnReadData, + IAVIStream_fnWriteData, + IAVIStream_fnSetInfo +}; + +typedef struct IAVIStreamImpl { + /* IUnknown stuff */ + ICOM_VFIELD(IAVIStream); + DWORD ref; + /* IAVIStream stuff */ + LPVOID lpInputFormat; + DWORD inputformatsize; + BOOL iscompressing; + DWORD curframe; + + /* Compressor stuff */ + HIC hic; + LPVOID lpCompressFormat; + ICINFO icinfo; + DWORD compbufsize; + LPVOID compbuffer; + + DWORD decompbufsize; + LPVOID decompbuffer; + LPVOID decompformat; + AVICOMPRESSOPTIONS aco; + + LPVOID lpPrev; /* pointer to decompressed frame later */ + LPVOID lpPrevFormat; /* pointer to decompressed info later */ +} IAVIStreamImpl; + +/*********************************************************************** + * AVIFileInit + */ +void WINAPI +AVIFileInit(void) { + FIXME("(),stub!\n"); +} + +typedef struct IAVIFileImpl { + /* IUnknown stuff */ + ICOM_VFIELD(IAVIFile); + DWORD ref; + /* IAVIFile stuff... */ +} IAVIFileImpl; + +static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj) { + ICOM_THIS(IAVIFileImpl,iface); + + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj); + if ( !memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown)) || + !memcmp(&IID_IAVIFile,refiid,sizeof(IID_IAVIFile)) + ) { + *obj = iface; + return S_OK; + } + return OLE_E_ENUM_NOMORE; +} + +static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface) { + ICOM_THIS(IAVIFileImpl,iface); + + FIXME("(%p)->AddRef()\n",iface); + return ++(This->ref); +} + +static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface) { + ICOM_THIS(IAVIFileImpl,iface); + + FIXME("(%p)->Release()\n",iface); + if (!--(This->ref)) { + HeapFree(GetProcessHeap(),0,iface); + return 0; + } + return This->ref; +} + +static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size) { + FIXME("(%p)->Info(%p,%ld)\n",iface,afi,size); + + /* FIXME: fill out struct? */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam) { + FIXME("(%p)->GetStream(%p,0x%08lx,%ld)\n",iface,avis,fccType,lParam); + /* FIXME: create interface etc. */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi) { + ICOM_THIS(IAVIStreamImpl,iface); + char fcc[5]; + IAVIStreamImpl *istream; + + FIXME("(%p,%p,%p)\n",This,avis,asi); + istream = (IAVIStreamImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IAVIStreamImpl)); + istream->ref = 1; + ICOM_VTBL(istream) = &iavist; + fcc[4]='\0'; + memcpy(fcc,(char*)&(asi->fccType),4); + FIXME("\tfccType '%s'\n",fcc); + memcpy(fcc,(char*)&(asi->fccHandler),4); + FIXME("\tfccHandler '%s'\n",fcc); + FIXME("\tdwFlags 0x%08lx\n",asi->dwFlags); + FIXME("\tdwCaps 0x%08lx\n",asi->dwCaps); + FIXME("\tname '%s'\n",debugstr_w(asi->szName)); + + istream->curframe = 0; + *avis = (PAVISTREAM)istream; + return S_OK; +} + +static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size) { + FIXME("(%p)->WriteData(0x%08lx,%p,%ld)\n",iface,ckid,lpData,size); + /* FIXME: write data to file */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size) { + FIXME("(%p)->ReadData(0x%08lx,%p,%p)\n",iface,ckid,lpData,size); + /* FIXME: read at most size bytes from file */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface) { + FIXME("(%p)->EndRecord()\n",iface); + /* FIXME: end record? */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam) { + FIXME("(%p)->DeleteStream(0x%08lx,%ld)\n",iface,fccType,lParam); + /* FIXME: delete stream? */ + return E_FAIL; +} + +/*********************************************************************** + * AVIFileOpenA + */ +HRESULT WINAPI AVIFileOpenA( + PAVIFILE * ppfile,LPCSTR szFile,UINT uMode,LPCLSID lpHandler +) { + IAVIFileImpl *iavi; + + FIXME("(%p,%s,0x%08lx,%s),stub!\n",ppfile,szFile,(DWORD)uMode,debugstr_guid(lpHandler)); + iavi = (IAVIFileImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IAVIFileImpl)); + iavi->ref = 1; + ICOM_VTBL(iavi) = &iavift; + *ppfile = (LPVOID)iavi; + return S_OK; +} + +static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj) { + ICOM_THIS(IAVIStreamImpl,iface); + + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj); + if ( !memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown)) || + !memcmp(&IID_IAVIStream,refiid,sizeof(IID_IAVIStream)) + ) { + *obj = This; + return S_OK; + } + /* can return IGetFrame interface too */ + return OLE_E_ENUM_NOMORE; +} + +static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream*iface) { + ICOM_THIS(IAVIStreamImpl,iface); + + FIXME("(%p)->AddRef()\n",iface); + return ++(This->ref); +} + +static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface) { + ICOM_THIS(IAVIStreamImpl,iface); + + FIXME("(%p)->Release()\n",iface); + if (!--(This->ref)) { + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return This->ref; +} + +static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2) { + FIXME("(%p)->Create(0x%08lx,0x%08lx)\n",iface,lParam1,lParam2); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size) { + FIXME("(%p)->Info(%p,%ld)\n",iface,psi,size); + return E_FAIL; +} + +static LONG WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags) { + FIXME("(%p)->FindSample(%ld,0x%08lx)\n",iface,pos,flags); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize) { + FIXME("(%p)->ReadFormat(%ld,%p,%p)\n",iface,pos,format,formatsize); + return E_FAIL; +} + +/*********************************************************************** + * IAVIStream::SetFormat + */ +static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize) { + IAVIStreamImpl *as = (IAVIStreamImpl*)iface; + + FIXME("(%p)->SetFormat(%ld,%p,%ld)\n",iface,pos,format,formatsize); + if (as->lpInputFormat) HeapFree(GetProcessHeap(),0,as->lpInputFormat); + as->inputformatsize = formatsize; + as->lpInputFormat = HeapAlloc(GetProcessHeap(),0,formatsize); + memcpy(as->lpInputFormat,format,formatsize); + if (as->iscompressing) { + int xsize; + /* Set up the Compressor part */ + xsize = ICCompressGetFormatSize(as->hic,as->lpInputFormat); + as->lpCompressFormat = HeapAlloc(GetProcessHeap(),0,xsize); + ICCompressGetFormat(as->hic,as->lpInputFormat,as->lpCompressFormat); + ICCompressBegin(as->hic,as->lpInputFormat,as->lpCompressFormat); + as->compbufsize = ICCompressGetSize(as->hic,as->lpInputFormat,as->lpCompressFormat); + as->compbuffer = HeapAlloc(GetProcessHeap(),0,as->compbufsize); + + /* Set up the Decompressor part (for prev frames?) */ + xsize=ICDecompressGetFormatSize(as->hic,as->lpCompressFormat); + as->decompformat = HeapAlloc(GetProcessHeap(),0,xsize); + ICDecompressGetFormat(as->hic,as->lpCompressFormat,as->decompformat); + as->decompbufsize=((LPBITMAPINFOHEADER)as->decompbuffer)->biSizeImage; + as->decompbuffer = HeapReAlloc(GetProcessHeap(),0,as->decompbuffer,as->decompbufsize); + memset(as->decompbuffer,0xff,as->decompbufsize); + assert(HeapValidate(GetProcessHeap(),0,NULL)); + + ICDecompressGetFormat(as->hic,as->lpCompressFormat,as->decompformat); + ICDecompressBegin(as->hic,as->lpCompressFormat,as->decompformat); + as->lpPrev = as->lpPrevFormat = NULL; + } + return S_OK; +} + +static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread) { + FIXME("(%p)->Read(%ld,%ld,%p,%ld,%p,%p)\n",iface,start,samples,buffer,buffersize,bytesread,samplesread); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten) { + IAVIStreamImpl *as = (IAVIStreamImpl*)iface; + DWORD ckid,xflags; + + FIXME("(%p)->Write(%ld,%ld,%p,%ld,0x%08lx,%p,%p)\n",iface,start,samples,buffer,buffersize,flags,sampwritten,byteswritten); + + ICCompress( + as->hic,flags, + as->lpCompressFormat, + as->compbuffer, + as->lpInputFormat,buffer, + &ckid,&xflags, + as->curframe,0xffffff/*framesize*/,as->aco.dwQuality, + as->lpPrevFormat,as->lpPrev + ); + ICDecompress( + as->hic, + flags, /* FIXME: check */ + as->lpCompressFormat, + as->compbuffer, + as->decompformat, + as->decompbuffer + ); + /* We now have a prev format for the next compress ... */ + as->lpPrevFormat = as->decompformat; + as->lpPrev = as->decompbuffer; + return S_OK; +} + +static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples) { + FIXME("(%p)->Delete(%ld,%ld)\n",iface,start,samples); + return E_FAIL; +} +static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread) { + FIXME("(%p)->ReadData(0x%08lx,%p,%p)\n",iface,fcc,lp,lpread); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size) { + FIXME("(%p)->WriteData(0x%08lx,%p,%ld)\n",iface,fcc,lp,size); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen) { + FIXME("(%p)->SetInfo(%p,%ld)\n",iface,info,infolen); + return E_FAIL; +} + +/*********************************************************************** + * AVIFileCreateStreamA + */ +HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE iface,PAVISTREAM *ppavi,AVISTREAMINFOA * psi) { + AVISTREAMINFOW psiw; + + /* Only the szName at the end is different */ + memcpy(&psiw,psi,sizeof(*psi)-sizeof(psi->szName)); + MultiByteToWideChar( CP_ACP, 0, psi->szName, -1, + psiw.szName, sizeof(psiw.szName) / sizeof(WCHAR) ); + return IAVIFile_CreateStream(iface,ppavi,&psiw); +} + +/*********************************************************************** + * AVIFileCreateStreamW + */ +HRESULT WINAPI AVIFileCreateStreamW(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi) { + return IAVIFile_CreateStream(iface,avis,asi); +} + + +/*********************************************************************** + * AVIFileGetStream + */ +HRESULT WINAPI AVIFileGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam) { + return IAVIFile_GetStream(iface,avis,fccType,lParam); +} + +/*********************************************************************** + * AVIFileInfoA + */ +HRESULT WINAPI AVIFileInfoA(PAVIFILE iface,LPAVIFILEINFOA afi,LONG size) { + AVIFILEINFOW afiw; + HRESULT hres; + + if (size < sizeof(AVIFILEINFOA)) + return AVIERR_BADSIZE; + hres = IAVIFile_Info(iface,&afiw,sizeof(afiw)); + memcpy(afi,&afiw,sizeof(*afi)-sizeof(afi->szFileType)); + WideCharToMultiByte( CP_ACP, 0, afiw.szFileType, -1, + afi->szFileType, sizeof(afi->szFileType), NULL, NULL ); + afi->szFileType[sizeof(afi->szFileType)-1] = 0; + return hres; +} + +/*********************************************************************** + * AVIStreamInfoW + */ +HRESULT WINAPI AVIStreamInfoW(PAVISTREAM iface,AVISTREAMINFOW *asi,LONG + size) { + return IAVIFile_Info(iface,asi,size); +} + +/*********************************************************************** + * AVIStreamInfoA + */ +HRESULT WINAPI AVIStreamInfoA(PAVISTREAM iface,AVISTREAMINFOA *asi,LONG + size) { + AVISTREAMINFOW asiw; + HRESULT hres; + + if (sizeszName, sizeof(asi->szName), NULL, NULL ); + asi->szName[sizeof(asi->szName)-1] = 0; + return hres; +} + +/*********************************************************************** + * AVIFileInfoW + */ +HRESULT WINAPI AVIFileInfoW(PAVIFILE iface,LPAVIFILEINFOW afi,LONG size) { + return IAVIFile_Info(iface,afi,size); +} + +/*********************************************************************** + * AVIMakeCompressedStream + */ +HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,PAVISTREAM ppsSource,AVICOMPRESSOPTIONS *aco,CLSID *pclsidHandler) { + char fcc[5]; + IAVIStreamImpl *as; + FIXME("(%p,%p,%p,%p)\n",ppsCompressed,ppsSource,aco,pclsidHandler); + fcc[4]='\0'; + memcpy(fcc,&(aco->fccType),4); + FIXME("\tfccType: '%s'\n",fcc); + memcpy(fcc,&(aco->fccHandler),4); + FIXME("\tfccHandler: '%s'\n",fcc); + FIXME("\tdwFlags: 0x%08lx\n",aco->dwFlags); + + /* we just create a duplicate for now */ + IAVIStream_AddRef(ppsSource); + *ppsCompressed = ppsSource; + as = (IAVIStreamImpl*)ppsSource; + + /* this is where the fun begins. Open a compressor and prepare it. */ + as->hic = ICOpen(aco->fccType,aco->fccHandler,ICMODE_COMPRESS); + + /* May happen. for instance if the codec is not able to compress */ + if (!as->hic) + return AVIERR_UNSUPPORTED; + + ICGetInfo(as->hic,&(as->icinfo),sizeof(ICINFO)); + FIXME("Opened compressor: '%s' '%s'\n",debugstr_w(as->icinfo.szName),debugstr_w(as->icinfo.szDescription)); + as->iscompressing = TRUE; + memcpy(&(as->aco),aco,sizeof(*aco)); + if (as->icinfo.dwFlags & VIDCF_COMPRESSFRAMES) { + ICCOMPRESSFRAMES icf; + + /* now what to fill in there ... Hmm */ + memset(&icf,0,sizeof(icf)); + icf.lDataRate = aco->dwBytesPerSecond; + icf.lQuality = aco->dwQuality; + icf.lKeyRate = aco->dwKeyFrameEvery; + + icf.GetData = (void *)0xdead4242; + icf.PutData = (void *)0xdead4243; + ICSendMessage(as->hic,ICM_COMPRESS_FRAMES_INFO,(LPARAM)&icf,sizeof(icf)); + } + return S_OK; +} + +/*********************************************************************** + * AVIStreamSetFormat + */ +HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM iface,LONG pos,LPVOID format,LONG formatsize) { + return IAVIStream_SetFormat(iface,pos,format,formatsize); +} + +/*********************************************************************** + * AVIStreamReadFormat + */ +HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM iface,LONG pos,LPVOID format,LONG *formatsize) { + return IAVIStream_ReadFormat(iface,pos,format,formatsize); +} + +/*********************************************************************** + * AVIStreamWrite( + */ +HRESULT WINAPI AVIStreamWrite(PAVISTREAM iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten) { + return IAVIStream_Write(iface,start,samples,buffer,buffersize,flags,sampwritten,byteswritten); +} + +/*********************************************************************** + * AVIStreamRead + */ +HRESULT WINAPI AVIStreamRead(PAVISTREAM iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread) { + return IAVIStream_Read(iface,start,samples,buffer,buffersize,bytesread,samplesread); +} + +/*********************************************************************** + * AVIStreamWriteData + */ +HRESULT WINAPI AVIStreamWriteData(PAVISTREAM iface,DWORD fcc,LPVOID lp,LONG size) { + return IAVIStream_WriteData(iface,fcc,lp,size); +} + +/*********************************************************************** + * AVIStreamReadData + */ +HRESULT WINAPI AVIStreamReadData(PAVISTREAM iface,DWORD fcc,LPVOID lp,LONG *lpread) { + return IAVIStream_ReadData(iface,fcc,lp,lpread); +} + +/*********************************************************************** + * AVIStreamStart + */ +LONG WINAPI AVIStreamStart(PAVISTREAM iface) { + AVISTREAMINFOW si; + + IAVIStream_Info(iface,&si,sizeof(si)); + return si.dwStart; +} + +/*********************************************************************** + * AVIStreamLength + */ +LONG WINAPI AVIStreamLength(PAVISTREAM iface) { + AVISTREAMINFOW si; + HRESULT ret; + + ret = IAVIStream_Info(iface,&si,sizeof(si)); + if (ret) /* error */ + return 1; + return si.dwLength; +} + +/*********************************************************************** + * AVIStreamRelease + */ +ULONG WINAPI AVIStreamRelease(PAVISTREAM iface) { + return IAVIStream_Release(iface); +} + +/*********************************************************************** + * AVIStreamGetFrameOpen + */ +PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM iface,LPBITMAPINFOHEADER bmi) { + FIXME("(%p)->(%p),stub!\n",iface,bmi); + return NULL; +} + +/*********************************************************************** + * AVIStreamGetFrame + */ +LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg,LONG pos) { + return IGetFrame_GetFrame(pg,pos); +} + +/*********************************************************************** + * AVIStreamGetFrameClose + */ +HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg) { + if (pg) IGetFrame_Release(pg); + return 0; +} + +/*********************************************************************** + * AVIFileRelease + */ +ULONG WINAPI AVIFileRelease(PAVIFILE iface) { + return IAVIFile_Release(iface); +} + +/*********************************************************************** + * AVIFileExit + */ +void WINAPI AVIFileExit(void) { + FIXME("(), stub.\n"); +} diff --git a/tags/GPGME-0-1-3/complus/guiddef.h b/tags/GPGME-0-1-3/complus/guiddef.h new file mode 100644 index 0000000..b329dad --- /dev/null +++ b/tags/GPGME-0-1-3/complus/guiddef.h @@ -0,0 +1,95 @@ +/* guiddef.h + + Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS + for a complete list) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* already defined bu Mingw32/cpd +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[ 8 ]; +} GUID; +#endif +*/ + +#undef DEFINE_GUID + +#ifdef INITGUID +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name = \ + { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + extern const GUID name +#endif + +#define DEFINE_OLEGUID(name, l, w1, w2) \ + DEFINE_GUID(name, l, w1, w2, 0xC0,0,0,0,0,0,0,0x46) + +#ifndef _GUIDDEF_H_ +#define _GUIDDEF_H_ + +/* typedef GUID *LPGUID; + typedef GUID CLSID,*LPCLSID; */ +typedef GUID IID,*LPIID; +typedef GUID FMTID,*LPFMTID; + +#if defined(__cplusplus) && !defined(CINTERFACE) +#define REFGUID const GUID & +#define REFCLSID const CLSID & +#define REFIID const IID & +#define REFFMTID const FMTID & +#else /* !defined(__cplusplus) && !defined(CINTERFACE) */ +#define REFGUID const GUID* const +#define REFCLSID const CLSID* const +#define REFIID const IID* const +#define REFFMTID const FMTID* const +#endif /* !defined(__cplusplus) && !defined(CINTERFACE) */ + +#if defined(__cplusplus) && !defined(CINTERFACE) +#define IsEqualGUID(rguid1, rguid2) (!memcmp(&(rguid1), &(rguid2), sizeof(GUID))) +#else /* defined(__cplusplus) && !defined(CINTERFACE) */ +#define IsEqualGUID(rguid1, rguid2) (!memcmp(rguid1, rguid2, sizeof(GUID))) +#endif /* defined(__cplusplus) && !defined(CINTERFACE) */ +#define IsEqualIID(riid1, riid2) IsEqualGUID(riid1, riid2) +#define IsEqualCLSID(rclsid1, rclsid2) IsEqualGUID(rclsid1, rclsid2) + +#if defined(__cplusplus) && !defined(CINTERFACE) +inline bool operator==(const GUID& guidOne, const GUID& guidOther) +{ + return !memcmp(&guidOne,&guidOther,sizeof(GUID)); +} +inline bool operator!=(const GUID& guidOne, const GUID& guidOther) +{ + return !(guidOne == guidOther); +} +#endif + +extern const IID GUID_NULL; +#define IID_NULL GUID_NULL +#define CLSID_NULL GUID_NULL +#define FMTID_NULL GUID_NULL + +#endif /* _GUIDDEF_H_ */ diff --git a/tags/GPGME-0-1-3/complus/ignupg.c b/tags/GPGME-0-1-3/complus/ignupg.c new file mode 100644 index 0000000..009d5db --- /dev/null +++ b/tags/GPGME-0-1-3/complus/ignupg.c @@ -0,0 +1,202 @@ +/* ignupg.c - COM+ class IGnuPG + * 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 + +#define INITGUID +#include "ignupg.h" + +/* + * Declare the interface implementation structures + */ +typedef struct IGnuPGImpl IGnuPGImpl; +typedef struct IClassFactoryImpl IClassFactoryImpl; + + +struct IGnuPGImpl { + /* IUnknown required stuff */ + ICOM_VFIELD (IGnuPG); + DWORD ref; + /* Our stuff */ + int foo; +}; + + +struct IClassFactoryImpl { + /* IUnknown fields */ + ICOM_VFIELD(IClassFactory); + DWORD ref; +}; + + + +/********************************************************** + ************** IGnuPG Implementation ******************* + **********************************************************/ + +static HRESULT WINAPI +IGnuPGImpl_QueryInterface (IGnuPG *iface, REFIID refiid, LPVOID *obj) +{ + ICOM_THIS (IGnuPGImpl,iface); + + fprintf (stderr,"(%p)->QueryInterface(%s,%p)\n", + This, "debugstr_guid(refiid)", obj); + if ( IsEqualGUID (&IID_IUnknown, refiid) + || !IsEqualGUID (&IID_IGnuPG, refiid) ) { + *obj = iface; + return 0; + } + *obj = NULL; + return E_NOINTERFACE; +} + + +static ULONG WINAPI +IGnuPGImpl_AddRef (IGnuPG *iface) +{ + ICOM_THIS (IGnuPGImpl,iface); + + return ++This->ref; +} + + +static ULONG WINAPI +IGnuPGImpl_Release (IGnuPG *iface) +{ + ICOM_THIS (IGnuPGImpl,iface); + + if (--This->ref) + return This->ref; + + HeapFree(GetProcessHeap(),0,iface); + return 0; +} + + + + +static ICOM_VTABLE(IGnuPG) gnupg_vtbl = +{ + /* IUnknow methods */ + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IGnuPGImpl_QueryInterface, + IGnuPGImpl_AddRef, + IGnuPGImpl_Release, + /* Our methods */ + +}; + + + +/*************************************************************** + ****************** GnuPG Factory **************************** + ***************************************************************/ + +static HRESULT WINAPI +GnuPGFactory_QueryInterface (IClassFactory *iface, REFIID refiid, LPVOID *obj) +{ + /*ICOM_THIS(IClassFactoryImpl,iface);*/ + return E_NOINTERFACE; +} + +static ULONG WINAPI +GnuPGFactory_AddRef (IClassFactory *iface) +{ + ICOM_THIS(IClassFactoryImpl,iface); + return ++(This->ref); +} + +static ULONG WINAPI +GnuPGFactory_Release (IClassFactory *iface) +{ + ICOM_THIS(IClassFactoryImpl,iface); + return --(This->ref); +} + +static HRESULT WINAPI +GnuPGFactory_CreateInstance (IClassFactory *iface, IUnknown *outer, + REFIID refiid, LPVOID *r_obj ) +{ + /*ICOM_THIS(IClassFactoryImpl,iface);*/ + + if ( IsEqualGUID (&IID_IGnuPG, refiid) ) { + IGnuPGImpl *obj; + + obj = HeapAlloc (GetProcessHeap(), 0, sizeof *obj ); + if ( !obj) + return E_OUTOFMEMORY; + + ICOM_VTBL(obj) = &gnupg_vtbl; + obj->ref = 1; + *r_obj = obj; + return 0; + } + *r_obj = NULL; + return E_NOINTERFACE; +} + +static HRESULT WINAPI +GnuPGFactory_LockServer (IClassFactory *iface, BOOL dolock ) +{ + /*ICOM_THIS(IClassFactoryImpl,iface);*/ + return 0; +} + +static ICOM_VTABLE(IClassFactory) gnupg_factory_vtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + GnuPGFactory_QueryInterface, + GnuPGFactory_AddRef, + GnuPGFactory_Release, + GnuPGFactory_CreateInstance, + GnuPGFactory_LockServer +}; +static IClassFactoryImpl GnuPG_CF = {&gnupg_factory_vtbl, 1 }; + + +IClassFactory * +gnupg_factory_new ( CLSID *r_clsid ) +{ + *r_clsid = CLSID_GnuPG; + IClassFactory_AddRef((IClassFactory*)&GnuPG_CF); + return (IClassFactory*)&GnuPG_CF; +} + +void +gnupg_factory_release ( IClassFactory *factory ) +{ + /* it's static - nothing to do */ +} + + + + + + + + + diff --git a/tags/GPGME-0-1-3/complus/ignupg.h b/tags/GPGME-0-1-3/complus/ignupg.h new file mode 100644 index 0000000..e9cf9a6 --- /dev/null +++ b/tags/GPGME-0-1-3/complus/ignupg.h @@ -0,0 +1,68 @@ +/* ignupg.h - COM+ class IGnuPG + * 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 IGNUPG_H +#define IGNUPG_H 1 + +#include "obj_base.h" + +DEFINE_GUID(CLSID_GnuPG, 0x42424242, 0x62e8, 0x11cf, + 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0); +DEFINE_GUID(IID_IGnuPG, 0x24242424, 0x4981, 0x11CE, + 0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60); +typedef struct IGnuPG IGnuPG; + + + +#define ICOM_INTERFACE IGnuPG + +#define IGnuPG_METHODS \ + ICOM_METHOD1(HRESULT,Initialize, REFIID,) \ + ICOM_METHOD1(HRESULT,EnumDevices, LPVOID,) + +#define IGnuPG_IMETHODS \ + IUnknown_IMETHODS \ + IGnuPG_METHODS + +ICOM_DEFINE(IGnuPG,IUnknown) +#undef ICOM_INTERFACE + + +/*** IUnknown methods ***/ +#define IGnuPG_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IGnuPG_AddRef(p) ICOM_CALL (AddRef,p) +#define IGnuPG_Release(p) ICOM_CALL (Release,p) +/*** IGnuPG methods ***/ +#define IGnuPG_Initialize(p,a) ICOM_CALL1(Initialize,p,a) +#define IGnuPG_EnumDevices(p,a,b) ICOM_CALL2(EnumDevice,p,a,b) + + +#endif /*IGNUPG_H*/ + + + + + + + + + + + diff --git a/tags/GPGME-0-1-3/complus/main.c b/tags/GPGME-0-1-3/complus/main.c new file mode 100644 index 0000000..519d2bc --- /dev/null +++ b/tags/GPGME-0-1-3/complus/main.c @@ -0,0 +1,285 @@ +/* main.c - COM+ component to access GnuPG + * Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "obj_base.h" + +#include "argparse.h" + +#include "main.h" + + +static void register_server (void); +static void unregister_server (void); +static void enter_complus (void); + + +enum cmd_and_opt_values { aNull = 0, + oQuiet = 'q', + oVerbose = 'v', + + oNoVerbose = 500, + oOptions, + oDebug, + oDebugAll, + oNoGreeting, + oNoOptions, + oHomedir, + oGPGBinary, + oRegServer, + oUnregServer, + oEmbedding, +aTest }; + + +static ARGPARSE_OPTS opts[] = { + + { 301, NULL, 0, N_("@Options:\n ") }, + + { oVerbose, "verbose", 0, N_("verbose") }, + { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, + { oOptions, "options" , 2, N_("read options from file")}, + { oDebug, "debug" ,4|16, N_("set debugging flags")}, + { oDebugAll, "debug-all" ,0, N_("enable full debugging")}, + { oGPGBinary, "gpg-program", 2 , "@" }, + { oRegServer, "RegServer" , 0, "@" }, + { oUnregServer, "UnregServer" , 0, "@" }, + { oEmbedding, "Embedding" , 0, "@" }, +{0} }; + + + + +static const char * +my_strusage( int level ) +{ + const char *p; + switch( level ) { + case 11: p = "gpgme"; + break; + case 13: p = VERSION; break; + /*case 17: p = PRINTABLE_OS_NAME; break;*/ + case 19: p = + _("Please report bugs to .\n"); + break; + case 1: + case 40: p = + _("Usage: gpgme [options] (-h for help)"); + break; + case 41: p = + _("Syntax: gpgme [options]\n" + "GnuPG COM+ component\n"); + break; + + default: p = NULL; + } + return p; +} + + +int +main (int argc, char **argv ) +{ + ARGPARSE_ARGS pargs; + int orig_argc; + char **orig_argv; + FILE *configfp = NULL; + char *configname = NULL; + unsigned configlineno; + int parse_debug = 0; + int default_config =1; + int greeting = 0; + int nogreeting = 0; + int action = 0; + + set_strusage( my_strusage ); + /*log_set_name ("gpa"); not yet implemented in logging.c */ + + opt.homedir = getenv("GNUPGHOME"); + if( !opt.homedir || !*opt.homedir ) { + #ifdef HAVE_DRIVE_LETTERS + opt.homedir = "c:/gnupg"; + #else + opt.homedir = "~/.gnupg"; + #endif + } + + /* check whether we have a config file on the commandline */ + orig_argc = argc; + orig_argv = argv; + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */ + while( arg_parse( &pargs, opts) ) { + if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll ) + parse_debug++; + else if( pargs.r_opt == oOptions ) { + /* yes there is one, so we do not try the default one, but + * read the option file when it is encountered at the commandline + */ + default_config = 0; + } + else if( pargs.r_opt == oNoOptions ) + default_config = 0; /* --no-options */ + else if( pargs.r_opt == oHomedir ) + opt.homedir = pargs.r.ret_str; + } + + if( default_config ) + configname = make_filename(opt.homedir, "gpgme.conf", NULL ); + + + argc = orig_argc; + argv = orig_argv; + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags= 1 | (1<<5); /* do not remove the args, allow one dash */ + next_pass: + if( configname ) { + configlineno = 0; + configfp = fopen( configname, "r" ); + if( !configfp ) { + if( default_config ) { + if( parse_debug ) + log_info(_("NOTE: no default option file `%s'\n"), + configname ); + } + else { + log_error(_("option file `%s': %s\n"), + configname, strerror(errno) ); + exit(2); + } + free(configname); configname = NULL; + } + if( parse_debug && configname ) + log_info(_("reading options from `%s'\n"), configname ); + default_config = 0; + } + + while( optfile_parse( configfp, configname, &configlineno, + &pargs, opts) ) { + switch( pargs.r_opt ) { + case oQuiet: opt.quiet = 1; break; + case oVerbose: opt.verbose++; break; + + case oDebug: opt.debug |= pargs.r.ret_ulong; break; + case oDebugAll: opt.debug = ~0; break; + + case oOptions: + /* config files may not be nested (silently ignore them) */ + if( !configfp ) { + free(configname); + configname = xstrdup(pargs.r.ret_str); + goto next_pass; + } + break; + case oNoGreeting: nogreeting = 1; break; + case oNoVerbose: opt.verbose = 0; break; + case oNoOptions: break; /* no-options */ + case oHomedir: opt.homedir = pargs.r.ret_str; break; + case oGPGBinary: break; + + case oRegServer: action = 1; break; + case oUnregServer: action = 2; break; + case oEmbedding: action = 3; break; + + default : pargs.err = configfp? 1:2; break; + } + } + if( configfp ) { + fclose( configfp ); + configfp = NULL; + free(configname); configname = NULL; + goto next_pass; + } + free( configname ); configname = NULL; + if( log_get_errorcount(0) ) + exit(2); + if( nogreeting ) + greeting = 0; + + if( greeting ) { + fprintf(stderr, "%s %s; %s\n", + strusage(11), strusage(13), strusage(14) ); + fprintf(stderr, "%s\n", strusage(15) ); + } + #ifdef IS_DEVELOPMENT_VERSION + log_info("NOTE: this is a development version!\n"); + #endif + + if ( action == 1 ) + register_server (); + else if (action == 2 ) + unregister_server (); + else if (action == 3 ) + enter_complus (); + else { + fprintf (stderr, "This is a COM+ component with no user interface.\n" + "gpgme --help will give you a list of options\n" ); + exit (1); + } + + return 0; +} + +static void +register_server () +{ +} + +static void +unregister_server () +{ +} + +static void +enter_complus () +{ + HANDLE running; + int reg; + IClassFactory *factory; + CLSID clsid; + + CoInitializeEx (NULL, COINIT_MULTITHREADED); + running = CreateEvent (NULL, FALSE, FALSE, NULL ); + + factory = gnupg_factory_new ( &clsid ); + CoRegisterClassObject (&clsid, (IUnknown*)factory, + CLSCTX_LOCAL_SERVER, + REGCLS_SUSPENDED|REGCLS_MULTIPLEUSE, ® ); + CoResumeClassObjects (); + + WaitForSingleObject ( running, INFINITE ); + CloseHandle (running); + CoRevokeClassObject ( reg ); + gnupg_factory_release (factory); + CoUninitialize (); +} + + diff --git a/tags/GPGME-0-1-3/complus/main.h b/tags/GPGME-0-1-3/complus/main.h new file mode 100644 index 0000000..472b8cd --- /dev/null +++ b/tags/GPGME-0-1-3/complus/main.h @@ -0,0 +1,54 @@ +/* main.h - GPGME COM+ component + * Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef COMPLUS_MAIN_H +#define COMPLUS_MAIN_H + +#include "xmalloc.h" +#include "stringhelp.h" +#include "logging.h" + + +#define _(a) (a) +#define N_(a) (a) + + +struct { + int verbose; + int quiet; + unsigned int debug; + char *homedir; +} opt; + + +/*-- ignupg.c --*/ +IClassFactory *gnupg_factory_new ( CLSID *r_clsid ); +void gnupg_factory_release ( IClassFactory *factory ); + + + +#endif /* COMPLUS_MAIN_H */ + + + + + + + diff --git a/tags/GPGME-0-1-3/complus/obj_base.h b/tags/GPGME-0-1-3/complus/obj_base.h new file mode 100644 index 0000000..8707ae9 --- /dev/null +++ b/tags/GPGME-0-1-3/complus/obj_base.h @@ -0,0 +1,800 @@ +/* obj_base.h - This file defines the macros and types necessary to + define COM interfaces, and the three most basic COM interfaces: + IUnknown, IMalloc and IClassFactory. + + Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS + for a complete list) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __WINE_WINE_OBJ_BASE_H +#define __WINE_WINE_OBJ_BASE_H + +/* check these values! */ +#define E_NOINTERFACE 0x80040002 +#define E_OUTOFMEMORY 0x8007000E + +/***************************************************************************** + * define ICOM_MSVTABLE_COMPAT + * to implement the microsoft com vtable compatibility workaround for g++. + * + * NOTE: Turning this option on will produce a winelib that is incompatible + * with the binary emulator. + * + * If the compiler supports the com_interface attribute, leave this off, and + * define the ICOM_USE_COM_INTERFACE_ATTRIBUTE macro below. This may also + * require the addition of the -vtable-thunks option for g++. + * + * If you aren't interested in Winelib C++ compatibility at all, leave both + * options off. + * + * The preferable method for using ICOM_USE_COM_INTERFACE_ATTRIBUTE macro + * would be to define it only for your Winelib application. This allows you + * to have both binary and Winelib compatibility for C and C++ at the same + * time :) + */ +/* #define ICOM_MSVTABLE_COMPAT 1 */ +/* #define ICOM_USE_COM_INTERFACE_ATTRIBUTE 1 */ + +/***************************************************************************** + * Defines the basic types + */ +#include "wtypes.h" +#include "guiddef.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef NONAMELESSSTRUCT +#define LISet32(li, v) ((li).HighPart = (v) < 0 ? -1 : 0, (li).LowPart = (v)) +#define ULISet32(li, v) ((li).HighPart = 0, (li).LowPart = (v)) +#else +#define LISet32(li, v) ((li).s.HighPart = (v) < 0 ? -1 : 0, (li).s.LowPart = (v)) +#define ULISet32(li, v) ((li).s.HighPart = 0, (li).s.LowPart = (v)) +#endif + +/***************************************************************************** + * GUID API + */ +HRESULT WINAPI StringFromCLSID16(REFCLSID id, LPOLESTR16*); +HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR*); + +HRESULT WINAPI CLSIDFromString16(LPCOLESTR16, CLSID *); +HRESULT WINAPI CLSIDFromString(LPCOLESTR, CLSID *); + +HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid); +HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid); + +HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID); + + +INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax); + + +/***************************************************************************** + * Macros to define a COM interface + */ +/* + * The goal of the following set of definitions is to provide a way to use the same + * header file definitions to provide both a C interface and a C++ object oriented + * interface to COM interfaces. The type of interface is selected automatically + * depending on the language but it is always possible to get the C interface in C++ + * by defining CINTERFACE. + * + * It is based on the following assumptions: + * - all COM interfaces derive from IUnknown, this should not be a problem. + * - the header file only defines the interface, the actual fields are defined + * separately in the C file implementing the interface. + * + * The natural approach to this problem would be to make sure we get a C++ class and + * virtual methods in C++ and a structure with a table of pointer to functions in C. + * Unfortunately the layout of the virtual table is compiler specific, the layout of + * g++ virtual tables is not the same as that of an egcs virtual table which is not the + * same as that generated by Visual C+. There are workarounds to make the virtual tables + * compatible via padding but unfortunately the one which is imposed to the WINE emulator + * by the Windows binaries, i.e. the Visual C++ one, is the most compact of all. + * + * So the solution I finally adopted does not use virtual tables. Instead I use inline + * non virtual methods that dereference the method pointer themselves and perform the call. + * + * Let's take Direct3D as an example: + * + * #define ICOM_INTERFACE IDirect3D + * #define IDirect3D_METHODS \ + * ICOM_METHOD1(HRESULT,Initialize, REFIID,) \ + * ICOM_METHOD2(HRESULT,EnumDevices, LPD3DENUMDEVICESCALLBACK,, LPVOID,) \ + * ICOM_METHOD2(HRESULT,CreateLight, LPDIRECT3DLIGHT*,, IUnknown*,) \ + * ICOM_METHOD2(HRESULT,CreateMaterial,LPDIRECT3DMATERIAL*,, IUnknown*,) \ + * ICOM_METHOD2(HRESULT,CreateViewport,LPDIRECT3DVIEWPORT*,, IUnknown*,) \ + * ICOM_METHOD2(HRESULT,FindDevice, LPD3DFINDDEVICESEARCH,, LPD3DFINDDEVICERESULT,) + * #define IDirect3D_IMETHODS \ + * IUnknown_IMETHODS \ + * IDirect3D_METHODS + * ICOM_DEFINE(IDirect3D,IUnknown) + * #undef ICOM_INTERFACE + * + * #ifdef ICOM_CINTERFACE + * // *** IUnknown methods *** // + * #define IDirect3D_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) + * #define IDirect3D_AddRef(p) ICOM_CALL (AddRef,p) + * #define IDirect3D_Release(p) ICOM_CALL (Release,p) + * // *** IDirect3D methods *** // + * #define IDirect3D_Initialize(p,a) ICOM_CALL1(Initialize,p,a) + * #define IDirect3D_EnumDevices(p,a,b) ICOM_CALL2(EnumDevice,p,a,b) + * #define IDirect3D_CreateLight(p,a,b) ICOM_CALL2(CreateLight,p,a,b) + * #define IDirect3D_CreateMaterial(p,a,b) ICOM_CALL2(CreateMaterial,p,a,b) + * #define IDirect3D_CreateViewport(p,a,b) ICOM_CALL2(CreateViewport,p,a,b) + * #define IDirect3D_FindDevice(p,a,b) ICOM_CALL2(FindDevice,p,a,b) + * #endif + * + * Comments: + * - The ICOM_INTERFACE macro is used in the ICOM_METHOD macros to define the type of the 'this' + * pointer. Defining this macro here saves us the trouble of having to repeat the interface + * name everywhere. Note however that because of the way macros work, a macro like ICOM_METHOD1 + * cannot use 'ICOM_INTERFACE##_VTABLE' because this would give 'ICOM_INTERFACE_VTABLE' and not + * 'IDirect3D_VTABLE'. + * - ICOM_METHODS defines the methods specific to this interface. It is then aggregated with the + * inherited methods to form ICOM_IMETHODS. + * - ICOM_IMETHODS defines the list of methods that are inheritable from this interface. It must + * be written manually (rather than using a macro to generate the equivalent code) to avoid + * macro recursion (which compilers don't like). + * - The ICOM_DEFINE finally declares all the structures necessary for the interface. We have to + * explicitly use the interface name for macro expansion reasons again. + * Inherited methods are inherited in C by using the IDirect3D_METHODS macro and the parent's + * Xxx_IMETHODS macro. In C++ we need only use the IDirect3D_METHODS since method inheritance + * is taken care of by the language. + * - In C++ the ICOM_METHOD macros generate a function prototype and a call to a function pointer + * method. This means using once 't1 p1, t2 p2, ...' and once 'p1, p2' without the types. The + * only way I found to handle this is to have one ICOM_METHOD macro per number of parameters and + * to have it take only the type information (with const if necessary) as parameters. + * The 'undef ICOM_INTERFACE' is here to remind you that using ICOM_INTERFACE in the following + * macros will not work. This time it's because the ICOM_CALL macro expansion is done only once + * the 'IDirect3D_Xxx' macro is expanded. And by that time ICOM_INTERFACE will be long gone + * anyway. + * - You may have noticed the double commas after each parameter type. This allows you to put the + * name of that parameter which I think is good for documentation. It is not required and since + * I did not know what to put there for this example (I could only find doc about IDirect3D2), + * I left them blank. + * - Finally the set of 'IDirect3D_Xxx' macros is a standard set of macros defined to ease access + * to the interface methods in C. Unfortunately I don't see any way to avoid having to duplicate + * the inherited method definitions there. This time I could have used a trick to use only one + * macro whatever the number of parameters but I prefered to have it work the same way as above. + * - You probably have noticed that we don't define the fields we need to actually implement this + * interface: reference count, pointer to other resources and miscellaneous fields. That's + * because these interfaces are just that: interfaces. They may be implemented more than once, in + * different contexts and sometimes not even in Wine. Thus it would not make sense to impose + * that the interface contains some specific fields. + * + * + * In C this gives: + * typedef struct IDirect3DVtbl IDirect3DVtbl; + * struct IDirect3D { + * IDirect3DVtbl* lpVtbl; + * }; + * struct IDirect3DVtbl { + * HRESULT (*fnQueryInterface)(IDirect3D* me, REFIID riid, LPVOID* ppvObj); + * ULONG (*fnQueryInterface)(IDirect3D* me); + * ULONG (*fnQueryInterface)(IDirect3D* me); + * HRESULT (*fnInitialize)(IDirect3D* me, REFIID a); + * HRESULT (*fnEnumDevices)(IDirect3D* me, LPD3DENUMDEVICESCALLBACK a, LPVOID b); + * HRESULT (*fnCreateLight)(IDirect3D* me, LPDIRECT3DLIGHT* a, IUnknown* b); + * HRESULT (*fnCreateMaterial)(IDirect3D* me, LPDIRECT3DMATERIAL* a, IUnknown* b); + * HRESULT (*fnCreateViewport)(IDirect3D* me, LPDIRECT3DVIEWPORT* a, IUnknown* b); + * HRESULT (*fnFindDevice)(IDirect3D* me, LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b); + * }; + * + * #ifdef ICOM_CINTERFACE + * // *** IUnknown methods *** // + * #define IDirect3D_QueryInterface(p,a,b) (p)->lpVtbl->fnQueryInterface(p,a,b) + * #define IDirect3D_AddRef(p) (p)->lpVtbl->fnAddRef(p) + * #define IDirect3D_Release(p) (p)->lpVtbl->fnRelease(p) + * // *** IDirect3D methods *** // + * #define IDirect3D_Initialize(p,a) (p)->lpVtbl->fnInitialize(p,a) + * #define IDirect3D_EnumDevices(p,a,b) (p)->lpVtbl->fnEnumDevice(p,a,b) + * #define IDirect3D_CreateLight(p,a,b) (p)->lpVtbl->fnCreateLight(p,a,b) + * #define IDirect3D_CreateMaterial(p,a,b) (p)->lpVtbl->fnCreateMaterial(p,a,b) + * #define IDirect3D_CreateViewport(p,a,b) (p)->lpVtbl->fnCreateViewport(p,a,b) + * #define IDirect3D_FindDevice(p,a,b) (p)->lpVtbl->fnFindDevice(p,a,b) + * #endif + * + * Comments: + * - IDirect3D only contains a pointer to the IDirect3D virtual/jump table. This is the only thing + * the user needs to know to use the interface. Of course the structure we will define to + * implement this interface will have more fields but the first one will match this pointer. + * - The code generated by ICOM_DEFINE defines both the structure representing the interface and + * the structure for the jump table. ICOM_DEFINE uses the parent's Xxx_IMETHODS macro to + * automatically repeat the prototypes of all the inherited methods and then uses IDirect3D_METHODS + * to define the IDirect3D methods. + * - Each method is declared as a pointer to function field in the jump table. The implementation + * will fill this jump table with appropriate values, probably using a static variable, and + * initialize the lpVtbl field to point to this variable. + * - The IDirect3D_Xxx macros then just derefence the lpVtbl pointer and use the function pointer + * corresponding to the macro name. This emulates the behavior of a virtual table and should be + * just as fast. + * - This C code should be quite compatible with the Windows headers both for code that uses COM + * interfaces and for code implementing a COM interface. + * + * + * And in C++ (with gcc's g++): + * + * typedef struct IDirect3D: public IUnknown { + * private: HRESULT (*fnInitialize)(IDirect3D* me, REFIID a); + * public: inline HRESULT Initialize(REFIID a) { return ((IDirect3D*)t.lpVtbl)->fnInitialize(this,a); }; + * private: HRESULT (*fnEnumDevices)(IDirect3D* me, LPD3DENUMDEVICESCALLBACK a, LPVOID b); + * public: inline HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK a, LPVOID b) + * { return ((IDirect3D*)t.lpVtbl)->fnEnumDevices(this,a,b); }; + * private: HRESULT (*fnCreateLight)(IDirect3D* me, LPDIRECT3DLIGHT* a, IUnknown* b); + * public: inline HRESULT CreateLight(LPDIRECT3DLIGHT* a, IUnknown* b) + * { return ((IDirect3D*)t.lpVtbl)->fnCreateLight(this,a,b); }; + * private: HRESULT (*fnCreateMaterial)(IDirect3D* me, LPDIRECT3DMATERIAL* a, IUnknown* b); + * public: inline HRESULT CreateMaterial(LPDIRECT3DMATERIAL* a, IUnknown* b) + * { return ((IDirect3D*)t.lpVtbl)->fnCreateMaterial(this,a,b); }; + * private: HRESULT (*fnCreateViewport)(IDirect3D* me, LPDIRECT3DVIEWPORT* a, IUnknown* b); + * public: inline HRESULT CreateViewport(LPDIRECT3DVIEWPORT* a, IUnknown* b) + * { return ((IDirect3D*)t.lpVtbl)->fnCreateViewport(this,a,b); }; + * private: HRESULT (*fnFindDevice)(IDirect3D* me, LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b); + * public: inline HRESULT FindDevice(LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b) + * { return ((IDirect3D*)t.lpVtbl)->fnFindDevice(this,a,b); }; + * }; + * + * Comments: + * - In C++ IDirect3D does double duty as both the virtual/jump table and as the interface + * definition. The reason for this is to avoid having to duplicate the mehod definitions: once + * to have the function pointers in the jump table and once to have the methods in the interface + * class. Here one macro can generate both. This means though that the first pointer, t.lpVtbl + * defined in IUnknown, must be interpreted as the jump table pointer if we interpret the + * structure as the the interface class, and as the function pointer to the QueryInterface + * method, t.fnQueryInterface, if we interpret the structure as the jump table. Fortunately this + * gymnastic is entirely taken care of in the header of IUnknown. + * - Of course in C++ we use inheritance so that we don't have to duplicate the method definitions. + * - Since IDirect3D does double duty, each ICOM_METHOD macro defines both a function pointer and + * a non-vritual inline method which dereferences it and calls it. This way this method behaves + * just like a virtual method but does not create a true C++ virtual table which would break the + * structure layout. If you look at the implementation of these methods you'll notice that they + * would not work for void functions. We have to return something and fortunately this seems to + * be what all the COM methods do (otherwise we would need another set of macros). + * - Note how the ICOM_METHOD generates both function prototypes mixing types and formal parameter + * names and the method invocation using only the formal parameter name. This is the reason why + * we need different macros to handle different numbers of parameters. + * - Finally there is no IDirect3D_Xxx macro. These are not needed in C++ unless the CINTERFACE + * macro is defined in which case we would not be here. + * - This C++ code works well for code that just uses COM interfaces. But it will not work with + * C++ code implement a COM interface. That's because such code assumes the interface methods + * are declared as virtual C++ methods which is not the case here. + * + * + * Implementing a COM interface. + * + * This continues the above example. This example assumes that the implementation is in C. + * + * typedef struct _IDirect3D { + * void* lpVtbl; + * // ... + * + * } _IDirect3D; + * + * static ICOM_VTABLE(IDirect3D) d3dvt; + * + * // implement the IDirect3D methods here + * + * int IDirect3D_fnQueryInterface(IDirect3D* me) + * { + * ICOM_THIS(IDirect3D,me); + * // ... + * } + * + * // ... + * + * static ICOM_VTABLE(IDirect3D) d3dvt = { + * ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + * IDirect3D_fnQueryInterface, + * IDirect3D_fnAdd, + * IDirect3D_fnAdd2, + * IDirect3D_fnInitialize, + * IDirect3D_fnSetWidth + * }; + * + * Comments: + * - We first define what the interface really contains. This is th e_IDirect3D structure. The + * first field must of course be the virtual table pointer. Everything else is free. + * - Then we predeclare our static virtual table variable, we will need its address in some + * methods to initialize the virtual table pointer of the returned interface objects. + * - Then we implement the interface methods. To match what has been declared in the header file + * they must take a pointer to a IDirect3D structure and we must cast it to an _IDirect3D so that + * we can manipulate the fields. This is performed by the ICOM_THIS macro. + * - Finally we initialize the virtual table. + */ + + +#define ICOM_VTABLE(iface) iface##Vtbl +#define ICOM_VFIELD(iface) ICOM_VTABLE(iface)* lpVtbl +#define ICOM_VTBL(iface) (iface)->lpVtbl + + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define ICOM_CINTERFACE 1 +#endif + +#ifndef ICOM_CINTERFACE +/* C++ interface */ + +#define ICOM_METHOD(ret,xfn) \ + public: virtual ret CALLBACK (xfn)(void) = 0; +#define ICOM_METHOD1(ret,xfn,ta,na) \ + public: virtual ret CALLBACK (xfn)(ta a) = 0; +#define ICOM_METHOD2(ret,xfn,ta,na,tb,nb) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b) = 0; +#define ICOM_METHOD3(ret,xfn,ta,na,tb,nb,tc,nc) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c) = 0; +#define ICOM_METHOD4(ret,xfn,ta,na,tb,nb,tc,nc,td,nd) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d) = 0; +#define ICOM_METHOD5(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e) = 0; +#define ICOM_METHOD6(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f) = 0; +#define ICOM_METHOD7(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g) = 0; +#define ICOM_METHOD8(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h) = 0; +#define ICOM_METHOD9(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i) = 0; +#define ICOM_METHOD10(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j) = 0; +#define ICOM_METHOD11(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k) = 0; + + +#define ICOM_VMETHOD(xfn) \ + public: virtual void CALLBACK (xfn)(void) = 0; +#define ICOM_VMETHOD1(xfn,ta,na) \ + public: virtual void CALLBACK (xfn)(ta a) = 0; +#define ICOM_VMETHOD2(xfn,ta,na,tb,nb) \ + public: virtual void CALLBACK (xfn)(ta a,tb b) = 0; +#define ICOM_VMETHOD3(xfn,ta,na,tb,nb,tc,nc) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c) = 0; +#define ICOM_VMETHOD4(xfn,ta,na,tb,nb,tc,nc,td,nd) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d) = 0; +#define ICOM_VMETHOD5(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e) = 0; +#define ICOM_VMETHOD6(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f) = 0; +#define ICOM_VMETHOD7(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g) = 0; +#define ICOM_VMETHOD8(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h) = 0; +#define ICOM_VMETHOD9(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i) = 0; +#define ICOM_VMETHOD10(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i, tj j) = 0; +#define ICOM_VMETHOD11(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i, tj j, tk k) = 0; + + +#ifdef ICOM_USE_COM_INTERFACE_ATTRIBUTE + +#define ICOM_DEFINE(iface,ibase) \ + typedef struct iface: public ibase { \ + iface##_METHODS \ + } __attribute__ ((com_interface)); + +#else + +#define ICOM_DEFINE(iface,ibase) \ + typedef struct iface: public ibase { \ + iface##_METHODS \ + }; + +#endif /* ICOM_USE_COM_INTERFACE_ATTRIBUTE */ + +#define ICOM_CALL(xfn, p) (p)->xfn() +#define ICOM_CALL1(xfn, p,a) (p)->xfn(a) +#define ICOM_CALL2(xfn, p,a,b) (p)->xfn(a,b) +#define ICOM_CALL3(xfn, p,a,b,c) (p)->xfn(a,b,c) +#define ICOM_CALL4(xfn, p,a,b,c,d) (p)->xfn(a,b,c,d) +#define ICOM_CALL5(xfn, p,a,b,c,d,e) (p)->xfn(a,b,c,d,e) +#define ICOM_CALL6(xfn, p,a,b,c,d,e,f) (p)->xfn(a,b,c,d,e,f) +#define ICOM_CALL7(xfn, p,a,b,c,d,e,f,g) (p)->xfn(a,b,c,d,e,f,g) +#define ICOM_CALL8(xfn, p,a,b,c,d,e,f,g,h) (p)->xfn(a,b,c,d,e,f,g,h) +#define ICOM_CALL9(xfn, p,a,b,c,d,e,f,g,h,i) (p)->xfn(a,b,c,d,e,f,g,h,i) +#define ICOM_CALL10(xfn, p,a,b,c,d,e,f,g,h,i,j) (p)->xfn(a,b,c,d,e,f,g,h,i,j) +#define ICOM_CALL11(xfn, p,a,b,c,d,e,f,g,h,i,j,k) (p)->xfn(a,b,c,d,e,f,g,h,i,j,k) + + +#else +/* C interface */ + + +#ifdef __WINE__ + +#define ICOM_METHOD(ret,xfn) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me); +#define ICOM_METHOD1(ret,xfn,ta,na) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a); +#define ICOM_METHOD2(ret,xfn,ta,na,tb,nb) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_METHOD3(ret,xfn,ta,na,tb,nb,tc,nc) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_METHOD4(ret,xfn,ta,na,tb,nb,tc,nc,td,nd) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_METHOD5(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_METHOD6(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_METHOD7(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_METHOD8(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); +#define ICOM_METHOD9(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_METHOD10(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_METHOD11(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_VMETHOD(xfn) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me); +#define ICOM_VMETHOD1(xfn,ta,na) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a); +#define ICOM_VMETHOD2(xfn,ta,na,tb,nb) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_VMETHOD3(xfn,ta,na,tb,nb,tc,nc) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_VMETHOD4(xfn,ta,na,tb,nb,tc,nc,td,nd) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_VMETHOD5(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_VMETHOD6(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_VMETHOD7(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_VMETHOD8(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,nh) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); +#define ICOM_VMETHOD9(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ni) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_VMETHOD10(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,nj) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_VMETHOD11(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,nk) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_CALL(xfn, p) ICOM_VTBL(p)->fn##xfn(p) +#define ICOM_CALL1(xfn, p,a) ICOM_VTBL(p)->fn##xfn(p,a) +#define ICOM_CALL2(xfn, p,a,b) ICOM_VTBL(p)->fn##xfn(p,a,b) +#define ICOM_CALL3(xfn, p,a,b,c) ICOM_VTBL(p)->fn##xfn(p,a,b,c) +#define ICOM_CALL4(xfn, p,a,b,c,d) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d) +#define ICOM_CALL5(xfn, p,a,b,c,d,e) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e) +#define ICOM_CALL6(xfn, p,a,b,c,d,e,f) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f) +#define ICOM_CALL7(xfn, p,a,b,c,d,e,f,g) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g) +#define ICOM_CALL8(xfn, p,a,b,c,d,e,f,g,h) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g,h) +#define ICOM_CALL9(xfn, p,a,b,c,d,e,f,g,h,i) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g,h,i) +#define ICOM_CALL10(xfn, p,a,b,c,d,e,f,g,h,i,j) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g,h,i,j) +#define ICOM_CALL11(xfn, p,a,b,c,d,e,f,g,h,i,j,k) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g,h,i,j,k) + +#else + +/* WINELIB case */ + +#define ICOM_METHOD(ret,xfn) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me); +#define ICOM_METHOD1(ret,xfn,ta,na) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a); +#define ICOM_METHOD2(ret,xfn,ta,na,tb,nb) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_METHOD3(ret,xfn,ta,na,tb,nb,tc,nc) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_METHOD4(ret,xfn,ta,na,tb,nb,tc,nc,td,nd) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_METHOD5(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_METHOD6(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_METHOD7(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_METHOD8(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); +#define ICOM_METHOD9(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_METHOD10(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_METHOD11(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_VMETHOD(xfn) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me); +#define ICOM_VMETHOD1(xfn,ta,na) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a); +#define ICOM_VMETHOD2(xfn,ta,na,tb,nb) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_VMETHOD3(xfn,ta,na,tb,nb,tc,nc) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_VMETHOD4(xfn,ta,na,tb,nb,tc,nc,td,nd) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_VMETHOD5(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_VMETHOD6(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_VMETHOD7(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_VMETHOD8(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,nh) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); +#define ICOM_VMETHOD9(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ni) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_VMETHOD10(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,nj) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_VMETHOD11(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,nk) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_CVMETHOD(xfn) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me); +#define ICOM_CVMETHOD1(xfn,ta,na) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a); +#define ICOM_CVMETHOD2(xfn,ta,na,tb,nb) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_CVMETHOD3(xfn,ta,na,tb,nb,tc,nc) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_CVMETHOD4(xfn,ta,na,tb,nb,tc,nc,td,nd) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_CVMETHOD5(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_CVMETHOD6(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_CVMETHOD7(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_CVMETHOD8(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); + +#define ICOM_CVMETHOD9(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_CVMETHOD10(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_CVMETHOD11(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_CALL(xfn, p) ICOM_VTBL(p)->xfn(p) +#define ICOM_CALL1(xfn, p,a) ICOM_VTBL(p)->xfn(p,a) +#define ICOM_CALL2(xfn, p,a,b) ICOM_VTBL(p)->xfn(p,a,b) +#define ICOM_CALL3(xfn, p,a,b,c) ICOM_VTBL(p)->xfn(p,a,b,c) +#define ICOM_CALL4(xfn, p,a,b,c,d) ICOM_VTBL(p)->xfn(p,a,b,c,d) +#define ICOM_CALL5(xfn, p,a,b,c,d,e) ICOM_VTBL(p)->xfn(p,a,b,c,d,e) +#define ICOM_CALL6(xfn, p,a,b,c,d,e,f) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f) +#define ICOM_CALL7(xfn, p,a,b,c,d,e,f,g) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g) +#define ICOM_CALL8(xfn, p,a,b,c,d,e,f,g,h) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g,h) +#define ICOM_CALL9(xfn, p,a,b,c,d,e,f,g,h,i) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g,h,i) +#define ICOM_CALL10(xfn, p,a,b,c,d,e,f,g,h,i,j) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g,h,i,j) +#define ICOM_CALL11(xfn, p,a,b,c,d,e,f,g,h,i,j,k) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g,h,i,j,k) + +#endif /* __WINE__ */ + +#ifdef ICOM_MSVTABLE_COMPAT +#define ICOM_DEFINE(iface,ibase) \ + typedef struct ICOM_VTABLE(iface) ICOM_VTABLE(iface); \ + struct iface { \ + const ICOM_VFIELD(iface); \ + }; \ + struct ICOM_VTABLE(iface) { \ + long dummyRTTI1; \ + long dummyRTTI2; \ + ibase##_IMETHODS \ + iface##_METHODS \ + }; +#define ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE 0,0, + +#else +#define ICOM_DEFINE(iface,ibase) \ + typedef struct ICOM_VTABLE(iface) ICOM_VTABLE(iface); \ + struct iface { \ + const ICOM_VFIELD(iface); \ + }; \ + struct ICOM_VTABLE(iface) { \ + ibase##_IMETHODS \ + iface##_METHODS \ + }; +#define ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE +#endif /* ICOM_MSVTABLE_COMPAT */ + + +#define ICOM_THIS(impl,iface) impl* const This=(impl*)iface +#define ICOM_CTHIS(impl,iface) const impl* const This=(const impl*)iface + +#endif + + +/***************************************************************************** + * Predeclare the interfaces + */ +DEFINE_OLEGUID(IID_IClassFactory, 0x00000001L, 0, 0); +typedef struct IClassFactory IClassFactory, *LPCLASSFACTORY; + +DEFINE_OLEGUID(IID_IMalloc, 0x00000002L, 0, 0); +typedef struct IMalloc IMalloc,*LPMALLOC; + +DEFINE_OLEGUID(IID_IUnknown, 0x00000000L, 0, 0); +typedef struct IUnknown IUnknown, *LPUNKNOWN; + + +/***************************************************************************** + * IUnknown interface + */ +#define ICOM_INTERFACE IUnknown +#define IUnknown_IMETHODS \ + ICOM_METHOD2(HRESULT,QueryInterface,REFIID,riid, LPVOID*,ppvObj) \ + ICOM_METHOD (ULONG,AddRef) \ + ICOM_METHOD (ULONG,Release) +#ifdef ICOM_CINTERFACE +typedef struct ICOM_VTABLE(IUnknown) ICOM_VTABLE(IUnknown); +struct IUnknown { + ICOM_VFIELD(IUnknown); +#if defined(ICOM_USE_COM_INTERFACE_ATTRIBUTE) +} __attribute__ ((com_interface)); +#else +}; +#endif /* ICOM_US_COM_INTERFACE_ATTRIBUTE */ + +struct ICOM_VTABLE(IUnknown) { +#ifdef ICOM_MSVTABLE_COMPAT + long dummyRTTI1; + long dummyRTTI2; +#endif /* ICOM_MSVTABLE_COMPAT */ + +#else /* ICOM_CINTERFACE */ +struct IUnknown { + +#endif /* ICOM_CINTERFACE */ + + ICOM_METHOD2(HRESULT,QueryInterface,REFIID,riid, LPVOID*,ppvObj) + ICOM_METHOD (ULONG,AddRef) + ICOM_METHOD (ULONG,Release) +#if defined(ICOM_USE_COM_INTERFACE_ATTRIBUTE) +} __attribute__ ((com_interface)); +#else +}; +#endif /* ICOM_US_COM_INTERFACE_ATTRIBUTE */ + +#undef ICOM_INTERFACE + +/*** IUnknown methods ***/ +#define IUnknown_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IUnknown_AddRef(p) ICOM_CALL (AddRef,p) +#define IUnknown_Release(p) ICOM_CALL (Release,p) + +/***************************************************************************** + * IClassFactory interface + */ +#define ICOM_INTERFACE IClassFactory +#define IClassFactory_METHODS \ + ICOM_METHOD3(HRESULT,CreateInstance, LPUNKNOWN,pUnkOuter, REFIID,riid, LPVOID*,ppvObject) \ + ICOM_METHOD1(HRESULT,LockServer, BOOL,fLock) +#define IClassFactory_IMETHODS \ + IUnknown_IMETHODS \ + IClassFactory_METHODS +ICOM_DEFINE(IClassFactory,IUnknown) +#undef ICOM_INTERFACE + +/*** IUnknown methods ***/ +#define IClassFactory_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IClassFactory_AddRef(p) ICOM_CALL (AddRef,p) +#define IClassFactory_Release(p) ICOM_CALL (Release,p) +/*** IClassFactory methods ***/ +#define IClassFactory_CreateInstance(p,a,b,c) ICOM_CALL3(CreateInstance,p,a,b,c) +#define IClassFactory_LockServer(p,a) ICOM_CALL1(LockServer,p,a) + + +/***************************************************************************** + * IMalloc interface + */ +#define ICOM_INTERFACE IMalloc +#define IMalloc_METHODS \ + ICOM_METHOD1 (LPVOID,Alloc, DWORD,cb) \ + ICOM_METHOD2 (LPVOID,Realloc, LPVOID,pv, DWORD,cb) \ + ICOM_VMETHOD1( Free, LPVOID,pv) \ + ICOM_METHOD1(DWORD, GetSize, LPVOID,pv) \ + ICOM_METHOD1(INT, DidAlloc, LPVOID,pv) \ + ICOM_METHOD (VOID, HeapMinimize) +#define IMalloc_IMETHODS \ + IUnknown_IMETHODS \ + IMalloc_METHODS +ICOM_DEFINE(IMalloc,IUnknown) +#undef ICOM_INTERFACE + +/*** IUnknown methods ***/ +#define IMalloc_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IMalloc_AddRef(p) ICOM_CALL (AddRef,p) +#define IMalloc_Release(p) ICOM_CALL (Release,p) +/*** IMalloc32 methods ***/ +#define IMalloc_Alloc(p,a) ICOM_CALL1(Alloc,p,a) +#define IMalloc_Realloc(p,a,b) ICOM_CALL2(Realloc,p,a,b) +#define IMalloc_Free(p,a) ICOM_CALL1(Free,p,a) +#define IMalloc_GetSize(p,a) ICOM_CALL1(GetSize,p,a) +#define IMalloc_DidAlloc(p,a) ICOM_CALL1(DidAlloc,p,a) +#define IMalloc_HeapMinimize(p) ICOM_CALL (HeapMinimize,p) + + +HRESULT WINAPI CoGetMalloc(DWORD dwMemContext,LPMALLOC* lpMalloc); + +LPVOID WINAPI CoTaskMemAlloc(ULONG size); + +void WINAPI CoTaskMemFree(LPVOID ptr); + +/* FIXME: unimplemented */ +LPVOID WINAPI CoTaskMemRealloc(LPVOID ptr, ULONG size); + + +/***************************************************************************** + * Additional API + */ + +HRESULT WINAPI CoCreateGuid(GUID* pguid); + +HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree); + +void WINAPI CoFreeAllLibraries(void); + +void WINAPI CoFreeLibrary(HINSTANCE hLibrary); + +void WINAPI CoFreeUnusedLibraries(void); + +HRESULT WINAPI CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv); + +HRESULT WINAPI CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext, LPVOID pvReserved, REFIID iid, LPVOID *ppv); + +HRESULT WINAPI CoInitialize(LPVOID lpReserved); +HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit); + +void WINAPI CoUninitialize(void); + +typedef enum tagCOINIT +{ + COINIT_APARTMENTTHREADED = 0x2, /* Apartment model */ + COINIT_MULTITHREADED = 0x0, /* OLE calls objects on any thread */ + COINIT_DISABLE_OLE1DDE = 0x4, /* Don't use DDE for Ole1 support */ + COINIT_SPEED_OVER_MEMORY = 0x8 /* Trade memory for speed */ +} COINIT; + + +/* FIXME: not implemented */ +BOOL WINAPI CoIsOle1Class(REFCLSID rclsid); + +HRESULT WINAPI CoLockObjectExternal(LPUNKNOWN pUnk, BOOL fLock, BOOL fLastUnlockReleases); + +/* class registration flags; passed to CoRegisterClassObject */ +typedef enum tagREGCLS +{ + REGCLS_SINGLEUSE = 0, + REGCLS_MULTIPLEUSE = 1, + REGCLS_MULTI_SEPARATE = 2, + REGCLS_SUSPENDED = 4 +} REGCLS; + +HRESULT WINAPI CoResumeClassObjects (void); +HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid,LPUNKNOWN pUnk,DWORD dwClsContext,DWORD flags,LPDWORD lpdwRegister); + +HRESULT WINAPI CoRevokeClassObject(DWORD dwRegister); + +/***************************************************************************** + * COM Server dll - exports + */ +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv); +HRESULT WINAPI DllCanUnloadNow(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __WINE_WINE_OBJ_BASE_H */ diff --git a/tags/GPGME-0-1-3/complus/wtypes.h b/tags/GPGME-0-1-3/complus/wtypes.h new file mode 100644 index 0000000..bff3f30 --- /dev/null +++ b/tags/GPGME-0-1-3/complus/wtypes.h @@ -0,0 +1,272 @@ +/* wtypes.h - Defines the basic types used by COM interfaces. + + Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS + for a complete list) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __WINE_WTYPES_H +#define __WINE_WTYPES_H + +#include "basetsd.h" +#include "guiddef.h" +/*#include "rpc.h"*/ +/*#include "rpcndr.h"*/ + +typedef WORD CLIPFORMAT, *LPCLIPFORMAT; + +/* FIXME: does not belong here */ +typedef CHAR OLECHAR16; +typedef LPSTR LPOLESTR16; +typedef LPCSTR LPCOLESTR16; +typedef OLECHAR16 *BSTR16; +typedef BSTR16 *LPBSTR16; +#define OLESTR16(x) x + +typedef WCHAR OLECHAR; +typedef LPWSTR LPOLESTR; +typedef LPCWSTR LPCOLESTR; +typedef OLECHAR *BSTR; +typedef BSTR *LPBSTR; + +/* +#ifndef _DWORDLONG_ +#define _DWORDLONG_ +typedef __uint64 DWORDLONG, *PDWORDLONG; +#endif + +#ifndef _ULONGLONG_ +#define _ULONGLONG_ +typedef __int64 LONGLONG, *PLONGLONG; +typedef __uint64 ULONGLONG, *PULONGLONG; +#endif +*/ + +#define OLESTR(x) L##x + +typedef enum tagDVASPECT +{ + DVASPECT_CONTENT = 1, + DVASPECT_THUMBNAIL = 2, + DVASPECT_ICON = 4, + DVASPECT_DOCPRINT = 8 +} DVASPECT; + +typedef enum tagSTGC +{ + STGC_DEFAULT = 0, + STGC_OVERWRITE = 1, + STGC_ONLYIFCURRENT = 2, + STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4, + STGC_CONSOLIDATE = 8 +} STGC; + +typedef enum tagSTGMOVE +{ + STGMOVE_MOVE = 0, + STGMOVE_COPY = 1, + STGMOVE_SHALLOWCOPY = 2 +} STGMOVE; + + +typedef struct _COAUTHIDENTITY +{ + USHORT* User; + ULONG UserLength; + USHORT* Domain; + ULONG DomainLength; + USHORT* Password; + ULONG PasswordLength; + ULONG Flags; +} COAUTHIDENTITY; + +typedef struct _COAUTHINFO +{ + DWORD dwAuthnSvc; + DWORD dwAuthzSvc; + LPWSTR pwszServerPrincName; + DWORD dwAuthnLevel; + DWORD dwImpersonationLevel; + COAUTHIDENTITY* pAuthIdentityData; + DWORD dwCapabilities; +} COAUTHINFO; + +typedef struct _COSERVERINFO +{ + DWORD dwReserved1; + LPWSTR pwszName; + COAUTHINFO* pAuthInfo; + DWORD dwReserved2; +} COSERVERINFO; + +typedef enum tagCLSCTX +{ + CLSCTX_INPROC_SERVER = 0x1, + CLSCTX_INPROC_HANDLER = 0x2, + CLSCTX_LOCAL_SERVER = 0x4, + CLSCTX_INPROC_SERVER16 = 0x8, + CLSCTX_REMOTE_SERVER = 0x10, + CLSCTX_INPROC_HANDLER16 = 0x20, + CLSCTX_INPROC_SERVERX86 = 0x40, + CLSCTX_INPROC_HANDLERX86 = 0x80, + CLSCTX_ESERVER_HANDLER = 0x100 +} CLSCTX; + +#define CLSCTX_INPROC (CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) +#define CLSCTX_ALL (CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER) +#define CLSCTX_SERVER (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER) + +typedef enum tagMSHLFLAGS +{ + MSHLFLAGS_NORMAL = 0, + MSHLFLAGS_TABLESTRONG = 1, + MSHLFLAGS_TABLEWEAK = 2, + MSHLFLAGS_NOPING = 4 +} MSHLFLAGS; + +typedef enum tagMSHCTX +{ + MSHCTX_LOCAL = 0, + MSHCTX_NOSHAREDMEM = 1, + MSHCTX_DIFFERENTMACHINE = 2, + MSHCTX_INPROC = 3 +} MSHCTX; + +typedef unsigned short VARTYPE; + +typedef ULONG PROPID; + +/* +#ifndef _tagBLOB_DEFINED +#define _tagBLOB_DEFINED +#define _BLOB_DEFINED +#define _LPBLOB_DEFINED +typedef struct tagBLOB +{ + ULONG cbSize; + BYTE *pBlobData; +} BLOB, *LPBLOB; +#endif +*/ + +#ifndef _tagCY_DEFINED +#define _tagCY_DEFINED + +typedef union tagCY { + struct { +#ifdef BIG_ENDIAN + LONG Hi; + LONG Lo; +#else /* defined(BIG_ENDIAN) */ + ULONG Lo; + LONG Hi; +#endif /* defined(BIG_ENDIAN) */ + } DUMMYSTRUCTNAME; + LONGLONG int64; +} CY; + +#endif /* _tagCY_DEFINED */ + +/* + * 0 == FALSE and -1 == TRUE + */ +#define VARIANT_TRUE ((VARIANT_BOOL)0xFFFF) +#define VARIANT_FALSE ((VARIANT_BOOL)0x0000) +typedef short VARIANT_BOOL,_VARIANT_BOOL; + +typedef struct tagCLIPDATA +{ + ULONG cbSize; + long ulClipFmt; + BYTE *pClipData; +} CLIPDATA; + +/* Macro to calculate the size of the above pClipData */ +#define CBPCLIPDATA(clipdata) ( (clipdata).cbSize - sizeof((clipdata).ulClipFmt) ) + +typedef LONG SCODE; + +/* +#ifndef _FILETIME_ +#define _FILETIME_ +*/ +/* 64 bit number of 100 nanoseconds intervals since January 1, 1601 */ +/* +typedef struct +{ + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME, *LPFILETIME; +#endif +*/ + +#ifndef _SECURITY_DEFINED +#define _SECURITY_DEFINED + +/* +typedef struct { + BYTE Value[6]; +} SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; + +typedef struct _SID { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[1]; +} SID,*PSID; +*/ +/* + * ACL + */ +/* +typedef struct _ACL { + BYTE AclRevision; + BYTE Sbz1; + WORD AclSize; + WORD AceCount; + WORD Sbz2; +} ACL, *PACL; + +typedef DWORD SECURITY_INFORMATION; +typedef WORD SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL; +typedef DWORD ACCESS_MASK, *PACCESS_MASK; + +typedef PVOID PGENERIC_MAPPING; +*/ +/* The security descriptor structure */ +/* +typedef struct { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; +} SECURITY_DESCRIPTOR, *PSECURITY_DESCRIPTOR; +*/ +#endif /* _SECURITY_DEFINED */ + +#ifndef _ROTFLAGS_DEFINED +#define _ROTFLAGS_DEFINED +#define ROTFLAGS_REGISTRATIONKEEPSALIVE 0x1 +#define ROTFLAGS_ALLOWANYCLIENT 0x2 +#endif /* !defined(_ROTFLAGS_DEFINED) */ + +#endif /* __WINE_WTYPES_H */ diff --git a/tags/GPGME-0-1-3/configure.in b/tags/GPGME-0-1-3/configure.in new file mode 100644 index 0000000..710b043 --- /dev/null +++ b/tags/GPGME-0-1-3/configure.in @@ -0,0 +1,170 @@ +# 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.3) +LIBGPGME_LT_CURRENT=1 +LIBGPGME_LT_AGE=1 +LIBGPGME_LT_REVISION=0 +############################################## + +AC_SUBST(LIBGPGME_LT_CURRENT) +AC_SUBST(LIBGPGME_LT_AGE) +AC_SUBST(LIBGPGME_LT_REVISION) + + +AM_MAINTAINER_MODE + +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 + +GPG= +component_system=None +case "${target}" in + *-*-mingw32* | i?86-emx-os2 | i?86-*-os2*emx | i?86-*-msdosdjgpp* ) + # special stuff for Windoze NT + # OS/2 with the EMX environment + # DOS with the DJGPP environment + AC_DEFINE(HAVE_DRIVE_LETTERS) + AC_DEFINE(HAVE_DOSISH_SYSTEM) + GPG='c:\\gnupg\\gpg.exe' + #component_system='COM+' + ;; + *) + ;; +esac + + + + +dnl +dnl Checks for libraries +dnl + +dnl +dnl Checks for header files +dnl + + + +dnl +dnl Checks for typedefs and structures +dnl +GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF) +GNUPG_CHECK_TYPEDEF(ushort, HAVE_USHORT_TYPEDEF) +GNUPG_CHECK_TYPEDEF(ulong, HAVE_ULONG_TYPEDEF) +GNUPG_CHECK_TYPEDEF(u16, HAVE_U16_TYPEDEF) +GNUPG_CHECK_TYPEDEF(u32, HAVE_U32_TYPEDEF) +# We should not use them in this software; +# However jnlib/types.h needs them - so we take the easy way. +AC_CHECK_SIZEOF(unsigned short, 2) +AC_CHECK_SIZEOF(unsigned int, 4) +AC_CHECK_SIZEOF(unsigned long, 4) +if test "$ac_cv_sizeof_unsigned_short" = "0" \ + || test "$ac_cv_sizeof_unsigned_int" = "0" \ + || test "$ac_cv_sizeof_unsigned_long" = "0"; then + AC_MSG_WARN([Hmmm, something is wrong with the sizes - using defaults]); +fi + + + +dnl +dnl Checks for compiler features +dnl + +dnl +dnl Checks for library functions +dnl +dnl These are needed by libjnlib +AC_CHECK_FUNCS(memicmp stpcpy strlwr strtoul memmove stricmp) + + +dnl +dnl Checks for system services +dnl + +if test -z "$GPG"; then + 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 +fi +AC_DEFINE_UNQUOTED(GPG_PATH, "$GPG") + + +dnl +dnl FIXME: check whether Bonobo is installed +dnl + + +dnl +dnl Create config files +dnl +dnl + +AM_CONDITIONAL(BUILD_COMPLUS, test "$component_system" = "COM+") +AM_CONDITIONAL(BUILD_BONOBO, test "$component_system" = "Bonobo") + +dnl Make the version number in gpgme/gpgme.h the same as the one here. +dnl (this is easier than to have a *.in file just for one substitution) +GNUPG_FIX_HDR_VERSION(gpgme/gpgme.h, GPGME_VERSION) + +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 +jnlib/Makefile +gpgme/Makefile +gpgme/gpgme-config +tests/Makefile +bonobo/Makefile +complus/Makefile +]) + +echo " + GPGME v${VERSION} has been configured as follows: + + GPG path: $GPG + Component: $component_system +" + + + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/ChangeLog b/tags/GPGME-0-1-3/gpgme/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/tags/GPGME-0-1-3/gpgme/Makefile.am b/tags/GPGME-0-1-3/gpgme/Makefile.am new file mode 100644 index 0000000..32b72b4 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/Makefile.am @@ -0,0 +1,45 @@ +# 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 \ + import.c \ + export.c \ + genkey.c \ + rungpg.c rungpg.h status-table.h \ + syshdr.h io.h posix-io.c w32-io.c \ + 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/GPGME-0-1-3/gpgme/context.h b/tags/GPGME-0-1-3/gpgme/context.h new file mode 100644 index 0000000..86554e0 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/context.h @@ -0,0 +1,129 @@ +/* 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; + + 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; + + GpgmePassphraseCb passphrase_cb; + void *passphrase_cb_value; + + GpgmeProgressCb progress_cb; + void *progress_cb_value; + + GpgmeData help_data_1; +}; + + +struct gpgme_data_s { + size_t len; + const char *data; + GpgmeDataType type; + GpgmeDataMode mode; + + int (*read_cb)( void *, char *, size_t, size_t *); + void *read_cb_value; + int read_cb_eof; + + size_t readpos; + size_t writepos; + size_t private_len; + 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/GPGME-0-1-3/gpgme/data.c b/tags/GPGME-0-1-3/gpgme/data.c new file mode 100644 index 0000000..e63fd52 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/data.c @@ -0,0 +1,636 @@ +/* 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 "syshdr.h" + +#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') ) + + +/** + * gpgme_data_new: + * @r_dh: returns the new data object + * + * Create a new data object without any content. + * + * Return value: An error value or 0 on success + **/ +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_with_read_cb ( GpgmeData *r_dh, + int (*read_cb)(void*,char *,size_t,size_t*), + void *read_cb_value ) +{ + GpgmeData dh; + GpgmeError err; + + if (!r_dh || !read_cb) + return mk_error (Invalid_Value); + *r_dh = NULL; + err = gpgme_data_new ( &dh ); + if (err) + return err; + dh->type = GPGME_DATA_TYPE_CB; + dh->mode = GPGME_DATA_MODE_OUT; + dh->read_cb = read_cb; + dh->read_cb_value = read_cb_value; + + *r_dh = dh; + return 0; +} + +/** + * gpgme_data_new_from_file: + * @r_dh: returns the new data object + * @fname: filename + * @copy: Flag, whether the file should be copied. + * + * Create a new data object and initialize it with the content of + * the file @file. If @copy is %True the file is immediately read in + * adn closed. @copy of %False is not yet supportted. + * + * Return value: An error code or 0 on success. If the error code is + * %GPGME_File_Error, the OS error code is held in %errno. + **/ +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; +} + +/** + * gpgme_data_release_and_get_mem: + * @dh: the data object + * @r_len: returns the length of the memory + * + * Release the data object @dh and return its content and the length of + * that content. The caller has to free this data. @dh maybe NULL in + * which case NULL is returned. I there is not enough memory for allocating + * the return value, NULL is returned and the object is released. + * + * Return value: a pointer to an allocated buffer of length @r_len. + **/ +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; +} + + +/** + * gpgme_data_get_type: + * @dh: the data object + * + * Get the type of the data object. + * Data types are prefixed with %GPGME_DATA_TYPE_ + * + * Return value: the data type + **/ +GpgmeDataType +gpgme_data_get_type ( GpgmeData dh ) +{ + if ( !dh || (!dh->data && !dh->read_cb)) + 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; +} + +/** + * gpgme_data_rewind: + * @dh: the data object + * + * Prepare the data object in a way, that a gpgme_data_read() does start + * at the beginning of the data. This has to be done for all types + * of data objects. + * + * Return value: An error code or 0 on success + **/ +GpgmeError +gpgme_data_rewind ( GpgmeData dh ) +{ + if ( !dh ) + return mk_error (Invalid_Value); + + if (dh->type == GPGME_DATA_TYPE_MEM ) { + dh->readpos = 0; + } + else if (dh->type == GPGME_DATA_TYPE_CB) { + dh->len = dh->readpos = 0; + dh->read_cb_eof = 0; + /* FIXME: do a special call to the read function to trigger a rewind + there */ + } + else + return mk_error (General_Error); + return 0; +} + +/** + * gpgme_data_read: + * @dh: the data object + * @buffer: A buffer + * @length: The length of that bufer + * @nread: Returns the number of bytes actually read. + * + * Copy data from the current read position (which may be set by + * gpgme_data_rewind()) to the supplied @buffer, max. @length bytes + * are copied and the actual number of bytes are returned in @nread. + * If there are no more bytes available %GPGME_EOF is returned and @nread + * is set to 0. + * + * Return value: An errorcode or 0 on success, EOF is indcated by the + * error code GPGME_EOF. + **/ +GpgmeError +gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread ) +{ + size_t nbytes; + + if ( !dh ) + return mk_error (Invalid_Value); + if (dh->type == GPGME_DATA_TYPE_MEM ) { + nbytes = dh->len - dh->readpos; + if ( !nbytes ) { + *nread = 0; + return mk_error(EOF); + } + if (nbytes > length) + nbytes = length; + memcpy ( buffer, dh->data + dh->readpos, nbytes ); + *nread = nbytes; + dh->readpos += nbytes; + } + else if (dh->type == GPGME_DATA_TYPE_CB) { + nbytes = dh->len - dh->readpos; + if ( nbytes ) { + /* we have unread data - return this */ + if (nbytes > length) + nbytes = length; + memcpy ( buffer, dh->data + dh->readpos, nbytes ); + *nread = nbytes; + dh->readpos += nbytes; + } + else { /* get the data from the callback */ + if (!dh->read_cb || dh->read_cb_eof) { + *nread = 0; + return mk_error (EOF); + } + if (dh->read_cb (dh->read_cb_value, buffer, length, nread )) { + *nread = 0; + dh->read_cb_eof = 1; + return mk_error (EOF); + } + } + } + else + return mk_error (General_Error); + return 0; +} + +GpgmeError +_gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length ) +{ + if ( !dh ) + return mk_error (Invalid_Value); + + if (dh->type == GPGME_DATA_TYPE_MEM ) { + /* check that we don't unread more than we have yet read */ + if ( dh->readpos < length ) + return mk_error (Invalid_Value); + /* No need to use the buffer for this data type */ + dh->readpos -= length; + } + else { + return mk_error (General_Error); + } + + return 0; +} + + +/* + * This function does make sense when we know that it contains no nil chars. + */ +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/GPGME-0-1-3/gpgme/decrypt.c b/tags/GPGME-0-1-3/gpgme/decrypt.c new file mode 100644 index 0000000..465101b --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/decrypt.c @@ -0,0 +1,246 @@ +/* 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 *last_pw_handle; +}; + + +void +_gpgme_release_decrypt_result ( DecryptResult res ) +{ + xfree (res); +} + + +static GpgmeError +create_result_struct ( GpgmeCtx ctx ) +{ + assert ( !ctx->result.decrypt ); + ctx->result.decrypt = xtrycalloc ( 1, sizeof *ctx->result.decrypt ); + if ( !ctx->result.decrypt ) { + return mk_error (Out_Of_Core); + } + ctx->result_type = RESULT_TYPE_DECRYPT; + return 0; +} + +static void +decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ + if ( ctx->out_of_core ) + return; + if ( ctx->result_type == RESULT_TYPE_NONE ) { + if ( create_result_struct ( ctx ) ) { + ctx->out_of_core = 1; + return; + } + } + assert ( ctx->result_type == RESULT_TYPE_DECRYPT ); + + switch (code) { + case STATUS_EOF: + break; + + case STATUS_NEED_PASSPHRASE: + case STATUS_NEED_PASSPHRASE_SYM: + fprintf (stderr, "need a passphrase ...\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; + } +} + +static const char * +command_handler ( void *opaque, GpgStatusCode code, const char *key ) +{ + GpgmeCtx c = opaque; + + if ( c->result_type == RESULT_TYPE_NONE ) { + if ( create_result_struct ( c ) ) { + c->out_of_core = 1; + return NULL; + } + } + + if ( !code ) { + /* We have been called for cleanup */ + if ( c->passphrase_cb ) { + /* Fixme: take the key in account */ + c->passphrase_cb (c->passphrase_cb_value, 0, + &c->result.decrypt->last_pw_handle ); + } + + return NULL; + } + + if ( !key || !c->passphrase_cb ) + return NULL; + + if ( code == STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter") ) { + return c->passphrase_cb (c->passphrase_cb_value, + "Hey, Mr. Hoover wants your passphrase!", + &c->result.decrypt->last_pw_handle ); + } + + return NULL; +} + + +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 ); + if (c->passphrase_cb) { + rc = _gpgme_gpg_set_command_handler ( c->gpg, command_handler, c ); + if (rc) + goto leave; + } + + /* 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/GPGME-0-1-3/gpgme/encrypt.c b/tags/GPGME-0-1-3/gpgme/encrypt.c new file mode 100644 index 0000000..30704d2 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/encrypt.c @@ -0,0 +1,136 @@ +/* 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 */ + _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, 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/GPGME-0-1-3/gpgme/errors.c b/tags/GPGME-0-1-3/gpgme/errors.c new file mode 100644 index 0000000..4445d17 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/errors.c @@ -0,0 +1,49 @@ +/* Generated automatically by mkerrors */ +/* Do not edit! */ + +#include +#include "gpgme.h" + +/** + * gpgme_strerror: + * @err: Error code + * + * This function returns a textual representaion of the given + * errocode. If this is an unknown value, a string with the value + * is returned (which is hold in a static buffer). + * + * Return value: String with the error description. + **/ +const char * +gpgme_strerror (GpgmeError err) +{ + const char *s; + static char buf[25]; + + switch (err) { + case GPGME_No_Error: s="No Error"; break; + case GPGME_General_Error: s="General Error"; break; + case GPGME_Out_Of_Core: s="Out Of Core"; break; + case GPGME_Invalid_Value: s="Invalid Value"; break; + case GPGME_Busy: s="Busy"; break; + case GPGME_No_Request: s="No Request"; break; + case GPGME_Exec_Error: s="Exec Error"; break; + case GPGME_Too_Many_Procs: s="Too Many Procs"; break; + case GPGME_Pipe_Error: s="Pipe Error"; break; + case GPGME_No_Recipients: s="No Recipients"; break; + case GPGME_No_Data: s="No Data"; break; + case GPGME_Conflict: s="Conflict"; break; + case GPGME_Not_Implemented: s="Not Implemented"; break; + case GPGME_Read_Error: s="Read Error"; break; + case GPGME_Write_Error: s="Write Error"; break; + case GPGME_Invalid_Type: s="Invalid Type"; break; + case GPGME_Invalid_Mode: s="Invalid Mode"; break; + case GPGME_File_Error: s="File Error"; break; + case GPGME_Decryption_Failed: s="Decryption Failed"; break; + case GPGME_No_Passphrase: s="No Passphrase"; break; + default: sprintf (buf, "ec=%d", err ); s=buf; break; +} + +return s; +} + diff --git a/tags/GPGME-0-1-3/gpgme/export.c b/tags/GPGME-0-1-3/gpgme/export.c new file mode 100644 index 0000000..0265b46 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/export.c @@ -0,0 +1,125 @@ +/* export.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 +export_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ + fprintf (stderr, "export_status: code=%d args=`%s'\n", + code, args ); + /* FIXME: Need to do more */ +} + + +GpgmeError +gpgme_op_export_start ( GpgmeCtx c, GpgmeRecipients recp, + GpgmeData keydata ) +{ + int rc = 0; + int i; + + fail_on_pending_request( c ); + c->pending = 1; + + /* create a process object */ + _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, export_status_handler, c ); + + /* build the commandline */ + _gpgme_gpg_add_arg ( c->gpg, "--export" ); + 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" ); + + if ( !keydata || gpgme_data_get_type (keydata) != GPGME_DATA_TYPE_NONE ) { + rc = mk_error (Invalid_Value); + goto leave; + } + _gpgme_data_set_mode (keydata, GPGME_DATA_MODE_IN ); + _gpgme_gpg_add_data ( c->gpg, keydata, 1 ); + _gpgme_gpg_add_arg ( c->gpg, "--" ); + + { + void *ec; + const char *s; + + rc = gpgme_recipients_enum_open ( recp, &ec ); + if ( rc ) + goto leave; + while ( (s = gpgme_recipients_enum_read ( recp, &ec )) ) + _gpgme_gpg_add_arg (c->gpg, s); + rc = gpgme_recipients_enum_close ( recp, &ec ); + if ( rc ) + goto leave; + } + + 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_export: + * @c: the context + * @recp: a list of recipients or NULL + * @keydata: Returns the keys + * + * This function can be used to extract public keys from the GnuPG key + * database either in armored (by using gpgme_set_armor()) or in plain + * binary form. The function expects a list of user IDs in @recp for + * whom the public keys are to be exportedkinit + * + * + * Return value: 0 for success or an error code + **/ +GpgmeError +gpgme_op_export ( GpgmeCtx c, GpgmeRecipients recp, GpgmeData keydata ) +{ + int rc = gpgme_op_export_start ( c, recp, keydata ); + if ( !rc ) { + gpgme_wait (c, 1); + c->pending = 0; + } + return rc; +} + + + diff --git a/tags/GPGME-0-1-3/gpgme/genkey.c b/tags/GPGME-0-1-3/gpgme/genkey.c new file mode 100644 index 0000000..b002372 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/genkey.c @@ -0,0 +1,202 @@ +/* genkey.c - key generation + * 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 +genkey_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ + if ( code == STATUS_PROGRESS && *args ) { + if (ctx->progress_cb) { + char *p; + int type=0, current=0, total=0; + + if ( (p = strchr (args, ' ')) ) { + *p++ = 0; + if (*p) { + type = *(byte*)p; + if ( (p = strchr (p+1, ' ')) ) { + *p++ = 0; + if (*p) { + current = atoi (p); + if ( (p = strchr (p+1, ' ')) ) { + *p++ = 0; + total = atoi (p); + } + } + } + } + } + if ( type != 'X' ) + ctx->progress_cb ( ctx->progress_cb_value, args, type, + current, total ); + } + return; + } + + fprintf (stderr, "genkey_status: code=%d args=`%s'\n", + code, args ); + /* FIXME: Need to do more */ +} + + + +/* + * Here is how the parms should be formatted: + +Key-Type: DSA +Key-Length: 1024 +Subkey-Type: ELG-E +Subkey-Length: 1024 +Name-Real: Joe Tester +Name-Comment: with stupid passphrase +Name-Email: joe@foo.bar +Expire-Date: 0 +Passphrase: abc + + * Strings should be given in UTF-8 encoding. The format we support for now + * "internal". The content of the container is passed + * verbatim to GnuPG. Control statements (e.g. %pubring) are not allowed. + */ + +GpgmeError +gpgme_op_genkey_start ( GpgmeCtx c, const char *parms, + GpgmeData pubkey, GpgmeData seckey ) +{ + int rc = 0; + int i; + const char *s, *s2, *sx; + + fail_on_pending_request( c ); + c->pending = 1; + + gpgme_data_release (c->help_data_1); c->help_data_1 = NULL; + + /* create a process object */ + _gpgme_gpg_release (c->gpg); c->gpg = NULL; + rc = _gpgme_gpg_new ( &c->gpg ); + if (rc) + goto leave; + + /* We need a special mechanism to get the fd of a pipe here, so + * that we can use this for the %pubring and %secring parameters. + * We don't have this yet, so we implement only the adding to the + * standard keyrings */ + if ( pubkey || seckey ) { + rc = mk_error (Not_Implemented); + goto leave; + } + + _gpgme_gpg_set_status_handler ( c->gpg, genkey_status_handler, c ); + + /* build the commandline */ + _gpgme_gpg_add_arg ( c->gpg, "--gen-key" ); + 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" ); + + if ( !pubkey && !seckey ) + ; /* okay: Add key to the keyrings */ + else if ( !pubkey + || gpgme_data_get_type (pubkey) != GPGME_DATA_TYPE_NONE ) { + rc = mk_error (Invalid_Value); + goto leave; + } + else if ( !seckey + || gpgme_data_get_type (seckey) != GPGME_DATA_TYPE_NONE ) { + rc = mk_error (Invalid_Value); + goto leave; + } + + if ( pubkey ) { + _gpgme_data_set_mode (pubkey, GPGME_DATA_MODE_IN ); + _gpgme_data_set_mode (seckey, GPGME_DATA_MODE_IN ); + /* need some more things here */ + } + + + if ( (parms = strstr (parms, "')) + && (sx = strstr (parms, "format=\"internal\"")) + && sx < s + && (s2 = strstr (s+1, "")) ) { + /* fixme: check that there are no control statements inside */ + rc = gpgme_data_new_from_mem ( &c->help_data_1, s+1, s2-s-1, 1 ); + } + else + rc = mk_error (Invalid_Value); + + if (rc ) + goto leave; + + _gpgme_data_set_mode (c->help_data_1, GPGME_DATA_MODE_OUT ); + _gpgme_gpg_add_data (c->gpg, c->help_data_1, 0); + + 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_genkey: + * @c: the context + * @parms: XML string with the key parameters + * @pubkey: Returns the public key + * @seckey: Returns the secret key + * + * Generate a new key and store the key in the default keyrings if both + * @pubkey and @seckey are NULL. If @pubkey and @seckey are given, the newly + * created key will be returned in these data objects. + * See gpgme_op_genkey_start() for a description of @parms. + * + * Return value: 0 for success or an error code + **/ +GpgmeError +gpgme_op_genkey( GpgmeCtx c, const char *parms, + GpgmeData pubkey, GpgmeData seckey ) +{ + int rc = gpgme_op_genkey_start ( c, parms, pubkey, seckey ); + if ( !rc ) { + gpgme_wait (c, 1); + c->pending = 0; + } + return rc; +} + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/gpgme-config.in b/tags/GPGME-0-1-3/gpgme/gpgme-config.in new file mode 100644 index 0000000..67bce0f --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/gpgme/gpgme-memory.h b/tags/GPGME-0-1-3/gpgme/gpgme-memory.h new file mode 100644 index 0000000..76ff388 --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/gpgme/gpgme-types.h b/tags/GPGME-0-1-3/gpgme/gpgme-types.h new file mode 100644 index 0000000..e20e758 --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/gpgme/gpgme.c b/tags/GPGME-0-1-3/gpgme/gpgme.c new file mode 100644 index 0000000..97c8250 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/gpgme.c @@ -0,0 +1,210 @@ +/* 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 + +#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 ) +{ + if (!c) + return; + _gpgme_gpg_release ( c->gpg ); + _gpgme_release_result ( c ); + _gpgme_key_release ( c->tmp_key ); + gpgme_data_release ( c->help_data_1 ); + 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; +} + + +/** + * gpgme_get_notation: + * @c: the context + * + * If there is notation data available from the last signature check, this + * function may be used to return this notation data as a string. The string + * is an XML represantaton of that data embedded in a % container. + * + * Return value: An XML string or NULL if no notation data is available. + **/ +char * +gpgme_get_notation ( GpgmeCtx c ) +{ + if ( !c->notation ) + return NULL; + return _gpgme_data_get_as_string ( c->notation ); +} + + +/** + * gpgme_set_armor: + * @c: the contect + * @yes: boolean value to set or clear that flag + * + * Enable or disable the use of an ascii armor for all output. + **/ +void +gpgme_set_armor ( GpgmeCtx c, int yes ) +{ + if ( !c ) + return; /* oops */ + c->use_armor = yes; +} + +/** + * gpgme_set_textmode: + * @c: the context + * @yes: boolean flag whether textmode should be enabled + * + * Enable or disable the use of the special textmode. Textmode is for example + * used for MIME (RFC2015) signatures + **/ +void +gpgme_set_textmode ( GpgmeCtx c, int yes ) +{ + if ( !c ) + return; /* oops */ + c->use_textmode = yes; +} + +/** + * gpgme_set_passphrase_cb: + * @c: the context + * @cb: A callback function + * @cb_value: The value passed to the callback function + * + * This function sets a callback function to be used to pass a passphrase + * to gpg. The preferred way to handle this is by using the gpg-agent, but + * because that beast is not ready for real use, you can use this passphrase + * thing. + * + * The callback function is defined as: + * + * typedef const char *(*GpgmePassphraseCb)(void*cb_value, + * const char *desc, + * void *r_hd); + * + * and called whenever gpgme needs a passphrase. DESC will have a nice + * text, to be used to prompt for the passphrase and R_HD is just a parameter + * to be used by the callback it self. Becuase the callback returns a const + * string, the callback might want to know when it can releae resources + * assocated with that returned string; gpgme helps here by calling this + * passphrase callback with an DESC of %NULL as soon as it does not need + * the returned string anymore. The callback function might then choose + * to release resources depending on R_HD. + * + **/ +void +gpgme_set_passphrase_cb ( GpgmeCtx c, GpgmePassphraseCb cb, void *cb_value ) +{ + c->passphrase_cb = cb; + c->passphrase_cb_value = cb_value; +} + +/** + * gpgme_set_pprogress_cb: + * @c: the context + * @cb: A callback function + * @cb_value: The value passed to the callback function + * + * This function sets a callback function to be used as a progress indicator. + * + * The callback function is defined as: + * + * typedef void (*GpgmeProgressCb) (void*cb_value, + * const char *what, int type, + * int curretn, int total); + * + * For details on the progress events, see the entry for the PROGRESS + * status in the file doc/DETAILS of the GnuPG distribution. + **/ +void +gpgme_set_progress_cb ( GpgmeCtx c, GpgmeProgressCb cb, void *cb_value ) +{ + c->progress_cb = cb; + c->progress_cb_value = cb_value; +} + + diff --git a/tags/GPGME-0-1-3/gpgme/gpgme.h b/tags/GPGME-0-1-3/gpgme/gpgme.h new file mode 100644 index 0000000..7c0e4c4 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/gpgme.h @@ -0,0 +1,215 @@ +/* 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.3" + + + +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, + GPGME_DATA_TYPE_CB = 4 +} 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 enum { + GPGME_SIG_MODE_NORMAL = 0, + GPGME_SIG_MODE_DETACH = 1, + GPGME_SIG_MODE_CLEAR = 2 +} GpgmeSigMode; + + +typedef const char *(*GpgmePassphraseCb)(void*, + const char *desc, void *r_hd); +typedef void (*GpgmeProgressCb)(void *opaque, + const char *what, + int type, int current, int total ); + + +/* 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 cb, void *cb_value); +void gpgme_set_progress_cb (GpgmeCtx c, GpgmeProgressCb cb, void *cb_value); + + + +/* 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 ); +GpgmeError gpgme_recipients_enum_open (const GpgmeRecipients rset,void **ctx); +const char *gpgme_recipients_enum_read (const GpgmeRecipients rset,void **ctx); +GpgmeError gpgme_recipients_enum_close (const GpgmeRecipients rset,void **ctx); + + +/* 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_with_read_cb ( GpgmeData *r_dh, + int (*read_cb)(void*,char *,size_t,size_t*), + void *read_cb_value ); + +GpgmeError gpgme_data_new_from_file ( GpgmeData *r_dh, + const char *fname, + int copy ); +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, + GpgmeSigMode mode ); +GpgmeError gpgme_op_verify_start ( GpgmeCtx c, + GpgmeData sig, GpgmeData text ); +GpgmeError gpgme_op_import_start ( GpgmeCtx c, GpgmeData keydata ); +GpgmeError gpgme_op_export_start ( GpgmeCtx c, GpgmeRecipients recp, + GpgmeData keydata ); +GpgmeError gpgme_op_genkey_start ( GpgmeCtx c, const char *parms, + GpgmeData pubkey, GpgmeData seckey ); + + + + +/* 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, + GpgmeSigMode mode); +GpgmeError gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text, + GpgmeSigStat *r_status ); +GpgmeError gpgme_op_import ( GpgmeCtx c, GpgmeData keydata ); +GpgmeError gpgme_op_export ( GpgmeCtx c, GpgmeRecipients recp, + GpgmeData keydata ); +GpgmeError gpgme_op_genkey ( GpgmeCtx c, const char *parms, + GpgmeData pubkey, GpgmeData seckey ); + + +/* miscellaneous functions */ +const char *gpgme_check_version ( const char *req_version ); +const char *gpgme_strerror (GpgmeError err); +const char *gpgme_get_prompt ( GpgmeCtx c, int which ); + + +#ifdef __cplusplus +} +#endif +#endif /* GPGME_H */ + + + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/gpgme.m4 b/tags/GPGME-0-1-3/gpgme/gpgme.m4 new file mode 100644 index 0000000..c00071a --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/gpgme/import.c b/tags/GPGME-0-1-3/gpgme/import.c new file mode 100644 index 0000000..368063a --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/import.c @@ -0,0 +1,98 @@ +/* impoirt.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 +import_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ + fprintf (stderr, "import_status: code=%d args=`%s'\n", + code, args ); + /* FIXME: We have to check here whether the import actually worked + * and maybe it is a good idea to save some statistics and provide + * a progress callback */ +} + + + +GpgmeError +gpgme_op_import_start ( GpgmeCtx c, GpgmeData keydata ) +{ + int rc = 0; + int i; + + fail_on_pending_request( c ); + c->pending = 1; + + /* create a process object */ + _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, import_status_handler, c ); + + /* build the commandline */ + _gpgme_gpg_add_arg ( c->gpg, "--import" ); + for ( i=0; i < c->verbosity; i++ ) + _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); + + /* Check the supplied data */ + if ( gpgme_data_get_type (keydata) == GPGME_DATA_TYPE_NONE ) { + rc = mk_error (No_Data); + goto leave; + } + _gpgme_data_set_mode (keydata, GPGME_DATA_MODE_OUT ); + + _gpgme_gpg_add_data ( c->gpg, keydata, 0 ); + + 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_import ( GpgmeCtx c, GpgmeData keydata ) +{ + int rc = gpgme_op_import_start ( c, keydata ); + if ( !rc ) { + gpgme_wait (c, 1); + c->pending = 0; + } + return rc; +} + + + + diff --git a/tags/GPGME-0-1-3/gpgme/io.h b/tags/GPGME-0-1-3/gpgme/io.h new file mode 100644 index 0000000..14c0947 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/io.h @@ -0,0 +1,67 @@ +/* io.h - I/O 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 IO_H +#define IO_H + +#include "types.h" + +struct spawn_fd_item_s { + int fd; + int dup_to; +}; + + +struct io_select_fd_s { + int fd; + int is_closed; + int for_read; + int for_write; + int signaled; + int frozen; + void *opaque; +}; + + +/* These function are either defined in posix-io.c or w32-io.c */ + +int _gpgme_io_read ( int fd, void *buffer, size_t count ); +int _gpgme_io_write ( int fd, const void *buffer, size_t count ); +int _gpgme_io_pipe ( int filedes[2], int inherit_idx ); +int _gpgme_io_close ( int fd ); +int _gpgme_io_set_nonblocking ( int fd ); +int _gpgme_io_spawn ( const char *path, char **argv, + struct spawn_fd_item_s *fd_child_list, + struct spawn_fd_item_s *fd_parent_list ); +int _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal ); +int _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds); + + + + + + + +#endif /* IO_H */ + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/key.c b/tags/GPGME-0-1-3/gpgme/key.c new file mode 100644 index 0000000..909b5cf --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/key.c @@ -0,0 +1,325 @@ +/* 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; +} + + +struct subkey_s * +_gpgme_key_add_subkey (GpgmeKey key) +{ + struct subkey_s *k, *kk; + + k = xtrycalloc (1, sizeof *k); + if (!k) + return NULL; + + if( !(kk=key->keys.next) ) + key->keys.next = k; + else { + while ( kk->next ) + kk = kk->next; + kk->next = k; + } + return k; +} + + +void +_gpgme_key_release ( GpgmeKey key ) +{ + struct user_id_s *u, *u2; + struct subkey_s *k, *k2; + + if (!key) + return; + + xfree (key->keys.fingerprint); + for (k = key->keys.next; k; k = k2 ) { + k2 = k->next; + xfree (k->fingerprint); + xfree (k); + } + 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; + struct subkey_s *k; + + 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->keys.keyid ); + if (key->keys.fingerprint) + add_tag_and_string (d, "fpr", key->keys.fingerprint ); + add_tag_and_uint (d, "algo", key->keys.key_algo ); + add_tag_and_uint (d, "len", key->keys.key_len ); + add_tag_and_time (d, "created", key->keys.timestamp ); + /*add_tag_and_time (d, "expires", key->expires );*/ + _gpgme_data_append_string (d, " \n"); + + /* Now 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"); + } + + for (k=key->keys.next; k; k = k->next ) { + _gpgme_data_append_string (d, " \n"); + add_tag_and_string (d, "keyid", k->keyid ); + if (k->fingerprint) + add_tag_and_string (d, "fpr", k->fingerprint ); + add_tag_and_uint (d, "algo", k->key_algo ); + add_tag_and_uint (d, "len", k->key_len ); + add_tag_and_time (d, "created", k->timestamp ); + _gpgme_data_append_string (d, " \n"); + } + _gpgme_data_append_string ( d, "\n" ); + + return _gpgme_data_release_and_return_string (d); +} + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/key.h b/tags/GPGME-0-1-3/gpgme/key.h new file mode 100644 index 0000000..8c68779 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/key.h @@ -0,0 +1,62 @@ +/* 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 subkey_s { + struct subkey_s *next; + 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 gpgme_key_s { + struct { + unsigned int revoked:1 ; + unsigned int expired:1 ; + unsigned int disabled:1 ; + } gloflags; + struct subkey_s keys; + struct user_id_s *uids; +}; + +struct subkey_s *_gpgme_key_add_subkey (GpgmeKey key); +GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s ); + + + +#endif /* KEY_H */ + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/keylist.c b/tags/GPGME-0-1-3/gpgme/keylist.c new file mode 100644 index 0000000..5cb124e --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/keylist.c @@ -0,0 +1,426 @@ +/* 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_mainkey_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->keys.flags.expired = 1; break; + case 'r': key->keys.flags.revoked = 1; break; + case 'd': key->keys.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; + } + } +} + +static void +set_subkey_trust_info ( struct subkey_s *k, const char *s ) +{ + /* look at letters and stop at the first digit */ + for (; *s && !my_isdigit (*s); s++ ) { + switch (*s) { + case 'e': k->flags.expired = 1; break; + case 'r': k->flags.revoked = 1; break; + case 'd': k->flags.disabled = 1; 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; + struct subkey_s *sk = NULL; + + if ( ctx->out_of_core ) + return; + if (!line) + return; /* EOF */ + + 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" ) && key ) { + /* start a new subkey */ + rectype = RT_SUB; + if ( !(sk = _gpgme_key_add_subkey (key)) ) { + ctx->out_of_core=1; + return; + } + } + 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 ) { + switch (field) { + case 2: /* trust info */ + trust_info = p; /*save for later */ + break; + case 3: /* key length */ + i = atoi (p); + if ( i > 1 ) /* ignore invalid values */ + key->keys.key_len = i; + break; + case 4: /* pubkey algo */ + i = atoi (p); + if ( i > 1 && i < 128 ) + key->keys.key_algo = i; + break; + case 5: /* long keyid */ + if ( strlen (p) == DIM(key->keys.keyid)-1 ) + strcpy (key->keys.keyid, p); + break; + case 6: /* timestamp (1998-02-28) */ + key->keys.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 ( _gpgme_key_append_name ( key, p) ) + ctx->out_of_core = 1; + else { + if (trust_info) + set_mainkey_trust_info (key, trust_info); + } + break; + case 11: /* signature class */ + break; + case 12: + pend = NULL; /* we can stop here */ + break; + } + } + else if ( rectype == RT_SUB && sk ) { + switch (field) { + case 2: /* trust info */ + set_subkey_trust_info ( sk, p); + break; + case 3: /* key length */ + i = atoi (p); + if ( i > 1 ) /* ignore invalid values */ + sk->key_len = i; + break; + case 4: /* pubkey algo */ + i = atoi (p); + if ( i > 1 && i < 128 ) + sk->key_algo = i; + break; + case 5: /* long keyid */ + if ( strlen (p) == DIM(sk->keyid)-1 ) + strcpy (sk->keyid, p); + break; + case 6: /* timestamp (1998-02-28) */ + sk->timestamp = parse_timestamp (p); + break; + case 7: /* valid for n days */ + break; + case 8: /* reserved (LID) */ + break; + case 9: /* ownertrust */ + break; + case 10:/* user ID n/a for a subkey */ + 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_mainkey_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->keys.fingerprint && *p ) { + key->keys.fingerprint = xtrystrdup (p); + if ( !key->keys.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. Use a tail pointer? */ + 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/GPGME-0-1-3/gpgme/mkerrors b/tags/GPGME-0-1-3/gpgme/mkerrors new file mode 100755 index 0000000..4ad5812 --- /dev/null +++ b/tags/GPGME-0-1-3/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 < +#ifndef HAVE_DOSISH_SYSTEM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "syshdr.h" + +#include "io.h" + +#define DEBUG_SELECT_ENABLED 0 + +#if DEBUG_SELECT_ENABLED +# define DEBUG_SELECT(a) fprintf a +#else +# define DEBUG_SELECT(a) do { } while(0) +#endif + + +int +_gpgme_io_read ( int fd, void *buffer, size_t count ) +{ + int nread; + + do { + nread = read (fd, buffer, count); + } while (nread == -1 && errno == EINTR ); + return nread; +} + + +int +_gpgme_io_write ( int fd, const void *buffer, size_t count ) +{ + int nwritten; + + do { + nwritten = write (fd, buffer, count); + } while (nwritten == -1 && errno == EINTR ); + return nwritten; +} + +int +_gpgme_io_pipe ( int filedes[2], int inherit_idx ) +{ + /* we don't need inherit_idx in this implementation */ + return pipe ( filedes ); +} + +int +_gpgme_io_close ( int fd ) +{ + if ( fd == -1 ) + return -1; + return close (fd); +} + +int +_gpgme_io_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); +} + + +int +_gpgme_io_spawn ( const char *path, char **argv, + struct spawn_fd_item_s *fd_child_list, + struct spawn_fd_item_s *fd_parent_list ) +{ + static volatile int fixed_signals; + pid_t pid; + int i; + + if ( !fixed_signals ) { + struct sigaction act; + + sigaction( SIGPIPE, NULL, &act ); + if( act.sa_handler == SIG_DFL ) { + act.sa_handler = SIG_IGN; + sigemptyset( &act.sa_mask ); + act.sa_flags = 0; + sigaction( SIGPIPE, &act, NULL); + } + fixed_signals = 1; + /* fixme: This is not really MT safe */ + } + + + pid = fork (); + if (pid == -1) + return -1; + + if ( !pid ) { /* child */ + int duped_stdin = 0; + int duped_stderr = 0; + + /* first close all fds which will not be duped */ + for (i=0; fd_child_list[i].fd != -1; i++ ) { + if (fd_child_list[i].dup_to == -1 ) + close (fd_child_list[i].fd); + } + /* and now dup and close the rest */ + for (i=0; fd_child_list[i].fd != -1; i++ ) { + if (fd_child_list[i].dup_to != -1 ) { + if ( dup2 (fd_child_list[i].fd, + fd_child_list[i].dup_to ) == -1 ) { + fprintf (stderr, "dup2 failed in child: %s\n", + strerror (errno)); + _exit (8); + } + if ( fd_child_list[i].dup_to == 0 ) + duped_stdin=1; + if ( fd_child_list[i].dup_to == 2 ) + duped_stderr=1; + close (fd_child_list[i].fd); + } + } + + if( !duped_stdin || !duped_stderr ) { + int fd = open ( "/dev/null", O_RDWR ); + if ( fd == -1 ) { + fprintf (stderr,"can't open `/dev/null': %s\n", + strerror (errno) ); + _exit (8); + } + /* Make sure that the process 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 ( path, argv ); + /* Hmm: in that case we could write a special status code to the + * status-pipe */ + fprintf (stderr,"exec of `%s' failed\n", path ); + _exit (8); + } /* end child */ + + /* .dup_to is not used in the parent list */ + for (i=0; fd_parent_list[i].fd != -1; i++ ) { + close (fd_parent_list[i].fd); + } + + return (int)pid; +} + + +int +_gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal ) +{ + int status; + + *r_status = 0; + *r_signal = 0; + if ( waitpid ( pid, &status, hang? 0 : WNOHANG ) == pid ) { + if ( WIFSIGNALED (status) ) { + *r_status = 4; /* Need some value here */ + *r_signal = WTERMSIG (status); + } + else if ( WIFEXITED (status) ) { + *r_status = WEXITSTATUS (status); + } + else { + *r_status = 4; /* oops */ + } + return 1; + } + return 0; +} + + +/* + * Select on the list of fds. + * Returns: -1 = error + * 0 = timeout or nothing to select + * >0 = number of signaled fds + */ +int +_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) +{ + static fd_set readfds; + static fd_set writefds; + int any, i, max_fd, n, count; + 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 [ ")); + any = 0; + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( fds[i].for_read ) { + assert ( !FD_ISSET ( fds[i].fd, &readfds ) ); + FD_SET ( fds[i].fd, &readfds ); + if ( fds[i].fd > max_fd ) + max_fd = fds[i].fd; + DEBUG_SELECT ((stderr, "r%d ", fds[i].fd )); + any = 1; + } + else if ( fds[i].for_write ) { + assert ( !FD_ISSET ( fds[i].fd, &writefds ) ); + FD_SET ( fds[i].fd, &writefds ); + if ( fds[i].fd > max_fd ) + max_fd = fds[i].fd; + DEBUG_SELECT ((stderr, "w%d ", fds[i].fd )); + any = 1; + } + fds[i].signaled = 0; + } + DEBUG_SELECT ((stderr, "]\n" )); + if ( !any ) + return 0; + + do { + count = select ( max_fd+1, &readfds, &writefds, NULL, &timeout ); + } while ( count < 0 && errno == EINTR); + if ( count < 0 ) { + fprintf (stderr, "_gpgme_io_select failed: %s\n", strerror (errno) ); + return -1; /* error */ + } + +#if DEBUG_SELECT_ENABLED + 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 + + /* n is used to optimize it a little bit */ + for ( n=count, i=0; i < nfds && n ; i++ ) { + if ( fds[i].fd == -1 ) + ; + else if ( fds[i].for_read ) { + if ( FD_ISSET ( fds[i].fd, &readfds ) ) { + fds[i].signaled = 1; + n--; + } + } + else if ( fds[i].for_write ) { + if ( FD_ISSET ( fds[i].fd, &writefds ) ) { + fds[i].signaled = 1; + n--; + } + } + } + return count; +} + + +#endif /*!HAVE_DOSISH_SYSTEM*/ + + + diff --git a/tags/GPGME-0-1-3/gpgme/recipient.c b/tags/GPGME-0-1-3/gpgme/recipient.c new file mode 100644 index 0000000..43d3698 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/recipient.c @@ -0,0 +1,137 @@ +/* recipient.c - mainatin recipient sets + * 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 "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; +} + + + +GpgmeError +gpgme_recipients_enum_open ( const GpgmeRecipients rset, void **ctx ) +{ + if (!rset || !ctx) + return mk_error (Invalid_Value); + + *ctx = rset->list; + return 0; +} + +const char * +gpgme_recipients_enum_read ( const GpgmeRecipients rset, void **ctx ) +{ + struct user_id_s *r; + + if (!rset || !ctx) + return NULL; /* oops */ + + r = *ctx; + if ( r ) { + const char *s = r->name; + r = r->next; + *ctx = r; + return s; + } + + return NULL; +} + +GpgmeError +gpgme_recipients_enum_close ( const GpgmeRecipients rset, void **ctx ) +{ + if (!rset || !ctx) + return mk_error (Invalid_Value); + *ctx = NULL; + return 0; +} + + +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/GPGME-0-1-3/gpgme/rungpg.c b/tags/GPGME-0-1-3/gpgme/rungpg.c new file mode 100644 index 0000000..0723171 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/rungpg.c @@ -0,0 +1,1262 @@ +/* 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 "unistd.h" + +#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 "io.h" + +#include "status-table.h" + + +/* This type is used to build a list of gpg arguments and + * data sources/sinks */ +struct arg_and_data_s { + struct arg_and_data_s *next; + GpgmeData data; /* If this is not NULL .. */ + int dup_to; + int print_fd; /* print the fd number and not the special form of it */ + char arg[1]; /* .. this is used */ +}; + +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; + + int pid; /* we can't use pid_t because we don't use it in Windoze */ + + int running; + int exit_status; + int exit_signal; + + /* stuff needed for pipemode */ + struct { + int used; + int active; + GpgmeData sig; + GpgmeData text; + int stream_started; + } pm; + + /* stuff needed for interactive (command) mode */ + struct { + int used; + int fd; + GpgmeData cb_data; /* hack to get init the above fd later */ + GpgStatusCode code; /* last code */ + char *keyword; /* what has been requested (malloced) */ + GpgCommandHandler fnc; + void *fnc_value; + } cmd; +}; + +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, int pid, int fd ); +static int gpg_outbound_handler ( void *opaque, int pid, int fd ); + +static int gpg_status_handler ( void *opaque, int pid, int fd ); +static GpgmeError read_status ( GpgObject gpg ); + +static int gpg_colon_line_handler ( void *opaque, int pid, int fd ); +static GpgmeError read_colon_line ( GpgObject gpg ); + +static int pipemode_cb ( void *opaque, + char *buffer, size_t length, size_t *nread ); +static int command_cb ( void *opaque, + char *buffer, size_t length, size_t *nread ); + + + +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; + gpg->cmd.fd = -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 (_gpgme_io_pipe (gpg->status.fd, 1) == -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, "--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); + xfree (gpg->cmd.keyword); + + #if 0 + /* fixme: We need a way to communicate back closed fds, so that we + * don't do it a second time. One way to do it is by using a global + * table of open fds associated with gpg objects - but this requires + * additional locking. */ + if (gpg->status.fd[0] != -1 ) + _gpgme_io_close (gpg->status.fd[0]); + if (gpg->status.fd[1] != -1 ) + _gpgme_io_close (gpg->status.fd[1]); + if (gpg->colon.fd[0] != -1 ) + _gpgme_io_close (gpg->colon.fd[0]); + if (gpg->colon.fd[1] != -1 ) + _gpgme_io_close (gpg->colon.fd[1]); + #endif + free_fd_data_map (gpg->fd_data_map); + kill_gpg (gpg); /* fixme: should be done asyncronously */ + xfree (gpg); +} + +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 +} + +void +_gpgme_gpg_enable_pipemode ( GpgObject gpg ) +{ + gpg->pm.used = 1; + assert ( !gpg->pm.sig ); + assert ( !gpg->pm.text ); +} + +GpgmeError +_gpgme_gpg_add_arg ( GpgObject gpg, const char *arg ) +{ + struct arg_and_data_s *a; + + assert (gpg); + assert (arg); + + if (gpg->pm.active) + return 0; + + 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); + if (gpg->pm.active) + return 0; + + a = xtrymalloc ( sizeof *a - 1 ); + if ( !a ) { + gpg->arg_error = 1; + return mk_error(Out_Of_Core); + } + a->next = NULL; + a->data = data; + if ( dup_to == -2 ) { + a->print_fd = 1; + a->dup_to = -1; + } + else { + a->print_fd = 0; + a->dup_to = dup_to; + } + *gpg->argtail = a; + gpg->argtail = &a->next; + return 0; +} + +GpgmeError +_gpgme_gpg_add_pm_data ( GpgObject gpg, GpgmeData data, int what ) +{ + GpgmeError rc=0; + + assert ( gpg->pm.used ); + + if ( !what ) { + /* the signature */ + assert ( !gpg->pm.sig ); + gpg->pm.sig = data; + } + else if (what == 1) { + /* the signed data */ + assert ( !gpg->pm.text ); + gpg->pm.text = data; + } + else { + assert (0); + } + + if ( gpg->pm.sig && gpg->pm.text ) { + if ( !gpg->pm.active ) { + /* create the callback handler and connect it to stdin */ + GpgmeData tmp; + + rc = gpgme_data_new_with_read_cb ( &tmp, pipemode_cb, gpg ); + if (!rc ) + rc = _gpgme_gpg_add_data (gpg, tmp, 0); + } + if ( !rc ) { + /* here we can reset the handler stuff */ + gpg->pm.stream_started = 0; + } + } + + return rc; +} + +/* + * 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); + if (gpg->pm.active) + return; + + 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); + if (gpg->pm.active) + return 0; + + 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 (_gpgme_io_pipe (gpg->colon.fd, 1) == -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; +} + + +/* + * The Fnc will be called to get a value for one of the commands with + * a key KEY. If the Code pssed to FNC is 0, the function may release + * resources associated with the returned value from another call. To + * match such a second call to a first call, the returned value from + * the first call is passed as keyword. + */ + +GpgmeError +_gpgme_gpg_set_command_handler ( GpgObject gpg, + GpgCommandHandler fnc, void *fnc_value ) +{ + GpgmeData tmp; + GpgmeError err; + + assert (gpg); + if (gpg->pm.active) + return 0; + + err = gpgme_data_new_with_read_cb ( &tmp, command_cb, gpg ); + if (err) + return err; + + _gpgme_gpg_add_arg ( gpg, "--command-fd" ); + _gpgme_gpg_add_data (gpg, tmp, -2); + gpg->cmd.cb_data = tmp; + gpg->cmd.fnc = fnc; + gpg->cmd.fnc_value = fnc_value; + gpg->cmd.used = 1; + 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; + + if ( !fd_data_map ) + return; + + for (i=0; fd_data_map[i].data; i++ ) { +#if 0 /* fixme -> see gpg_release */ + if ( fd_data_map[i].fd != -1 ) + _gpgme_io_close (fd_data_map[i].fd); + if ( fd_data_map[i].peer_fd != -1 ) + _gpgme_io_close (fd_data_map[i].peer_fd); +#endif + /* don't release 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 && !a->print_fd ) + need_special = 1; + } + else { + /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ + } + } + if ( need_special ) + argc++; + if (use_agent) + argc++; + if (!gpg->cmd.used) + 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++; + } + if ( !gpg->cmd.used ) { + argv[argc] = xtrystrdup ( "--batch" ); + 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: + case GPGME_DATA_TYPE_CB: + 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 (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 ) + == -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]; + } + } + + /* Hack to get hands on the fd later */ + if ( gpg->cmd.used && gpg->cmd.cb_data == a->data ) { + assert (gpg->cmd.fd == -1); + gpg->cmd.fd = fd_data_map[datac].fd; + } + + 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], + a->print_fd? "%d" : "-&%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, n; + int pid; + struct spawn_fd_item_s *fd_child_list, *fd_parent_list; + + 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); + + if (gpg->pm.active) + return 0; + + rc = build_argv ( gpg ); + if ( rc ) + return rc; + + n = 4; /* status fd, 2*colon_fd and end of list */ + for (i=0; gpg->fd_data_map[i].data; i++ ) + n += 2; + fd_child_list = xtrycalloc ( n+n, sizeof *fd_child_list ); + if (!fd_child_list) + return mk_error (Out_Of_Core); + fd_parent_list = fd_child_list + n; + + /* build the fd list for the child */ + n=0; + fd_child_list[n].fd = gpg->status.fd[0]; + fd_child_list[n].dup_to = -1; + n++; + if ( gpg->colon.fnc ) { + fd_child_list[n].fd = gpg->colon.fd[0]; + fd_child_list[n].dup_to = -1; + n++; + fd_child_list[n].fd = gpg->colon.fd[1]; + fd_child_list[n].dup_to = 1; /* dup to stdout */ + n++; + } + for (i=0; gpg->fd_data_map[i].data; i++ ) { + fd_child_list[n].fd = gpg->fd_data_map[i].fd; + fd_child_list[n].dup_to = -1; + n++; + if (gpg->fd_data_map[i].dup_to != -1) { + fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd; + fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to; + n++; + } + } + fd_child_list[n].fd = -1; + fd_child_list[n].dup_to = -1; + + /* build the fd list for the parent */ + n=0; + if ( gpg->status.fd[1] != -1 ) { + fd_parent_list[n].fd = gpg->status.fd[1]; + fd_parent_list[n].dup_to = -1; + n++; + gpg->status.fd[1] = -1; + } + if ( gpg->colon.fd[1] != -1 ) { + fd_parent_list[n].fd = gpg->colon.fd[1]; + fd_parent_list[n].dup_to = -1; + n++; + gpg->colon.fd[1] = -1; + } + for (i=0; gpg->fd_data_map[i].data; i++ ) { + fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd; + fd_parent_list[n].dup_to = -1; + n++; + gpg->fd_data_map[i].peer_fd = -1; + } + fd_parent_list[n].fd = -1; + fd_parent_list[n].dup_to = -1; + + + pid = _gpgme_io_spawn (GPG_PATH, gpg->argv, fd_child_list, fd_parent_list); + xfree (fd_child_list); + if (pid == -1) { + return mk_error (Exec_Error); + } + + gpg->pid = pid; + if (gpg->pm.used) + gpg->pm.active = 1; + + /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ + + 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.fnc ) { + 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++ ) { + /* Due to problems with select and write we set outbound pipes + * to non-blocking */ + if (!gpg->fd_data_map[i].inbound) { + _gpgme_io_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); + } + } + + if ( gpg->cmd.used ) + _gpgme_freeze_fd ( gpg->cmd.fd ); + + /* fixme: check what data we can release here */ + + gpg->running = 1; + return 0; +} + + +static int +gpg_inbound_handler ( void *opaque, int pid, int fd ) +{ + GpgmeData dh = opaque; + GpgmeError err; + int nread; + char buf[200]; + + assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN ); + + nread = _gpgme_io_read (fd, buf, 200 ); + 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 ) { + _gpgme_io_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. + */ + + nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes ); + 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) ); + _gpgme_io_close (fd); + return 1; + } + + dh->readpos += nwritten; + return 0; +} + +static int +write_cb_data ( GpgmeData dh, int fd ) +{ + size_t nbytes; + int err, nwritten; + char buffer[512]; + + err = gpgme_data_read ( dh, buffer, DIM(buffer), &nbytes ); + if (err == GPGME_EOF) { + _gpgme_io_close (fd); + return 1; + } + + nwritten = _gpgme_io_write ( fd, buffer, nbytes ); + if (nwritten == -1 && errno == EAGAIN ) + return 0; + if ( nwritten < 1 ) { + fprintf (stderr, "write_cb_data(%d): write failed (n=%d): %s\n", + fd, nwritten, strerror (errno) ); + _gpgme_io_close (fd); + return 1; + } + + if ( nwritten < nbytes ) { + /* ugly, ugly: It does currently only for for MEM type data */ + if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) ) + fprintf (stderr, "wite_cb_data: unread of %d bytes failed\n", + nbytes - nwritten ); + _gpgme_io_close (fd); + return 1; + } + + return 0; +} + + +static int +gpg_outbound_handler ( void *opaque, int pid, int fd ) +{ + 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; + case GPGME_DATA_TYPE_CB: + if (write_cb_data (dh, fd)) + return 1; /* ready */ + break; + default: + assert (0); + } + + return 0; +} + + + +static int +gpg_status_handler ( void *opaque, int 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); + } + + + nread = _gpgme_io_read ( gpg->status.fd[0], + buffer+readpos, bufsize-readpos ); + 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' ) { + 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 ) { + if ( gpg->cmd.used + && ( r->code == STATUS_GET_BOOL + || r->code == STATUS_GET_LINE + || r->code == STATUS_GET_HIDDEN )) { + gpg->cmd.code = r->code; + xfree (gpg->cmd.keyword); + gpg->cmd.keyword = xtrystrdup (rest); + if ( !gpg->cmd.keyword ) + return mk_error (Out_Of_Core); + /* this should be the last thing we have received + * and the next thing will be that the command + * handler does it action */ + if ( nread > 1 ) + fprintf (stderr, "** ERROR, unxpected data in" + " read_status\n" ); + _gpgme_thaw_fd (gpg->cmd.fd); + } + else if ( gpg->status.fnc ) { + gpg->status.fnc ( gpg->status.fnc_value, + r->code, rest); + } + } + if ( r->code == STATUS_END_STREAM ) { + /* _gpgme_freeze_fd ( ? );*/ + } + } + /* 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, int 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); + } + + + nread = _gpgme_io_read ( gpg->colon.fd[0], + buffer+readpos, bufsize-readpos ); + 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; +} + +static GpgmeError +pipemode_copy (char *buffer, size_t length, size_t *nread, GpgmeData data ) +{ + GpgmeError err; + int nbytes; + char tmp[1000], *s, *d; + + /* we can optimize this whole thing but for now we just + * return after each escape character */ + if (length > 990) + length = 990; + + err = gpgme_data_read ( data, tmp, length, &nbytes ); + if (err) + return err; + for (s=tmp, d=buffer; nbytes; s++, nbytes--) { + *d++ = *s; + if (*s == '@' ) { + *d++ = '@'; + break; + } + } + *nread = d - buffer; + return 0; +} + + +static int +pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) +{ + GpgObject gpg = opaque; + GpgmeError err; + + if ( !buffer || !length || !nread ) + return 0; /* those values are reserved for extensions */ + *nread =0; + if ( !gpg->pm.stream_started ) { + assert (length > 4 ); + strcpy (buffer, "@<@B" ); + *nread = 4; + gpg->pm.stream_started = 1; + } + else if ( gpg->pm.sig ) { + err = pipemode_copy ( buffer, length, nread, gpg->pm.sig ); + if ( err == GPGME_EOF ) { + gpg->pm.sig = NULL; + assert (length > 4 ); + strcpy (buffer, "@t" ); + *nread = 2; + } + else if (err) { + fprintf (stderr, "** pipemode_cb: copy sig failed: %s\n", + gpgme_strerror (err) ); + return -1; + } + } + else if ( gpg->pm.text ) { + err = pipemode_copy ( buffer, length, nread, gpg->pm.text ); + if ( err == GPGME_EOF ) { + gpg->pm.text = NULL; + assert (length > 4 ); + strcpy (buffer, "@.@>" ); + *nread = 4; + } + else if (err) { + fprintf (stderr, "** pipemode_cb: copy data failed: %s\n", + gpgme_strerror (err) ); + return -1; + } + } + else { + return 0; /* eof */ + } + + return 0; +} + + +/* + * Here we handle --command-fd. This works closely together with + * the status handler. + */ + +static int +command_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) +{ + GpgObject gpg = opaque; + const char *value; + int value_len; + + fprintf (stderr, "** command_cb: enter\n"); + assert (gpg->cmd.used); + if ( !buffer || !length || !nread ) + return 0; /* those values are reserved for extensions */ + *nread =0; + if ( !gpg->cmd.code ) { + fprintf (stderr, "** command_cb: no code\n"); + return -1; + } + + if ( !gpg->cmd.fnc ) { + fprintf (stderr, "** command_cb: no user cb\n"); + return -1; + } + + value = gpg->cmd.fnc ( gpg->cmd.fnc_value, + gpg->cmd.code, gpg->cmd.keyword ); + if ( !value ) { + fprintf (stderr, "** command_cb: no data from user cb\n"); + gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); + return -1; + } + + value_len = strlen (value); + if ( value_len+1 > length ) { + fprintf (stderr, "** command_cb: too much data from user cb\n"); + gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); + return -1; + } + + memcpy ( buffer, value, value_len ); + if ( !value_len || (value_len && value[value_len-1] != '\n') ) + buffer[value_len++] = '\n'; + *nread = value_len; + + fprintf (stderr, "** command_cb: leave (wrote `%.*s')\n", + (int)*nread-1, buffer); + gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); + gpg->cmd.code = 0; + /* and sleep again until read_status will wake us up again */ + _gpgme_freeze_fd ( gpg->cmd.fd ); + return 0; +} + + + + diff --git a/tags/GPGME-0-1-3/gpgme/rungpg.h b/tags/GPGME-0-1-3/gpgme/rungpg.h new file mode 100644 index 0000000..0d7be62 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/rungpg.h @@ -0,0 +1,121 @@ +/* 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 , + STATUS_BEGIN_STREAM , + STATUS_END_STREAM +} GpgStatusCode; + +typedef void (*GpgStatusHandler)( GpgmeCtx, GpgStatusCode code, char *args ); +typedef void (*GpgColonLineHandler)( GpgmeCtx, char *line ); +typedef const char *(*GpgCommandHandler)(void*, GpgStatusCode code, + const char *keyword); + + +GpgmeError _gpgme_gpg_new ( GpgObject *r_gpg ); +void _gpgme_gpg_release ( GpgObject gpg ); +void _gpgme_gpg_enable_pipemode ( GpgObject gpg ); +GpgmeError _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg ); +GpgmeError _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to ); +GpgmeError _gpgme_gpg_add_pm_data ( GpgObject gpg, GpgmeData data, int what ); +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_set_command_handler ( GpgObject gpg, + GpgCommandHandler fnc, + void *fnc_value ); + +GpgmeError _gpgme_gpg_spawn ( GpgObject gpg, void *opaque ); + + + +#endif /* RUNGPG_H */ + + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/sign.c b/tags/GPGME-0-1-3/gpgme/sign.c new file mode 100644 index 0000000..11480e0 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/sign.c @@ -0,0 +1,254 @@ +/* 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 *last_pw_handle; +}; + + +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; + } +} + +static const char * +command_handler ( void *opaque, GpgStatusCode code, const char *key ) +{ + GpgmeCtx c = opaque; + + if ( c->result_type == RESULT_TYPE_NONE ) { + assert ( !c->result.sign ); + c->result.sign = xtrycalloc ( 1, sizeof *c->result.sign ); + if ( !c->result.sign ) { + c->out_of_core = 1; + return NULL; + } + c->result_type = RESULT_TYPE_SIGN; + } + + if ( !code ) { + /* We have been called for cleanup */ + if ( c->passphrase_cb ) { + /* Fixme: take the key in account */ + c->passphrase_cb (c->passphrase_cb_value, 0, + &c->result.sign->last_pw_handle ); + } + + return NULL; + } + + if ( !key || !c->passphrase_cb ) + return NULL; + + if ( code == STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter") ) { + return c->passphrase_cb (c->passphrase_cb_value, + "Please enter your Friedrich Willem!", + &c->result.sign->last_pw_handle ); + } + + return NULL; +} + + +GpgmeError +gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out, + GpgmeSigMode mode ) +{ + int rc = 0; + int i; + + fail_on_pending_request( c ); + c->pending = 1; + + _gpgme_release_result (c); + c->out_of_core = 0; + + + if ( mode != GPGME_SIG_MODE_NORMAL + && mode != GPGME_SIG_MODE_DETACH + && mode != GPGME_SIG_MODE_CLEAR ) + return mk_error (Invalid_Value); + + /* create a process object */ + _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, sign_status_handler, c ); + if (c->passphrase_cb) { + rc = _gpgme_gpg_set_command_handler ( c->gpg, command_handler, c ); + if (rc) + goto leave; + } + + /* build the commandline */ + if ( mode == GPGME_SIG_MODE_CLEAR ) { + _gpgme_gpg_add_arg ( c->gpg, "--clearsign" ); + } + else { + _gpgme_gpg_add_arg ( c->gpg, "--sign" ); + if ( mode == GPGME_SIG_MODE_DETACH ) + _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 + * @mode: Signature creation mode + * + * 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. + * The defined modes for signature create are: + * + * GPGME_SIG_MODE_NORMAL (or 0) + * GPGME_SIG_MODE_DETACH + * GPGME_SIG_MODE_CLEAR + * + * Note that the settings done by gpgme_set_armor() and gpgme_set_textmode() + * are ignore for @mode GPGME_SIG_MODE_CLEAR. + * + * Return value: 0 on success or an error code. + **/ +GpgmeError +gpgme_op_sign ( GpgmeCtx c, GpgmeData in, GpgmeData out, GpgmeSigMode mode ) +{ + GpgmeError err = gpgme_op_sign_start ( c, in, out, mode ); + 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/GPGME-0-1-3/gpgme/status-table.h b/tags/GPGME-0-1-3/gpgme/status-table.h new file mode 100644 index 0000000..4922d4e --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/status-table.h @@ -0,0 +1,70 @@ +/* Generated automatically by mkstatus */ +/* Do not edit! */ + +struct status_table_s { + const char *name; + GpgStatusCode code; +}; + +static struct status_table_s status_table[] = +{ + { "ABORT", STATUS_ABORT }, + { "BADARMOR", STATUS_BADARMOR }, + { "BADMDC", STATUS_BADMDC }, + { "BADSIG", STATUS_BADSIG }, + { "BAD_PASSPHRASE", STATUS_BAD_PASSPHRASE }, + { "BEGIN_DECRYPTION", STATUS_BEGIN_DECRYPTION }, + { "BEGIN_ENCRYPTION", STATUS_BEGIN_ENCRYPTION }, + { "BEGIN_STREAM", STATUS_BEGIN_STREAM }, + { "DECRYPTION_FAILED", STATUS_DECRYPTION_FAILED }, + { "DECRYPTION_OKAY", STATUS_DECRYPTION_OKAY }, + { "DELETE_PROBLEM", STATUS_DELETE_PROBLEM }, + { "ENC_TO", STATUS_ENC_TO }, + { "END_DECRYPTION", STATUS_END_DECRYPTION }, + { "END_ENCRYPTION", STATUS_END_ENCRYPTION }, + { "END_STREAM", STATUS_END_STREAM }, + { "ENTER", STATUS_ENTER }, + { "ERRMDC", STATUS_ERRMDC }, + { "ERRSIG", STATUS_ERRSIG }, + { "FILE_DONE", STATUS_FILE_DONE }, + { "FILE_ERROR", STATUS_FILE_ERROR }, + { "FILE_START", STATUS_FILE_START }, + { "GET_BOOL", STATUS_GET_BOOL }, + { "GET_HIDDEN", STATUS_GET_HIDDEN }, + { "GET_LINE", STATUS_GET_LINE }, + { "GOODMDC", STATUS_GOODMDC }, + { "GOODSIG", STATUS_GOODSIG }, + { "GOOD_PASSPHRASE", STATUS_GOOD_PASSPHRASE }, + { "GOT_IT", STATUS_GOT_IT }, + { "IMPORTED", STATUS_IMPORTED }, + { "IMPORT_RES", STATUS_IMPORT_RES }, + { "KEYREVOKED", STATUS_KEYREVOKED }, + { "LEAVE", STATUS_LEAVE }, + { "MISSING_PASSPHRASE", STATUS_MISSING_PASSPHRASE }, + { "NEED_PASSPHRASE", STATUS_NEED_PASSPHRASE }, + { "NEED_PASSPHRASE_SYM,", STATUS_NEED_PASSPHRASE_SYM, }, + { "NODATA", STATUS_NODATA }, + { "NOTATION_DATA", STATUS_NOTATION_DATA }, + { "NOTATION_NAME", STATUS_NOTATION_NAME }, + { "NO_PUBKEY", STATUS_NO_PUBKEY }, + { "NO_SECKEY", STATUS_NO_SECKEY }, + { "POLICY_URL", STATUS_POLICY_URL }, + { "PROGRESS", STATUS_PROGRESS }, + { "RSA_OR_IDEA", STATUS_RSA_OR_IDEA }, + { "SESSION_KEY", STATUS_SESSION_KEY }, + { "SHM_GET", STATUS_SHM_GET }, + { "SHM_GET_BOOL", STATUS_SHM_GET_BOOL }, + { "SHM_GET_HIDDEN", STATUS_SHM_GET_HIDDEN }, + { "SHM_INFO", STATUS_SHM_INFO }, + { "SIGEXPIRED", STATUS_SIGEXPIRED }, + { "SIG_CREATED", STATUS_SIG_CREATED }, + { "SIG_ID", STATUS_SIG_ID }, + { "TRUST_FULLY", STATUS_TRUST_FULLY }, + { "TRUST_MARGINAL", STATUS_TRUST_MARGINAL }, + { "TRUST_NEVER", STATUS_TRUST_NEVER }, + { "TRUST_ULTIMATE", STATUS_TRUST_ULTIMATE }, + { "TRUST_UNDEFINED", STATUS_TRUST_UNDEFINED }, + { "VALIDSIG", STATUS_VALIDSIG }, + {NULL, 0} +}; + diff --git a/tags/GPGME-0-1-3/gpgme/types.h b/tags/GPGME-0-1-3/gpgme/types.h new file mode 100644 index 0000000..38d83b2 --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/gpgme/util.c b/tags/GPGME-0-1-3/gpgme/util.c new file mode 100644 index 0000000..0210733 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/util.c @@ -0,0 +1,79 @@ +/* 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); +} + + + + +/********************************************* + ********** missing string functions ********* + *********************************************/ + +#ifndef HAVE_STPCPY +char * +stpcpy (char *a, const char *b) +{ + while( *b ) + *a++ = *b++; + *a = 0; + + return a; +} +#endif + diff --git a/tags/GPGME-0-1-3/gpgme/util.h b/tags/GPGME-0-1-3/gpgme/util.h new file mode 100644 index 0000000..72e3eae --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/util.h @@ -0,0 +1,56 @@ +/* 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) + + + +#ifndef HAVE_STPCPY +char *stpcpy (char *a, const char *b); +#endif + + + +#endif /* UTIL_H */ + + + + diff --git a/tags/GPGME-0-1-3/gpgme/verify.c b/tags/GPGME-0-1-3/gpgme/verify.c new file mode 100644 index 0000000..fad5cd9 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/verify.c @@ -0,0 +1,277 @@ +/* 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; + + case STATUS_END_STREAM: + 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; + int pipemode = 0 /*!!text*/; /* use pipemode for detached sigs */ + + fail_on_pending_request( c ); + c->pending = 1; + + _gpgme_release_result (c); + c->out_of_core = 0; + + if ( !pipemode ) { + _gpgme_gpg_release ( c->gpg ); + c->gpg = NULL; + } + + if ( !c->gpg ) + rc = _gpgme_gpg_new ( &c->gpg ); + if (rc) + goto leave; + + if (pipemode) + _gpgme_gpg_enable_pipemode ( c->gpg ); + _gpgme_gpg_set_status_handler ( c->gpg, verify_status_handler, c ); + + /* build the commandline */ + _gpgme_gpg_add_arg ( c->gpg, pipemode?"--pipemode" : "--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, "--" ); + if (pipemode) { + _gpgme_gpg_add_pm_data ( c->gpg, sig, 0 ); + _gpgme_gpg_add_pm_data ( c->gpg, text, 1 ); + } + else { + _gpgme_gpg_add_data ( c->gpg, sig, -1 ); + if (text) { + _gpgme_gpg_add_arg ( c->gpg, "-" ); + _gpgme_gpg_add_data ( c->gpg, text, 0 ); + } + } + + /* and kick off the process */ + rc = _gpgme_gpg_spawn ( c->gpg, c ); + + leave: + if (rc) { + c->pending = 0; + _gpgme_gpg_release ( c->gpg ); c->gpg = NULL; + } + return rc; +} + + +/** + * gpgme_op_verify: + * @c: the context + * @sig: the signature data + * @text: the signed text + * @r_stat: returns the status of the signature + * + * Perform a signature check on the signature given in @sig. Currently it is + * assumed that this is a detached signature for the material given in @text. + * The result of this operation is returned in @r_stat which can take these + * values: + * GPGME_SIG_STAT_NONE: No status - should not happen + * GPGME_SIG_STAT_GOOD: The signature is valid + * GPGME_SIG_STAT_BAD: The signature is not valid + * GPGME_SIG_STAT_NOKEY: The signature could not be checked due to a + * missing key + * GPGME_SIG_STAT_NOSIG: This is not a signature + * GPGME_SIG_STAT_ERROR: Due to some other error the check could not be done. + * FIXME: What do we return if only some o the signatures ae valid? + * + * Return value: 0 on success or an errorcode if something not related to + * the signature itself did go wrong. + **/ +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/GPGME-0-1-3/gpgme/version.c b/tags/GPGME-0-1-3/gpgme/version.c new file mode 100644 index 0000000..0319b06 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/version.c @@ -0,0 +1,104 @@ +/* version.c - version check + * Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include + +#include "gpgme.h" + +static const char* +parse_version_number ( const char *s, int *number ) +{ + int val = 0; + + if ( *s == '0' && isdigit(s[1]) ) + return NULL; /* leading zeros are not allowed */ + for ( ; isdigit(*s); s++ ) { + val *= 10; + val += *s - '0'; + } + *number = val; + return val < 0? NULL : s; +} + + +static const char * +parse_version_string( const char *s, int *major, int *minor, int *micro ) +{ + s = parse_version_number ( s, major ); + if ( !s || *s != '.' ) + return NULL; + s++; + s = parse_version_number ( s, minor ); + if ( !s || *s != '.' ) + return NULL; + s++; + s = parse_version_number ( s, micro ); + if ( !s ) + return NULL; + return s; /* patchlevel */ +} + +/** + * gpgme_check_version: + * @req_version: A string with a version + * + * Check that the the version of the library is at minimum the requested one + * and return the version string; return NULL if the condition is not + * met. If a NULL is passed to this function, no check is done and + * the version string is simply returned. + * + * Return value: The version string or NULL + **/ +const char * +gpgme_check_version ( const char *req_version ) +{ + const char *ver = VERSION; + int my_major, my_minor, my_micro; + int rq_major, rq_minor, rq_micro; + const char *my_plvl, *rq_plvl; + + if ( !req_version ) + return ver; + + my_plvl = parse_version_string ( ver, &my_major, &my_minor, &my_micro ); + if ( !my_plvl ) + return NULL; /* very strange: our own version is bogus */ + rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor, + &rq_micro ); + if ( !rq_plvl ) + return NULL; /* req version string is invalid */ + + if ( my_major > rq_major + || (my_major == rq_major && my_minor > rq_minor) + || (my_major == rq_major && my_minor == rq_minor + && my_micro > rq_micro) + || (my_major == rq_major && my_minor == rq_minor + && my_micro == rq_micro + && strcmp( my_plvl, rq_plvl ) >= 0) ) { + return ver; + } + return NULL; +} + + + diff --git a/tags/GPGME-0-1-3/gpgme/w32-io.c b/tags/GPGME-0-1-3/gpgme/w32-io.c new file mode 100644 index 0000000..237c038 --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/w32-io.c @@ -0,0 +1,602 @@ +/* w32-io.c - W32 API I/O 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 +#ifdef HAVE_DOSISH_SYSTEM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "syshdr.h" + +#include "util.h" +#include "io.h" + +#define DEBUG_SELECT_ENABLED 0 + +#if DEBUG_SELECT_ENABLED +# define DEBUG_SELECT(a) fprintf a +#else +# define DEBUG_SELECT(a) do { } while(0) +#endif + + + +/* + * We assume that a HANDLE can be represented by an int which should be true + * for all i386 systems (HANDLE is defined as void *) and these are the only + * systems for which Windows is available. + * Further we assume that -1 denotes an invalid handle. + */ + +#define fd_to_handle(a) ((HANDLE)(a)) +#define handle_to_fd(a) ((int)(a)) +#define pid_to_handle(a) ((HANDLE)(a)) +#define handle_to_pid(a) ((int)(a)) + + +int +_gpgme_io_read ( int fd, void *buffer, size_t count ) +{ + int nread = 0; + HANDLE h = fd_to_handle (fd); + + DEBUG_SELECT ((stderr,"** fd %d: about to read %d bytes\n", fd, (int)count )); + if ( !ReadFile ( h, buffer, count, &nread, NULL) ) { + fprintf (stderr, "** ReadFile failed: ec=%d\n", (int)GetLastError ()); + return -1; + } + DEBUG_SELECT ((stderr,"** fd %d: got %d bytes\n", fd, nread )); + + return nread; +} + + +int +_gpgme_io_write ( int fd, const void *buffer, size_t count ) +{ + int nwritten; + HANDLE h = fd_to_handle (fd); + + DEBUG_SELECT ((stderr,"** fd %d: about to write %d bytes\n", fd, (int)count )); + if ( !WriteFile ( h, buffer, count, &nwritten, NULL) ) { + fprintf (stderr, "** WriteFile failed: ec=%d\n", (int)GetLastError ()); + return -1; + } + DEBUG_SELECT ((stderr,"** fd %d: wrote %d bytes\n", fd, nwritten )); + + return nwritten; +} + +int +_gpgme_io_pipe ( int filedes[2], int inherit_idx ) +{ + HANDLE r, w; + SECURITY_ATTRIBUTES sec_attr; + + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + if (!CreatePipe ( &r, &w, &sec_attr, 0)) + return -1; + /* make one end inheritable */ + if ( inherit_idx == 0 ) { + HANDLE h; + if (!DuplicateHandle( GetCurrentProcess(), r, + GetCurrentProcess(), &h, 0, + TRUE, DUPLICATE_SAME_ACCESS ) ) { + fprintf (stderr, "** DuplicateHandle failed: ec=%d\n", + (int)GetLastError()); + CloseHandle (r); + CloseHandle (w); + return -1; + } + CloseHandle (r); + r = h; + } + else if ( inherit_idx == 1 ) { + HANDLE h; + if (!DuplicateHandle( GetCurrentProcess(), w, + GetCurrentProcess(), &h, 0, + TRUE, DUPLICATE_SAME_ACCESS ) ) { + fprintf (stderr, "** DuplicateHandle failed: ec=%d\n", + (int)GetLastError()); + CloseHandle (r); + CloseHandle (w); + return -1; + } + CloseHandle (w); + w = h; + } + + filedes[0] = handle_to_fd (r); + filedes[1] = handle_to_fd (w); + DEBUG_SELECT ((stderr,"** create pipe %p %p %d %d inherit=%d\n", r, w, + filedes[0], filedes[1], inherit_idx )); + return 0; +} + +int +_gpgme_io_close ( int fd ) +{ + if ( fd == -1 ) + return -1; + + DEBUG_SELECT ((stderr,"** closing handle for fd %d\n", fd)); + if ( !CloseHandle (fd_to_handle (fd)) ) { + fprintf (stderr, "** CloseHandle for fd %d failed: ec=%d\n", + fd, (int)GetLastError ()); + return -1; + } + + return 0; +} + + +int +_gpgme_io_set_nonblocking ( int fd ) +{ + return 0; +} + + +static char * +build_commandline ( char **argv ) +{ + int i, n = 0; + char *buf, *p; + + /* FIXME: we have to quote some things because under Windows the + * program parses the commandline and does some unquoting */ + for (i=0; argv[i]; i++) + n += strlen (argv[i]) + 1; + buf = p = xtrymalloc (n); + if ( !buf ) + return NULL; + *buf = 0; + if ( argv[0] ) + p = stpcpy (p, argv[0]); + for (i = 1; argv[i]; i++) + p = stpcpy (stpcpy (p, " "), argv[i]); + + return buf; +} + + +int +_gpgme_io_spawn ( const char *path, char **argv, + struct spawn_fd_item_s *fd_child_list, + struct spawn_fd_item_s *fd_parent_list ) +{ + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION pi = { + NULL, /* returns process handle */ + 0, /* returns primary thread handle */ + 0, /* returns pid */ + 0 /* returns tid */ + }; + STARTUPINFO si; + char *envblock = NULL; + int cr_flags = CREATE_DEFAULT_ERROR_MODE + | GetPriorityClass (GetCurrentProcess ()); + int i; + char *arg_string; + int duped_stdin = 0; + int duped_stderr = 0; + HANDLE hnul = INVALID_HANDLE_VALUE; + int debug_me = !!getenv ("GPGME_DEBUG"); + + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + arg_string = build_commandline ( argv ); + if (!arg_string ) + return -1; + + memset (&si, 0, sizeof si); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = debug_me? SW_SHOW : SW_MINIMIZE; + si.hStdInput = GetStdHandle (STD_INPUT_HANDLE); + si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); + si.hStdError = GetStdHandle (STD_ERROR_HANDLE); + + for (i=0; fd_child_list[i].fd != -1; i++ ) { + if (fd_child_list[i].dup_to == 0 ) { + si.hStdInput = fd_to_handle (fd_child_list[i].fd); + DEBUG_SELECT ((stderr,"** using %d for stdin\n", fd_child_list[i].fd )); + duped_stdin=1; + } + else if (fd_child_list[i].dup_to == 1 ) { + si.hStdOutput = fd_to_handle (fd_child_list[i].fd); + DEBUG_SELECT ((stderr,"** using %d for stdout\n", fd_child_list[i].fd )); + } + else if (fd_child_list[i].dup_to == 2 ) { + si.hStdError = fd_to_handle (fd_child_list[i].fd); + DEBUG_SELECT ((stderr,"** using %d for stderr\n", fd_child_list[i].fd )); + duped_stderr = 1; + } + } + + if( !duped_stdin || !duped_stderr ) { + SECURITY_ATTRIBUTES sa; + + memset (&sa, 0, sizeof sa ); + sa.nLength = sizeof sa; + sa.bInheritHandle = TRUE; + hnul = CreateFile ( "/dev/nul", + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + &sa, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + if ( hnul == INVALID_HANDLE_VALUE ) { + fprintf (stderr,"can't open `/dev/nul': ec=%d\n", + (int)GetLastError () ); + xfree (arg_string); + return -1; + } + /* Make sure that the process has a connected stdin */ + if ( !duped_stdin ) { + si.hStdInput = hnul; + DEBUG_SELECT ((stderr,"** using %d for stdin\n", (int)hnul )); + } + /* We normally don't want all the normal output */ + if ( !duped_stderr ) { + if (!debug_me) { + si.hStdError = hnul; + DEBUG_SELECT ((stderr,"** using %d for stderr\n", (int)hnul )); + } + } + } + + DEBUG_SELECT ((stderr,"** CreateProcess ...\n")); + DEBUG_SELECT ((stderr,"** args=`%s'\n", arg_string)); + cr_flags |= CREATE_SUSPENDED; + if ( !CreateProcessA (GPG_PATH, + arg_string, + &sec_attr, /* process security attributes */ + &sec_attr, /* thread security attributes */ + TRUE, /* inherit handles */ + cr_flags, /* creation flags */ + envblock, /* environment */ + NULL, /* use current drive/directory */ + &si, /* startup information */ + &pi /* returns process information */ + ) ) { + fprintf (stderr, "** CreateProcess failed: ec=%d\n", + (int) GetLastError ()); + xfree (arg_string); + return -1; + } + + /* close the /dev/nul handle if used */ + if (hnul != INVALID_HANDLE_VALUE ) { + if ( !CloseHandle ( hnul ) ) + fprintf (stderr, "** CloseHandle(hnul) failed: ec=%d\n", + (int)GetLastError()); + } + + /* Close the other ends of the pipes */ + for (i=0; fd_parent_list[i].fd != -1; i++ ) { + DEBUG_SELECT ((stderr,"** Closing fd %d\n", fd_parent_list[i].fd )); + if ( !CloseHandle ( fd_to_handle (fd_parent_list[i].fd) ) ) + fprintf (stderr, "** CloseHandle failed: ec=%d\n", + (int)GetLastError()); + } + + DEBUG_SELECT ((stderr,"** CreateProcess ready\n" + "** hProcess=%p hThread=%p\n" + "** dwProcessID=%d dwThreadId=%d\n", + pi.hProcess, pi.hThread, + (int) pi.dwProcessId, (int) pi.dwThreadId)); + + if ( ResumeThread ( pi.hThread ) < 0 ) { + fprintf (stderr, "** ResumeThread failed: ec=%d\n", + (int)GetLastError ()); + } + + if ( !CloseHandle (pi.hThread) ) { + fprintf (stderr, "** CloseHandle of thread failed: ec=%d\n", + (int)GetLastError ()); + } + + return handle_to_pid (pi.hProcess); +} + + + + +int +_gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal ) +{ + HANDLE proc = fd_to_handle (pid); + int code, exc, ret = 0; + + *r_status = 0; + *r_signal = 0; + code = WaitForSingleObject ( proc, hang? INFINITE : 0 ); + switch (code) { + case WAIT_FAILED: + fprintf (stderr, "** WFSO pid=%d failed: %d\n", + (int)pid, (int)GetLastError () ); + break; + + case WAIT_OBJECT_0: + if (!GetExitCodeProcess (proc, &exc)) { + fprintf (stderr, "** GECP pid=%d failed: ec=%d\n", + (int)pid, (int)GetLastError () ); + *r_status = 4; + } + else { + DEBUG_SELECT ((stderr,"** GECP pid=%d exit code=%d\n", + (int)pid, exc)); + *r_status = exc; + } + ret = 1; + break; + + case WAIT_TIMEOUT: + DEBUG_SELECT ((stderr,"** WFSO pid=%d timed out\n", (int)pid)); + break; + + default: + fprintf (stderr, "** WFSO pid=%d returned %d\n", (int)pid, code ); + break; + } + return ret; +} + + +/* + * Select on the list of fds. + * Returns: -1 = error + * 0 = timeout or nothing to select + * >0 = number of signaled fds + */ +int +_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) +{ +#if 0 /* We can't use WFMO becaus a pipe handle is not a suitable object */ + HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS]; + int code, nwait; + int i, any, any_write; + int count; + + restart: + DEBUG_SELECT ((stderr, "gpgme:select on [ ")); + any = any_write = 0; + nwait = 0; + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( fds[i].for_read || fds[i].for_write ) { + if ( nwait >= DIM (waitbuf) ) { + DEBUG_SELECT ((stderr,stderr, "oops ]\n" )); + fprintf (stderr, "** Too many objects for WFMO!\n" ); + return -1; + } + else { + if ( fds[i].for_read ) + waitbuf[nwait++] = fd_to_handle (fds[i].fd); + DEBUG_SELECT ((stderr, "%c%d ", + fds[i].for_read? 'r':'w',fds[i].fd )); + any = 1; + } + } + fds[i].signaled = 0; + } + DEBUG_SELECT ((stderr, "]\n" )); + if (!any) + return 0; + + count = 0; + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( fds[i].for_write ) { + fds[i].signaled = 1; + any_write =1; + count++; + } + } + code = WaitForMultipleObjects ( nwait, waitbuf, 0, any_write? 0:1000); + if (code == WAIT_FAILED ) { + int le = (int)GetLastError (); + if ( le == ERROR_INVALID_HANDLE || le == ERROR_INVALID_EVENT_COUNT ) { + any = 0; + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( fds[i].for_read /*|| fds[i].for_write*/ ) { + int navail; + if (PeekNamedPipe (fd_to_handle (fds[i].fd), + NULL, 0, NULL, + &navail, NULL) && navail ) { + fds[i].signaled = 1; + any = 1; + count++; + } + } + } + if (any) + return count; + /* find that handle and remove it from the list*/ + for (i=0; i < nwait; i++ ) { + code = WaitForSingleObject ( waitbuf[i], NULL ); + if (!code) { + int k, j = handle_to_fd (waitbuf[i]); + + fprintf (stderr, "** handle meanwhile signaled %d\n", j); + for (k=0 ; k < nfds; k++ ) { + if ( fds[k].fd == j ) { + fds[k].signaled = 1; + count++; + return count; + } + } + fprintf (stderr, "** oops, or not???\n"); + } + if ( GetLastError () == ERROR_INVALID_HANDLE) { + int k, j = handle_to_fd (waitbuf[i]); + + fprintf (stderr, "** WFMO invalid handle %d removed\n", j); + for (k=0 ; k < nfds; i++ ) { + if ( fds[k].fd == j ) { + fds[k].for_read = fds[k].for_write = 0; + goto restart; + } + } + fprintf (stderr, "** oops, or not???\n"); + } + } + } + + fprintf (stderr, "** WFMO failed: %d\n", le ); + count = -1; + } + else if ( code == WAIT_TIMEOUT ) { + fprintf (stderr, "** WFMO timed out\n" ); + } + else if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) { + /* This WFMO is a really silly function: It does return either + * the index of the signaled object or if 2 objects have been + * signalled at the same time, the index of the object with the + * lowest object is returned - so and how do we find out + * how many objects have been signaled???. + * The only solution I can imagine is to test each object starting + * with the returned index individually - how dull. + */ + any = 0; + for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) { + if (WaitForSingleObject ( waitbuf[i], NULL ) == WAIT_OBJECT_0) { + fds[i].signaled = 1; + any = 1; + count++; + } + } + if (!any) { + fprintf (stderr, + "** Oops: No signaled objects found after WFMO\n"); + count = -1; + } + } + else { + fprintf (stderr, "** WFMO returned %d\n", code ); + count = -1; + } + + return count; +#else /* This is the code we use */ + int i, any, count; + int once_more = 0; + + DEBUG_SELECT ((stderr, "gpgme:fakedselect on [ ")); + any = 0; + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( fds[i].for_read || fds[i].for_write ) { + DEBUG_SELECT ((stderr, "%c%d ", + fds[i].for_read? 'r':'w',fds[i].fd )); + any = 1; + } + fds[i].signaled = 0; + } + DEBUG_SELECT ((stderr, "]\n" )); + if (!any) + return 0; + + restart: + count = 0; + /* no way to see whether a handle is ready fro writing, signal all */ + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( fds[i].for_write ) { + fds[i].signaled = 1; + count++; + } + } + + /* now peek on all read handles */ + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( fds[i].for_read ) { + int navail; + + if ( !PeekNamedPipe (fd_to_handle (fds[i].fd), + NULL, 0, NULL, &navail, NULL) ) { + fprintf (stderr, "** select: PeekFile failed: ec=%d\n", + (int)GetLastError ()); + } + else if ( navail ) { + /*fprintf (stderr, "** fd %d has %d bytes to read\n", + fds[i].fd, navail );*/ + fds[i].signaled = 1; + count++; + } + } + } + if ( !once_more && !count ) { + /* once more but after relinquishing our timeslot */ + once_more = 1; + Sleep (0); + goto restart; + } + + if ( count ) { + DEBUG_SELECT ((stderr, "gpgme: signaled [ ")); + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) { + DEBUG_SELECT ((stderr, "%c%d ", + fds[i].for_read? 'r':'w',fds[i].fd )); + } + } + DEBUG_SELECT ((stderr, "]\n" )); + } + + return count; +#endif +} + +#endif /*HAVE_DOSISH_SYSTEM*/ + + + + + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/wait.c b/tags/GPGME-0-1-3/gpgme/wait.c new file mode 100644 index 0000000..edd492e --- /dev/null +++ b/tags/GPGME-0-1-3/gpgme/wait.c @@ -0,0 +1,368 @@ +/* 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 "syshdr.h" + +#include "util.h" +#include "context.h" +#include "ops.h" +#include "wait.h" +#include "io.h" + +/* 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_table() do { } while (0) +#define unlock_table() do { } while (0) + + +struct wait_item_s { + volatile int active; + int (*handler)(void*,int,int); + void *handler_value; + int pid; + int inbound; /* this is an inbound data handler fd */ + int exited; + int exit_status; + int exit_signal; + GpgmeCtx ctx; +}; + +static int fd_table_size; +static struct io_select_fd_s *fd_table; + +static int do_select ( void ); + + +static struct wait_item_s * +queue_item_from_context ( GpgmeCtx ctx ) +{ + struct wait_item_s *q; + int i; + + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->ctx == ctx ) + return q; + } + return NULL; +} + + +static void +propagate_term_results ( const struct wait_item_s *first_q ) +{ + struct wait_item_s *q; + int i; + + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) + && q != 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 ( int pid ) +{ + struct wait_item_s *q; + int i, count = 0; + + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) + && q->active && q->pid == pid ) + count++; + } + return count; +} + +static void +clear_active_fds ( int pid ) +{ + struct wait_item_s *q; + int i; + + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) + && q->active && q->pid == pid ) + q->active = 0; + } +} + + +/* remove the given process from the queue */ +static void +remove_process ( int pid ) +{ + struct wait_item_s *q; + int i; + + for (i=0; i < fd_table_size; i++ ) { + if (fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->pid == pid ) { + xfree (q); + fd_table[i].opaque = NULL; + + if ( !fd_table[i].is_closed ) { + _gpgme_io_close (fd_table[i].fd); + fd_table[i].is_closed = 1; + } + fd_table[i].fd = -1; + } + } +} + + + +/** + * 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_item_s *q; + + do { + int did_work = do_select(); + + if ( cond && *cond ) + hang = 0; + + if ( !did_work ) { + /* We did no read/write - see whether the process is still + * alive */ + assert (c); /* !c is not yet implemented */ + q = queue_item_from_context ( c ); + assert (q); + + if (q->exited) { + /* this is the second time we reached this and we got no + * more data from the pipe (which may happen to to buffering). + * Set all FDs inactive. + */ + clear_active_fds (q->pid); + } + else if ( _gpgme_io_waitpid (q->pid, 0, + &q->exit_status, &q->exit_signal)){ + q->exited = 1; + 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!! + * Returns: 0 = nothing to run + * 1 = did run something + */ + +static int +do_select ( void ) +{ + struct wait_item_s *q; + int i, n; + int any=0; + + n = _gpgme_io_select ( fd_table, fd_table_size ); + if ( n <= 0 ) + return 0; /* error or timeout */ + + for (i=0; i < fd_table_size && n; i++ ) { + if ( fd_table[i].fd != -1 && fd_table[i].signaled + && !fd_table[i].frozen ) { + q = fd_table[i].opaque; + assert (n); + n--; + if ( q->active ) + any = 1; + if ( q->active && q->handler (q->handler_value, + q->pid, fd_table[i].fd ) ) { + q->active = 0; + fd_table[i].for_read = 0; + fd_table[i].for_write = 0; + fd_table[i].is_closed = 1; + } + } + } + + return any; +} + + + +/* + * called by rungpg.c to register something for select() + */ +GpgmeError +_gpgme_register_pipe_handler ( void *opaque, + int (*handler)(void*,int,int), + void *handler_value, + int pid, int fd, int inbound ) +{ + GpgmeCtx ctx = opaque; + struct wait_item_s *q; + int i; + + assert (opaque); + assert (handler); + + q = xtrycalloc ( 1, sizeof *q ); + if ( !q ) + return mk_error (Out_Of_Core); + q->inbound = inbound; + q->handler = handler; + q->handler_value = handler_value; + q->pid = pid; + q->ctx = ctx; + q->active = 1; + + lock_table (); + again: + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd == -1 ) { + fd_table[i].fd = fd; + fd_table[i].is_closed = 0; + fd_table[i].for_read = inbound; + fd_table[i].for_write = !inbound; + fd_table[i].signaled = 0; + fd_table[i].frozen = 0; + fd_table[i].opaque = q; + unlock_table (); + return 0; + } + } + if ( fd_table_size < 50 ) { + /* FIXME: We have to wait until there are no other readers of the + * table, i.e that the io_select is not active in another thread */ + struct io_select_fd_s *tmp; + + tmp = xtryrealloc ( fd_table, (fd_table_size + 10) * sizeof *tmp ); + if ( tmp ) { + for (i=0; i < 10; i++ ) + tmp[fd_table_size+i].fd = -1; + fd_table_size += i; + fd_table = tmp; + goto again; + } + } + + unlock_table (); + xfree (q); + return mk_error (Too_Many_Procs); +} + + +void +_gpgme_freeze_fd ( int fd ) +{ + int i; + + lock_table (); + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd == fd ) { + fd_table[i].frozen = 1; + /*fprintf (stderr, "** FD %d frozen\n", fd );*/ + break; + } + } + unlock_table (); +} + +void +_gpgme_thaw_fd ( int fd ) +{ + int i; + + lock_table (); + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd == fd ) { + fd_table[i].frozen = 0; + /*fprintf (stderr, "** FD %d thawed\n", fd );*/ + break; + } + } + unlock_table (); +} + + + + + + + + + + + + + + + + diff --git a/tags/GPGME-0-1-3/gpgme/wait.h b/tags/GPGME-0-1-3/gpgme/wait.h new file mode 100644 index 0000000..775be1d --- /dev/null +++ b/tags/GPGME-0-1-3/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*,int,int), + void *handler_value, + int pid, int fd, int inbound ); + + + +#endif /* WAIT_H */ + + + + + diff --git a/tags/GPGME-0-1-3/jnlib/ChangeLog b/tags/GPGME-0-1-3/jnlib/ChangeLog new file mode 100644 index 0000000..ed5e20a --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/ChangeLog @@ -0,0 +1,41 @@ +2000-07-26 10:02:51 Werner Koch (wk@habibti.openit.de) + + * stringhelp.c.: Add stdarg.h + * argparse.h: s/ulong/unsigned long/ although this should be defined + by types.h. + +2000-06-28 19:40:23 Werner Koch (wk@habibti.openit.de) + + * Makefile.am: Replaced second logging.c by .h + +2000-05-24 08:58:15 Werner Koch (wk@habibti.openit.de) + + * logging.c (log_get_errorcount): New. + +2000-05-24 08:44:47 Werner Koch (wk@habibti.openit.de) + + * stringhelp.c: Added a few filename related helper functions. + +2000-05-11 18:04:43 Werner Koch (wk@habibti.openit.de) + + * xmalloc.c (xstrcat2): Replaced stpcpy to quickly address W32 + problems. + +2000-05-02 19:43:38 Werner Koch (wk@habibti.openit.de) + + * xmalloc.c (xstrcat2): New. + +Mon Jan 24 13:04:28 CET 2000 Werner Koch + + * README: New. + * Makefile.am: new. + * argparse.c argparse.h logging.c logging.h + mischelp.h stringhelp.c stringhelp.h xmalloc.c + xmalloc.h dotlock.c: Moved from ../util to here. + * dotlock.h: New. + * libjnlib-config.h: New. + + * logging.c (log_set_file): New. + (log_printf): New. + (do_logv): Add kludge to insert LFs. + diff --git a/tags/GPGME-0-1-3/jnlib/README b/tags/GPGME-0-1-3/jnlib/README new file mode 100644 index 0000000..e49ef44 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/README @@ -0,0 +1,7 @@ +jnlib - this is a collection of utility function which are +too small to put into a library. + +libjnlib-config.h should be be modified for each project +to make these functions fit into the software. Mainly these +are memory functions in case you need another allocator. + diff --git a/tags/GPGME-0-1-3/jnlib/argparse.c b/tags/GPGME-0-1-3/jnlib/argparse.c new file mode 100644 index 0000000..0384c5d --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/argparse.c @@ -0,0 +1,995 @@ +/* [argparse.c wk 17.06.97] Argument Parser for option handling + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 "libjnlib-config.h" +#include "mischelp.h" +#include "stringhelp.h" +#include "logging.h" +#include "argparse.h" + + +/********************************* + * @Summary arg_parse + * #include + * + * typedef struct { + * char *argc; pointer to argc (value subject to change) + * char ***argv; pointer to argv (value subject to change) + * unsigned flags; Global flags (DO NOT CHANGE) + * int err; print error about last option + * 1 = warning, 2 = abort + * int r_opt; return option + * int r_type; type of return value (0 = no argument found) + * union { + * int ret_int; + * long ret_long + * ulong ret_ulong; + * char *ret_str; + * } r; Return values + * struct { + * int idx; + * const char *last; + * void *aliases; + * } internal; DO NOT CHANGE + * } ARGPARSE_ARGS; + * + * typedef struct { + * int short_opt; + * const char *long_opt; + * unsigned flags; + * } ARGPARSE_OPTS; + * + * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts ); + * + * @Description + * This is my replacement for getopt(). See the example for a typical usage. + * Global flags are: + * Bit 0 : Do not remove options form argv + * Bit 1 : Do not stop at last option but return other args + * with r_opt set to -1. + * Bit 2 : Assume options and real args are mixed. + * Bit 3 : Do not use -- to stop option processing. + * Bit 4 : Do not skip the first arg. + * Bit 5 : allow usage of long option with only one dash + * Bit 6 : ignore --version + * all other bits must be set to zero, this value is modified by the + * function, so assume this is write only. + * Local flags (for each option): + * Bit 2-0 : 0 = does not take an argument + * 1 = takes int argument + * 2 = takes string argument + * 3 = takes long argument + * 4 = takes ulong argument + * Bit 3 : argument is optional (r_type will the be set to 0) + * Bit 4 : allow 0x etc. prefixed values. + * Bit 7 : this is a command and not an option + * You stop the option processing by setting opts to NULL, the function will + * then return 0. + * @Return Value + * Returns the args.r_opt or 0 if ready + * r_opt may be -2/-7 to indicate an unknown option/command. + * @See Also + * ArgExpand + * @Notes + * You do not need to process the options 'h', '--help' or '--version' + * because this function includes standard help processing; but if you + * specify '-h', '--help' or '--version' you have to do it yourself. + * The option '--' stops argument processing; if bit 1 is set the function + * continues to return normal arguments. + * To process float args or unsigned args you must use a string args and do + * the conversion yourself. + * @Example + * + * ARGPARSE_OPTS opts[] = { + * { 'v', "verbose", 0 }, + * { 'd', "debug", 0 }, + * { 'o', "output", 2 }, + * { 'c', "cross-ref", 2|8 }, + * { 'm', "my-option", 1|8 }, + * { 500, "have-no-short-option-for-this-long-option", 0 }, + * {0} }; + * ARGPARSE_ARGS pargs = { &argc, &argv, 0 } + * + * while( ArgParse( &pargs, &opts) ) { + * switch( pargs.r_opt ) { + * case 'v': opt.verbose++; break; + * case 'd': opt.debug++; break; + * case 'o': opt.outfile = pargs.r.ret_str; break; + * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + * case 500: opt.a_long_one++; break + * default : pargs.err = 1; break; -- force warning output -- + * } + * } + * if( argc > 1 ) + * log_fatal( "Too many args"); + * + */ + +typedef struct alias_def_s *ALIAS_DEF; +struct alias_def_s { + ALIAS_DEF next; + char *name; /* malloced buffer with name, \0, value */ + const char *value; /* ptr into name */ +}; + +static const char *(*strusage_handler)( int ) = NULL; + +static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s); +static void show_help(ARGPARSE_OPTS *opts, unsigned flags); +static void show_version(void); + + +static void +initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno ) +{ + if( !(arg->flags & (1<<15)) ) { /* initialize this instance */ + arg->internal.idx = 0; + arg->internal.last = NULL; + arg->internal.inarg = 0; + arg->internal.stopped = 0; + arg->internal.aliases = NULL; + arg->internal.cur_alias = NULL; + arg->err = 0; + arg->flags |= 1<<15; /* mark initialized */ + if( *arg->argc < 0 ) + jnlib_log_bug("Invalid argument for ArgParse\n"); + } + + + if( arg->err ) { /* last option was erroneous */ + const char *s; + + if( filename ) { + if( arg->r_opt == -6 ) + s = "%s:%u: argument not expected\n"; + else if( arg->r_opt == -5 ) + s = "%s:%u: read error\n"; + else if( arg->r_opt == -4 ) + s = "%s:%u: keyword too long\n"; + else if( arg->r_opt == -3 ) + s = "%s:%u: missing argument\n"; + else if( arg->r_opt == -7 ) + s = "%s:%u: invalid command\n"; + else if( arg->r_opt == -10 ) + s = "%s:%u: invalid alias definition\n"; + else + s = "%s:%u: invalid option\n"; + jnlib_log_error(s, filename, *lineno ); + } + else { + if( arg->r_opt == -3 ) + s = "Missing argument for option \"%.50s\"\n"; + else if( arg->r_opt == -6 ) + s = "Option \"%.50s\" does not expect an argument\n"; + else if( arg->r_opt == -7 ) + s = "Invalid command \"%.50s\"\n"; + else if( arg->r_opt == -8 ) + s = "Option \"%.50s\" is ambiguous\n"; + else if( arg->r_opt == -9 ) + s = "Command \"%.50s\" is ambiguous\n"; + else + s = "Invalid option \"%.50s\"\n"; + jnlib_log_error(s, arg->internal.last? arg->internal.last:"[??]" ); + } + if( arg->err != 1 ) + exit(2); + arg->err = 0; + } + + /* clearout the return value union */ + arg->r.ret_str = NULL; + arg->r.ret_long= 0; +} + + +static void +store_alias( ARGPARSE_ARGS *arg, char *name, char *value ) +{ + /* TODO: replace this dummy function with a rea one + * and fix the probelms IRIX has with (ALIAS_DEV)arg.. + * used as lvalue + */ +#if 0 + ALIAS_DEF a = jnlib_xmalloc( sizeof *a ); + a->name = name; + a->value = value; + a->next = (ALIAS_DEF)arg->internal.aliases; + (ALIAS_DEF)arg->internal.aliases = a; +#endif +} + +/**************** + * Get options from a file. + * Lines starting with '#' are comment lines. + * Syntax is simply a keyword and the argument. + * Valid keywords are all keywords from the long_opt list without + * the leading dashes. The special keywords "help", "warranty" and "version" + * are not valid here. + * The special keyword "alias" may be used to store alias definitions, + * which are later expanded like long options. + * Caller must free returned strings. + * If called with FP set to NULL command line args are parse instead. + * + * Q: Should we allow the syntax + * keyword = value + * and accept for boolean options a value of 1/0, yes/no or true/false? + * Note: Abbreviation of options is here not allowed. + */ +int +optfile_parse( FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int state, i, c; + int idx=0; + char keyword[100]; + char *buffer = NULL; + size_t buflen = 0; + int inverse=0; + int in_alias=0; + + if( !fp ) /* same as arg_parse() in this case */ + return arg_parse( arg, opts ); + + initialize( arg, filename, lineno ); + + /* find the next keyword */ + state = i = 0; + for(;;) { + c=getc(fp); + if( c == '\n' || c== EOF ) { + if( c != EOF ) + ++*lineno; + if( state == -1 ) + break; + else if( state == 2 ) { + keyword[i] = 0; + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) ) + break; + idx = i; + arg->r_opt = opts[idx].short_opt; + if( inverse ) /* this does not have an effect, hmmm */ + arg->r_opt = -arg->r_opt; + if( !opts[idx].short_opt ) /* unknown command/option */ + arg->r_opt = (opts[idx].flags & 256)? -7:-2; + else if( (opts[idx].flags & 8) ) /* no argument */ + arg->r_opt = -3; /* error */ + else /* no or optional argument */ + arg->r_type = 0; /* okay */ + break; + } + else if( state == 3 ) { /* no argument found */ + if( in_alias ) + arg->r_opt = -3; /* error */ + else if( !(opts[idx].flags & 7) ) /* does not take an arg */ + arg->r_type = 0; /* okay */ + else if( (opts[idx].flags & 8) ) /* no optional argument */ + arg->r_type = 0; /* okay */ + else /* no required argument */ + arg->r_opt = -3; /* error */ + break; + } + else if( state == 4 ) { /* have an argument */ + if( in_alias ) { + if( !buffer ) + arg->r_opt = -6; + else { + char *p; + + buffer[i] = 0; + p = strpbrk( buffer, " \t" ); + if( p ) { + *p++ = 0; + trim_spaces( p ); + } + if( !p || !*p ) { + jnlib_free( buffer ); + arg->r_opt = -10; + } + else { + store_alias( arg, buffer, p ); + } + } + } + else if( !(opts[idx].flags & 7) ) /* does not take an arg */ + arg->r_opt = -6; /* error */ + else { + char *p; + if( !buffer ) { + keyword[i] = 0; + buffer = jnlib_xstrdup(keyword); + } + else + buffer[i] = 0; + + trim_spaces( buffer ); + p = buffer; + if( *p == '"' ) { /* remove quotes */ + p++; + if( *p && p[strlen(p)-1] == '"' ) + p[strlen(p)-1] = 0; + } + if( !set_opt_arg(arg, opts[idx].flags, p) ) + jnlib_free(buffer); + } + break; + } + else if( c == EOF ) { + if( ferror(fp) ) + arg->r_opt = -5; /* read error */ + else + arg->r_opt = 0; /* eof */ + break; + } + state = 0; + i = 0; + } + else if( state == -1 ) + ; /* skip */ + else if( !state && isspace(c) ) + ; /* skip leading white space */ + else if( !state && c == '#' ) + state = 1; /* start of a comment */ + else if( state == 1 ) + ; /* skip comments */ + else if( state == 2 && isspace(c) ) { + keyword[i] = 0; + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) ) + break; + idx = i; + arg->r_opt = opts[idx].short_opt; + if( !opts[idx].short_opt ) { + if( !strcmp( keyword, "alias" ) ) { + in_alias = 1; + state = 3; + } + else { + arg->r_opt = (opts[idx].flags & 256)? -7:-2; + state = -1; /* skip rest of line and leave */ + } + } + else + state = 3; + } + else if( state == 3 ) { /* skip leading spaces of the argument */ + if( !isspace(c) ) { + i = 0; + keyword[i++] = c; + state = 4; + } + } + else if( state == 4 ) { /* collect the argument */ + if( buffer ) { + if( i < buflen-1 ) + buffer[i++] = c; + else { + buflen += 50; + buffer = jnlib_xrealloc(buffer, buflen); + buffer[i++] = c; + } + } + else if( i < DIM(keyword)-1 ) + keyword[i++] = c; + else { + buflen = DIM(keyword)+50; + buffer = jnlib_xmalloc(buflen); + memcpy(buffer, keyword, i); + buffer[i++] = c; + } + } + else if( i >= DIM(keyword)-1 ) { + arg->r_opt = -4; /* keyword to long */ + state = -1; /* skip rest of line and leave */ + } + else { + keyword[i++] = c; + state = 2; + } + } + + return arg->r_opt; +} + + + +static int +find_long_option( ARGPARSE_ARGS *arg, + ARGPARSE_OPTS *opts, const char *keyword ) +{ + int i; + size_t n; + + /* Would be better if we can do a binary search, but it is not + possible to reorder our option table because we would mess + up our help strings - What we can do is: Build a nice option + lookup table wehn this function is first invoked */ + if( !*keyword ) + return -1; + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) ) + return i; + #if 0 + { + ALIAS_DEF a; + /* see whether it is an alias */ + for( a = args->internal.aliases; a; a = a->next ) { + if( !strcmp( a->name, keyword) ) { + /* todo: must parse the alias here */ + args->internal.cur_alias = a; + return -3; /* alias available */ + } + } + } + #endif + /* not found, see whether it is an abbreviation */ + /* aliases may not be abbreviated */ + n = strlen( keyword ); + for(i=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) { + int j; + for(j=i+1; opts[j].short_opt; j++ ) { + if( opts[j].long_opt + && !strncmp( opts[j].long_opt, keyword, n ) ) + return -2; /* abbreviation is ambiguous */ + } + return i; + } + } + return -1; +} + +int +arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int idx; + int argc; + char **argv; + char *s, *s2; + int i; + + initialize( arg, NULL, NULL ); + argc = *arg->argc; + argv = *arg->argv; + idx = arg->internal.idx; + + if( !idx && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */ + argc--; argv++; idx++; + } + + next_one: + if( !argc ) { /* no more args */ + arg->r_opt = 0; + goto leave; /* ready */ + } + + s = *argv; + arg->internal.last = s; + + if( arg->internal.stopped && (arg->flags & (1<<1)) ) { + arg->r_opt = -1; /* not an option but a argument */ + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; idx++; /* set to next one */ + } + else if( arg->internal.stopped ) { /* ready */ + arg->r_opt = 0; + goto leave; + } + else if( *s == '-' && s[1] == '-' ) { /* long option */ + char *argpos; + + arg->internal.inarg = 0; + if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */ + arg->internal.stopped = 1; + argc--; argv++; idx++; + goto next_one; + } + + argpos = strchr( s+2, '=' ); + if( argpos ) + *argpos = 0; + i = find_long_option( arg, opts, s+2 ); + if( argpos ) + *argpos = '='; + + if( i < 0 && !strcmp( "help", s+2) ) + show_help(opts, arg->flags); + else if( i < 0 && !strcmp( "version", s+2) ) { + if( !(arg->flags & (1<<6)) ) { + show_version(); + exit(0); + } + } + else if( i < 0 && !strcmp( "warranty", s+2) ) { + puts( strusage(16) ); + exit(0); + } + else if( i < 0 && !strcmp( "dump-options", s+2) ) { + for(i=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt ) + printf( "--%s\n", opts[i].long_opt ); + } + fputs("--dump-options\n--help\n--version\n--warranty\n", stdout ); + exit(0); + } + + if( i == -2 ) /* ambiguous option */ + arg->r_opt = -8; + else if( i == -1 ) { + arg->r_opt = -2; + arg->r.ret_str = s+2; + } + else + arg->r_opt = opts[i].short_opt; + if( i < 0 ) + ; + else if( (opts[i].flags & 7) ) { + if( argpos ) { + s2 = argpos+1; + if( !*s2 ) + s2 = NULL; + } + else + s2 = argv[1]; + if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/ + arg->r_type = 0; /* because it is optional */ + } + else if( !s2 ) { + arg->r_opt = -3; /* missing argument */ + } + else if( !argpos && *s2 == '-' && (opts[i].flags & 8) ) { + /* the argument is optional and the next seems to be + * an option. We do not check this possible option + * but assume no argument */ + arg->r_type = 0; + } + else { + set_opt_arg(arg, opts[i].flags, s2); + if( !argpos ) { + argc--; argv++; idx++; /* skip one */ + } + } + } + else { /* does not take an argument */ + if( argpos ) + arg->r_type = -6; /* argument not expected */ + else + arg->r_type = 0; + } + argc--; argv++; idx++; /* set to next one */ + } + else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */ + int dash_kludge = 0; + i = 0; + if( !arg->internal.inarg ) { + arg->internal.inarg++; + if( arg->flags & (1<<5) ) { + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) { + dash_kludge=1; + break; + } + } + } + s += arg->internal.inarg; + + if( !dash_kludge ) { + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].short_opt == *s ) + break; + } + + if( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) ) + show_help(opts, arg->flags); + + arg->r_opt = opts[i].short_opt; + if( !opts[i].short_opt ) { + arg->r_opt = (opts[i].flags & 256)? -7:-2; + arg->internal.inarg++; /* point to the next arg */ + arg->r.ret_str = s; + } + else if( (opts[i].flags & 7) ) { + if( s[1] && !dash_kludge ) { + s2 = s+1; + set_opt_arg(arg, opts[i].flags, s2); + } + else { + s2 = argv[1]; + if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/ + arg->r_type = 0; /* because it is optional */ + } + else if( !s2 ) { + arg->r_opt = -3; /* missing argument */ + } + else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) { + /* the argument is optional and the next seems to be + * an option. We do not check this possible option + * but assume no argument */ + arg->r_type = 0; + } + else { + set_opt_arg(arg, opts[i].flags, s2); + argc--; argv++; idx++; /* skip one */ + } + } + s = "x"; /* so that !s[1] yields false */ + } + else { /* does not take an argument */ + arg->r_type = 0; + arg->internal.inarg++; /* point to the next arg */ + } + if( !s[1] || dash_kludge ) { /* no more concatenated short options */ + arg->internal.inarg = 0; + argc--; argv++; idx++; + } + } + else if( arg->flags & (1<<2) ) { + arg->r_opt = -1; /* not an option but a argument */ + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; idx++; /* set to next one */ + } + else { + arg->internal.stopped = 1; /* stop option processing */ + goto next_one; + } + + leave: + *arg->argc = argc; + *arg->argv = argv; + arg->internal.idx = idx; + return arg->r_opt; +} + + + +static int +set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s) +{ + int base = (flags & 16)? 0 : 10; + + switch( arg->r_type = (flags & 7) ) { + case 1: /* takes int argument */ + arg->r.ret_int = (int)strtol(s,NULL,base); + return 0; + case 3: /* takes long argument */ + arg->r.ret_long= strtol(s,NULL,base); + return 0; + case 4: /* takes ulong argument */ + arg->r.ret_ulong= strtoul(s,NULL,base); + return 0; + case 2: /* takes string argument */ + default: + arg->r.ret_str = s; + return 1; + } +} + + +static size_t +long_opt_strlen( ARGPARSE_OPTS *o ) +{ + size_t n = strlen(o->long_opt); + + if( o->description && *o->description == '|' ) { + const char *s; + + s=o->description+1; + if( *s != '=' ) + n++; + for(; *s && *s != '|'; s++ ) + n++; + } + return n; +} + +/**************** + * Print formatted help. The description string has some special + * meanings: + * - A description string which is "@" suppresses help output for + * this option + * - a description,ine which starts with a '@' and is followed by + * any other characters is printed as is; this may be used for examples + * ans such. + * - A description which starts with a '|' outputs the string between this + * bar and the next one as arguments of the long option. + */ +static void +show_help( ARGPARSE_OPTS *opts, unsigned flags ) +{ + const char *s; + + show_version(); + putchar('\n'); + s = strusage(41); + puts(s); + if( opts[0].description ) { /* auto format the option description */ + int i,j, indent; + /* get max. length of long options */ + for(i=indent=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt ) + if( !opts[i].description || *opts[i].description != '@' ) + if( (j=long_opt_strlen(opts+i)) > indent && j < 35 ) + indent = j; + } + /* example: " -v, --verbose Viele Sachen ausgeben" */ + indent += 10; + if( *opts[0].description != '@' ) + puts("Options:"); + for(i=0; opts[i].short_opt; i++ ) { + s = _( opts[i].description ); + if( s && *s== '@' && !s[1] ) /* hide this line */ + continue; + if( s && *s == '@' ) { /* unindented comment only line */ + for(s++; *s; s++ ) { + if( *s == '\n' ) { + if( s[1] ) + putchar('\n'); + } + else + putchar(*s); + } + putchar('\n'); + continue; + } + + j = 3; + if( opts[i].short_opt < 256 ) { + printf(" -%c", opts[i].short_opt ); + if( !opts[i].long_opt ) { + if(s && *s == '|' ) { + putchar(' '); j++; + for(s++ ; *s && *s != '|'; s++, j++ ) + putchar(*s); + if( *s ) + s++; + } + } + } + else + fputs(" ", stdout); + if( opts[i].long_opt ) { + j += printf("%c --%s", opts[i].short_opt < 256?',':' ', + opts[i].long_opt ); + if(s && *s == '|' ) { + if( *++s != '=' ) { + putchar(' '); + j++; + } + for( ; *s && *s != '|'; s++, j++ ) + putchar(*s); + if( *s ) + s++; + } + fputs(" ", stdout); + j += 3; + } + for(;j < indent; j++ ) + putchar(' '); + if( s ) { + if( *s && j > indent ) { + putchar('\n'); + for(j=0;j < indent; j++ ) + putchar(' '); + } + for(; *s; s++ ) { + if( *s == '\n' ) { + if( s[1] ) { + putchar('\n'); + for(j=0;j < indent; j++ ) + putchar(' '); + } + } + else + putchar(*s); + } + } + putchar('\n'); + } + if( flags & 32 ) + puts("\n(A single dash may be used instead of the double ones)"); + } + if( (s=strusage(19)) ) { /* bug reports to ... */ + putchar('\n'); + fputs(s, stdout); + } + fflush(stdout); + exit(0); +} + +static void +show_version() +{ + const char *s; + int i; + /* version line */ + fputs(strusage(11), stdout); + if( (s=strusage(12)) ) + printf(" (%s)", s ); + printf(" %s\n", strusage(13) ); + /* additional version lines */ + for(i=20; i < 30; i++ ) + if( (s=strusage(i)) ) + printf("%s\n", s ); + /* copyright string */ + if( (s=strusage(14)) ) + printf("%s\n", s ); + /* copying conditions */ + if( (s=strusage(15)) ) + fputs(s, stdout); + /* thanks */ + if( (s=strusage(18)) ) + fputs(s, stdout); + /* additional program info */ + for(i=30; i < 40; i++ ) + if( (s=strusage(i)) ) + fputs( (const byte*)s, stdout); + fflush(stdout); +} + + +void +usage( int level ) +{ + if( !level ) { + fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13), + strusage(14) ); + fflush(stderr); + } + else if( level == 1 ) { + fputs(strusage(40),stderr); + exit(2); + } + else if( level == 2 ) { + puts(strusage(41)); + exit(0); + } +} + +/* Level + * 0: Copyright String auf stderr ausgeben + * 1: Kurzusage auf stderr ausgeben und beenden + * 2: Langusage auf stdout ausgeben und beenden + * 11: name of program + * 12: optional name of package which includes this program. + * 13: version string + * 14: copyright string + * 15: Short copying conditions (with LFs) + * 16: Long copying conditions (with LFs) + * 17: Optional printable OS name + * 18: Optional thanks list (with LFs) + * 19: Bug report info + *20..29: Additional lib version strings. + *30..39: Additional program info (with LFs) + * 40: short usage note (with LF) + * 41: long usage note (with LF) + */ +const char * +strusage( int level ) +{ + const char *p = strusage_handler? strusage_handler(level) : NULL; + + if( p ) + return p; + + switch( level ) { + case 11: p = "foo"; break; + case 13: p = "0.0"; break; + case 14: p = "Copyright (C) 2000 Free Software Foundation, Inc."; break; + case 15: p = +"This program comes with ABSOLUTELY NO WARRANTY.\n" +"This is free software, and you are welcome to redistribute it\n" +"under certain conditions. See the file COPYING for details.\n"; break; + case 16: p = +"This is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 2 of the License, or\n" +"(at your option) any later version.\n\n" +"It is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"; + break; + case 40: /* short and long usage */ + case 41: p = ""; break; + } + + return p; +} + +void +set_strusage( const char *(*f)( int ) ) +{ + strusage_handler = f; +} + + +#ifdef TEST +static struct { + int verbose; + int debug; + char *outfile; + char *crf; + int myopt; + int echo; + int a_long_one; +}opt; + +int +main(int argc, char **argv) +{ + ARGPARSE_OPTS opts[] = { + { 'v', "verbose", 0 , "Laut sein"}, + { 'e', "echo" , 0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"}, + { 'd', "debug", 0 , "Debug\nfalls mal etasws\nSchief geht"}, + { 'o', "output", 2 }, + { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" }, + { 'm', "my-option", 1|8 }, + { 500, "a-long-option", 0 }, + {0} }; + ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 }; + int i; + + while( ArgParse( &pargs, opts) ) { + switch( pargs.r_opt ) { + case -1 : printf( "arg=`%s'\n", pargs.r.ret_str); break; + case 'v': opt.verbose++; break; + case 'e': opt.echo++; break; + case 'd': opt.debug++; break; + case 'o': opt.outfile = pargs.r.ret_str; break; + case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + case 500: opt.a_long_one++; break; + default : pargs.err = 1; break; /* force warning output */ + } + } + for(i=0; i < argc; i++ ) + printf("%3d -> (%s)\n", i, argv[i] ); + puts("Options:"); + if( opt.verbose ) + printf(" verbose=%d\n", opt.verbose ); + if( opt.debug ) + printf(" debug=%d\n", opt.debug ); + if( opt.outfile ) + printf(" outfile=`%s'\n", opt.outfile ); + if( opt.crf ) + printf(" crffile=`%s'\n", opt.crf ); + if( opt.myopt ) + printf(" myopt=%d\n", opt.myopt ); + if( opt.a_long_one ) + printf(" a-long-one=%d\n", opt.a_long_one ); + if( opt.echo ) + printf(" echo=%d\n", opt.echo ); + return 0; +} +#endif + +/**** bottom of file ****/ diff --git a/tags/GPGME-0-1-3/jnlib/argparse.h b/tags/GPGME-0-1-3/jnlib/argparse.h new file mode 100644 index 0000000..3668a21 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/argparse.h @@ -0,0 +1,67 @@ +/* argparse.h + * Copyright (C) 1998,1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 LIBJNLIB_ARGPARSE_H +#define LIBJNLIB_ARGPARSE_H + +#include +#include "types.h" + +typedef struct { + int *argc; /* pointer to argc (value subject to change) */ + char ***argv; /* pointer to argv (value subject to change) */ + unsigned flags; /* Global flags (DO NOT CHANGE) */ + int err; /* print error about last option */ + /* 1 = warning, 2 = abort */ + int r_opt; /* return option */ + int r_type; /* type of return value (0 = no argument found)*/ + union { + int ret_int; + long ret_long; + unsigned long ret_ulong; + char *ret_str; + } r; /* Return values */ + struct { + int idx; + int inarg; + int stopped; + const char *last; + void *aliases; + const void *cur_alias; + } internal; /* DO NOT CHANGE */ +} ARGPARSE_ARGS; + +typedef struct { + int short_opt; + const char *long_opt; + unsigned flags; + const char *description; /* optional option description */ +} ARGPARSE_OPTS; + + + +int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +int optfile_parse( FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +void usage( int level ); +const char *strusage( int level ); +void set_strusage( const char *(*f)( int ) ); + +#endif /*LIBJNLIB_ARGPARSE_H*/ diff --git a/tags/GPGME-0-1-3/jnlib/dotlock.c b/tags/GPGME-0-1-3/jnlib/dotlock.c new file mode 100644 index 0000000..8e61f7a --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/dotlock.c @@ -0,0 +1,346 @@ +/* dotlock.c - dotfile locking + * Copyright (C) 1998,2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 +#ifndef HAVE_DOSISH_SYSTEM +#include +#endif +#include +#include +#include +#include +#include + +#include "libjnlib-config.h" +#include "dotlock.h" + +struct dotlock_handle { + struct dotlock_handle *next; + char *tname; /* name of lockfile template */ + char *lockname; /* name of the real lockfile */ + int locked; /* lock status */ +}; + + +static DOTLOCK all_lockfiles; + +static int read_lockfile( const char *name ); +static void remove_lockfiles(void); + +/**************** + * Create a lockfile with the given name and return an object of + * type DOTLOCK which may be used later to actually do the lock. + * A cleanup routine gets installed to cleanup left over locks + * or other files used together with the lockmechanism. + * Althoug the function is called dotlock, this does not necessarily + * mean that real lockfiles are used - the function may decide to + * use fcntl locking. Calling the function with NULL only install + * the atexit handler and maybe used to assure that the cleanup + * is called after all other atexit handlers. + * + * Notes: This function creates a lock file in the same directory + * as file_to_lock with the name "file_to_lock.lock" + * A temporary file ".#lk..pid[.threadid] is used. + * This function does nothing for Windoze. + */ +DOTLOCK +create_dotlock( const char *file_to_lock ) +{ + static int initialized; + DOTLOCK h; + int fd = -1; + char pidstr[16]; + #ifndef HAVE_DOSISH_SYSTEM + struct utsname utsbuf; + #endif + const char *nodename; + const char *dirpart; + int dirpartlen; + + if( !initialized ) { + atexit( remove_lockfiles ); + initialized = 1; + } + if( !file_to_lock ) + return NULL; + + h = jnlib_xcalloc( 1, sizeof *h ); +#ifndef HAVE_DOSISH_SYSTEM + sprintf( pidstr, "%10d\n", (int)getpid() ); + /* fixme: add the hostname to the second line (FQDN or IP addr?) */ + + /* create a temporary file */ + if( uname( &utsbuf ) ) + nodename = "unknown"; + else + nodename = utsbuf.nodename; + + if( !(dirpart = strrchr( file_to_lock, '/' )) ) { + dirpart = "."; + dirpartlen = 1; + } + else { + dirpartlen = dirpart - file_to_lock; + dirpart = file_to_lock; + } + + #ifdef _REENTRANT + /* fixme: aquire mutex on all_lockfiles */ + #endif + h->next = all_lockfiles; + all_lockfiles = h; + + h->tname = jnlib_xmalloc( dirpartlen + 6+30+ strlen(nodename) + 11 ); + sprintf( h->tname, "%.*s/.#lk%p.%s.%d", + dirpartlen, dirpart, h, nodename, (int)getpid() ); + + do { + errno = 0; + fd = open( h->tname, O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR ); + } while( fd == -1 && errno == EINTR ); + if( fd == -1 ) { + all_lockfiles = h->next; + log_error( "failed to create temporary file `%s': %s\n", + h->tname, strerror(errno)); + jnlib_free(h->tname); + jnlib_free(h); + return NULL; + } + if( write(fd, pidstr, 11 ) != 11 ) { + all_lockfiles = h->next; + #ifdef _REENTRANT + /* release mutex */ + #endif + log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) ); + close(fd); + unlink(h->tname); + jnlib_free(h->tname); + jnlib_free(h); + return NULL; + } + if( close(fd) ) { + all_lockfiles = h->next; + #ifdef _REENTRANT + /* release mutex */ + #endif + log_error( "error closing `%s': %s\n", h->tname, strerror(errno)); + unlink(h->tname); + jnlib_free(h->tname); + jnlib_free(h); + return NULL; + } + + #ifdef _REENTRANT + /* release mutex */ + #endif +#endif /* !HAVE_DOSISH_SYSTEM */ + h->lockname = jnlib_xmalloc( strlen(file_to_lock) + 6 ); + strcpy(stpcpy(h->lockname, file_to_lock), ".lock"); + return h; +} + +static int +maybe_deadlock( DOTLOCK h ) +{ + DOTLOCK r; + + for( r=all_lockfiles; r; r = r->next ) { + if( r != h && r->locked ) + return 1; + } + return 0; +} + +/**************** + * Do a lock on H. A TIMEOUT of 0 returns immediately, + * -1 waits forever (hopefully not), other + * values are timeouts in milliseconds. + * Returns: 0 on success + */ +int +make_dotlock( DOTLOCK h, long timeout ) +{ +#ifdef HAVE_DOSISH_SYSTEM + return 0; +#else + int pid; + const char *maybe_dead=""; + int backoff=0; + + if( h->locked ) { + log_debug("oops, `%s' is already locked\n", h->lockname ); + return 0; + } + + for(;;) { + if( !link(h->tname, h->lockname) ) { + /* fixme: better use stat to check the link count */ + h->locked = 1; + return 0; /* okay */ + } + if( errno != EEXIST ) { + log_error( "lock not made: link() failed: %s\n", strerror(errno) ); + return -1; + } + if( (pid = read_lockfile(h->lockname)) == -1 ) { + if( errno != ENOENT ) { + log_info("cannot read lockfile\n"); + return -1; + } + log_info( "lockfile disappeared\n"); + continue; + } + else if( pid == getpid() ) { + log_info( "Oops: lock already hold by us\n"); + h->locked = 1; + return 0; /* okay */ + } + else if( kill(pid, 0) && errno == ESRCH ) { + maybe_dead = " - probably dead"; + #if 0 /* we should not do this without checking the permissions */ + /* and the hostname */ + log_info( "removing stale lockfile (created by %d)", pid ); + #endif + } + if( timeout == -1 ) { + struct timeval tv; + log_info( "waiting for lock (hold by %d%s) %s...\n", + pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":""); + + + /* can't use sleep, cause signals may be blocked */ + tv.tv_sec = 1 + backoff; + tv.tv_usec = 0; + select(0, NULL, NULL, NULL, &tv); + if( backoff < 10 ) + backoff++ ; + } + else + return -1; + } + /*not reached */ +#endif /* !HAVE_DOSISH_SYSTEM */ +} + + +/**************** + * release a lock + * Returns: 0 := success + */ +int +release_dotlock( DOTLOCK h ) +{ +#ifdef HAVE_DOSISH_SYSTEM + return 0; +#else + int pid; + + if( !h->locked ) { + log_debug("oops, `%s' is not locked\n", h->lockname ); + return 0; + } + + pid = read_lockfile( h->lockname ); + if( pid == -1 ) { + log_error( "release_dotlock: lockfile error\n"); + return -1; + } + if( pid != getpid() ) { + log_error( "release_dotlock: not our lock (pid=%d)\n", pid); + return -1; + } + if( unlink( h->lockname ) ) { + log_error( "release_dotlock: error removing lockfile `%s'", + h->lockname); + return -1; + } + /* fixme: check that the link count is now 1 */ + h->locked = 0; + return 0; +#endif /* !HAVE_DOSISH_SYSTEM */ +} + + +/**************** + * Read the lock file and return the pid, returns -1 on error. + */ +static int +read_lockfile( const char *name ) +{ + #ifdef HAVE_DOSISH_SYSTEM + return 0; + #else + int fd, pid; + char pidstr[16]; + + if( (fd = open(name, O_RDONLY)) == -1 ) { + int e = errno; + log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) ); + errno = e; + return -1; + } + if( read(fd, pidstr, 10 ) != 10 ) { /* Read 10 digits w/o newline */ + log_debug("error reading lockfile `%s'", name ); + close(fd); + errno = 0; + return -1; + } + pidstr[10] = 0; /* terminate pid string */ + close(fd); + pid = atoi(pidstr); + if( !pid || pid == -1 ) { + log_error("invalid pid %d in lockfile `%s'", pid, name ); + errno = 0; + return -1; + } + return pid; + #endif +} + + +static void +remove_lockfiles() +{ + #ifndef HAVE_DOSISH_SYSTEM + DOTLOCK h, h2; + + h = all_lockfiles; + all_lockfiles = NULL; + + while( h ) { + h2 = h->next; + if( h->locked ) + unlink( h->lockname ); + unlink(h->tname); + jnlib_free(h->tname); + jnlib_free(h->lockname); + jnlib_free(h); + h = h2; + } + #endif +} + diff --git a/tags/GPGME-0-1-3/jnlib/dotlock.h b/tags/GPGME-0-1-3/jnlib/dotlock.h new file mode 100644 index 0000000..d54219e --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/dotlock.h @@ -0,0 +1,32 @@ +/* dotlock.h + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 LIBJNLIB_DOTLOCK_H +#define LIBJNLIB_DOTLOCK_H + +struct dotlock_handle; +typedef struct dotlock_handle *DOTLOCK; + +DOTLOCK create_dotlock( const char *file_to_lock ); +int make_dotlock( DOTLOCK h, long timeout ); +int release_dotlock( DOTLOCK h ); + + +#endif /*LIBJNLIB_DOTLOCK_H*/ diff --git a/tags/GPGME-0-1-3/jnlib/libjnlib-config.h b/tags/GPGME-0-1-3/jnlib/libjnlib-config.h new file mode 100644 index 0000000..4cc57b2 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/libjnlib-config.h @@ -0,0 +1,75 @@ +/* libjnlib-config.h - local configuration of the jnlib functions + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 + */ + +/**************** + * This header is to be included only by the files in this directory + * it should not be used by other modules. + */ + +#ifndef LIBJNLIB_CONFIG_H +#define LIBJNLIB_CONFIG_H + +#include "xmalloc.h" +#include "logging.h" + + + +#ifdef USE_SIMPLE_GETTEXT + int set_gettext_file( const char *filename ); + const char *gettext( const char *msgid ); + + #define _(a) gettext (a) + #define N_(a) (a) + +#else +#ifdef HAVE_LOCALE_H + #include +#endif + +#ifdef ENABLE_NLS + #include + #define _(a) gettext (a) + #ifdef gettext_noop + #define N_(a) gettext_noop (a) + #else + #define N_(a) (a) + #endif +#else + #define _(a) (a) + #define N_(a) (a) +#endif +#endif /* !USE_SIMPLE_GETTEXT */ + + +#define jnlib_xmalloc(a) xmalloc( (a) ) +#define jnlib_xcalloc(a,b) xcalloc( (a), (b) ) +#define jnlib_xrealloc(a,n) xrealloc( (a), (n) ) +#define jnlib_xstrdup(a) xstrdup( (a) ) +#define jnlib_free(a) free( (a) ) + +#define jnlib_log_debug log_debug +#define jnlib_log_info log_info +#define jnlib_log_error log_error +#define jnlib_log_fatal log_fatal +#define jnlib_log_bug log_bug + + +#endif /*LIBJNUTIL_CONFIG_H*/ + diff --git a/tags/GPGME-0-1-3/jnlib/logging.c b/tags/GPGME-0-1-3/jnlib/logging.c new file mode 100644 index 0000000..7ab2cb5 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/logging.c @@ -0,0 +1,257 @@ +/* logging.c - useful logging functions + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 + */ + + +/* This file should replace logger.c in the future - for now it is not + * used by GnuPG but by GPA. + * It is a quite simple implemenation but sufficient for most purposes. + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef __MINGW32__ + #include +#endif + +#include "libjnlib-config.h" +#include "logging.h" + +enum my_log_levels { + MY_LOG_BEGIN, /* only print the timestamp if configured */ + MY_LOG_CONT, + MY_LOG_INFO, + MY_LOG_WARN, + MY_LOG_ERROR, + MY_LOG_FATAL, + MY_LOG_BUG, + MY_LOG_DEBUG +}; + +static FILE *logstream; +static int use_time; +static int missing_lf; +static int errorcount; + +#if 0 +static void +write2stderr( const char *s ) +{ + write( 2, s, strlen(s) ); +} + + +static void +do_die(int rc, const char *text ) +{ + write2stderr("\nFatal error: "); + write2stderr(text); + write2stderr("\n"); + abort(); +} +#endif + +int +log_get_errorcount (int clear) +{ + int n = errorcount; + if( clear ) + errorcount = 0; + return n; +} + +void +log_set_file( const char *name ) +{ + FILE *fp = (name && strcmp(name,"-"))? fopen(name, "a") : stderr; + if( !fp ) { + fprintf(stderr, "failed to open log file `%s': %s\n", + name, strerror(errno)); + return; + } + setvbuf( fp, NULL, _IOLBF, 0 ); + + if( logstream && logstream != stderr ) + fclose( logstream ); + logstream = fp; + use_time = fp != stderr; + missing_lf = 0; +} + + +int +log_get_fd() +{ + return fileno(logstream?logstream:stderr); +} + +static void +do_logv( int level, const char *fmt, va_list arg_ptr ) +{ + if( !logstream ) + logstream = stderr; + + if( missing_lf && level != MY_LOG_CONT ) + putc('\n', logstream ); + missing_lf = 0; + + if( use_time && level != MY_LOG_CONT ) { + /* Note this does not work for multiple line logging as we would + * need to print to a buffer first */ + struct tm *tp; + time_t atime = time(NULL); + + tp = localtime( &atime ); + fprintf( logstream, "%04d-%02d-%02d %02d:%02d:%02d ", + 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec ); + } + + switch ( level ) { + case MY_LOG_BEGIN: break; + case MY_LOG_CONT: break; + case MY_LOG_INFO: break; + case MY_LOG_WARN: break; + case MY_LOG_ERROR: break; + case MY_LOG_FATAL: fputs("Fatal: ",logstream ); break; + case MY_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break; + case MY_LOG_DEBUG: fputs("DBG: ", logstream ); break; + default: fprintf(logstream,"[Unknown log level %d]: ", level ); break; + } + + if( fmt ) { + vfprintf(logstream,fmt,arg_ptr) ; + if( *fmt && fmt[strlen(fmt)-1] != '\n' ) + missing_lf = 1; + } + + if( level == MY_LOG_FATAL ) + exit(2); + if( level == MY_LOG_BUG ) + abort(); +} + +static void +do_log( int level, const char *fmt, ... ) +{ + va_list arg_ptr ; + + va_start( arg_ptr, fmt ) ; + do_logv( level, fmt, arg_ptr ); + va_end(arg_ptr); +} + + + +void +log_info( const char *fmt, ... ) +{ + va_list arg_ptr ; + + va_start( arg_ptr, fmt ) ; + do_logv( MY_LOG_INFO, fmt, arg_ptr ); + va_end(arg_ptr); +} + +void +log_error( const char *fmt, ... ) +{ + va_list arg_ptr ; + + va_start( arg_ptr, fmt ) ; + do_logv( MY_LOG_ERROR, fmt, arg_ptr ); + va_end(arg_ptr); + /* protect against counter overflow */ + if( errorcount < 30000 ) + errorcount++; +} + + +void +log_fatal( const char *fmt, ... ) +{ + va_list arg_ptr ; + + va_start( arg_ptr, fmt ) ; + do_logv( MY_LOG_FATAL, fmt, arg_ptr ); + va_end(arg_ptr); + abort(); /* never called, bugs it makes the compiler happy */ +} + +void +log_bug( const char *fmt, ... ) +{ + va_list arg_ptr ; + + va_start( arg_ptr, fmt ) ; + do_logv( MY_LOG_BUG, fmt, arg_ptr ); + va_end(arg_ptr); + abort(); /* never called, but it makes the compiler happy */ +} + +void +log_debug( const char *fmt, ... ) +{ + va_list arg_ptr ; + + va_start( arg_ptr, fmt ) ; + do_logv( MY_LOG_DEBUG, fmt, arg_ptr ); + va_end(arg_ptr); +} + + +void +log_printf( const char *fmt, ... ) +{ + va_list arg_ptr ; + + if( !fmt ) { + do_logv( MY_LOG_BEGIN, NULL, NULL ); + } + else { + va_start( arg_ptr, fmt ) ; + do_logv( MY_LOG_CONT, fmt, arg_ptr ); + va_end(arg_ptr); + } +} + + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) +void +bug_at( const char *file, int line, const char *func ) +{ + do_log( MY_LOG_BUG, + ("... this is a bug (%s:%d:%s)\n"), file, line, func ); + abort(); /* never called, but it makes the compiler happy */ +} +#else +void +bug_at( const char *file, int line ) +{ + do_log( MY_LOG_BUG, + _("you found a bug ... (%s:%d)\n"), file, line); + abort(); /* never called, but it makes the compiler happy */ +} +#endif + diff --git a/tags/GPGME-0-1-3/jnlib/logging.h b/tags/GPGME-0-1-3/jnlib/logging.h new file mode 100644 index 0000000..5084b71 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/logging.h @@ -0,0 +1,47 @@ +/* logging.h + * Copyright (C) 1999, 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 LIBJNLIB_LOGGING_H +#define LIBJNLIB_LOGGING_H + +#include +#include "mischelp.h" + +int log_get_errorcount (int clear); +void log_set_file( const char *name ); +int log_get_fd(void); + +#ifdef JNLIB_GCC_M_FUNCTION + void bug_at( const char *file, int line, const char *func ) JNLIB_GCC_A_NR; +# define BUG() bug_at( __FILE__ , __LINE__, __FUNCTION__ ) +#else + void bug_at( const char *file, int line ); +# define BUG() bug_at( __FILE__ , __LINE__ ) +#endif + +void log_bug( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2); +void log_fatal( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2); +void log_error( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); +void log_info( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); +void log_debug( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); +void log_printf( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); + + +#endif /*LIBJNLIB_LOGGING_H*/ diff --git a/tags/GPGME-0-1-3/jnlib/mischelp.h b/tags/GPGME-0-1-3/jnlib/mischelp.h new file mode 100644 index 0000000..684a697 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/mischelp.h @@ -0,0 +1,43 @@ +/* mischelp.h + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 LIBJNLIB_MISCHELP_H +#define LIBJNLIB_MISCHHELP_H + + +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) +# define JNLIB_GCC_M_FUNCTION 1 +# define JNLIB_GCC_A_NR __attribute__ ((noreturn)) +# define JNLIB_GCC_A_PRINTF( f, a ) __attribute__ ((format (printf,f,a))) +# define JNLIB_GCC_A_NR_PRINTF( f, a ) \ + __attribute__ ((noreturn, format (printf,f,a))) +#else +# define JNLIB_GCC_A_NR +# define JNLIB_GCC_A_PRINTF( f, a ) +# define JNLIB_GCC_A_NR_PRINTF( f, a ) +#endif + + + +#endif /*LIBJNLIB_MISCHELP_H*/ diff --git a/tags/GPGME-0-1-3/jnlib/stringhelp.c b/tags/GPGME-0-1-3/jnlib/stringhelp.c new file mode 100644 index 0000000..59345f2 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/stringhelp.c @@ -0,0 +1,323 @@ +/* stringhelp.c - standard string helper functions + * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 "libjnlib-config.h" +#include "stringhelp.h" + + +/**************** + * look for the substring SUB in buffer and return a pointer to that + * substring in BUF or NULL if not found. + * Comparison is case-insensitive. + */ +const char * +memistr( const char *buf, size_t buflen, const char *sub ) +{ + const byte *t, *s ; + size_t n; + + for( t=buf, n=buflen, s=sub ; n ; t++, n-- ) + if( toupper(*t) == toupper(*s) ) { + for( buf=t++, buflen = n--, s++; + n && toupper(*t) == toupper(*s); t++, s++, n-- ) + ; + if( !*s ) + return buf; + t = buf; n = buflen; s = sub ; + } + + return NULL ; +} + +/**************** + * Wie strncpy(), aber es werden maximal n-1 zeichen kopiert und ein + * '\0' angehängt. Ist n = 0, so geschieht nichts, ist Destination + * gleich NULL, so wird via jnlib_xmalloc Speicher besorgt, ist dann nicht + * genügend Speicher vorhanden, so bricht die funktion ab. + */ +char * +mem2str( char *dest , const void *src , size_t n ) +{ + char *d; + const char *s; + + if( n ) { + if( !dest ) + dest = jnlib_xmalloc( n ) ; + d = dest; + s = src ; + for(n--; n && *s; n-- ) + *d++ = *s++; + *d = '\0' ; + } + + return dest ; +} + + +/**************** + * remove leading and trailing white spaces + */ +char * +trim_spaces( char *str ) +{ + char *string, *p, *mark; + + string = str; + /* find first non space character */ + for( p=string; *p && isspace( *(byte*)p ) ; p++ ) + ; + /* move characters */ + for( (mark = NULL); (*string = *p); string++, p++ ) + if( isspace( *(byte*)p ) ) { + if( !mark ) + mark = string ; + } + else + mark = NULL ; + if( mark ) + *mark = '\0' ; /* remove trailing spaces */ + + return str ; +} + +/**************** + * remove trailing white spaces + */ +char * +trim_trailing_spaces( char *string ) +{ + char *p, *mark; + + for( mark = NULL, p = string; *p; p++ ) { + if( isspace( *(byte*)p ) ) { + if( !mark ) + mark = p; + } + else + mark = NULL; + } + if( mark ) + *mark = '\0' ; + + return string ; +} + + + +unsigned +trim_trailing_chars( byte *line, unsigned len, const char *trimchars ) +{ + byte *p, *mark; + unsigned n; + + for(mark=NULL, p=line, n=0; n < len; n++, p++ ) { + if( strchr(trimchars, *p ) ) { + if( !mark ) + mark = p; + } + else + mark = NULL; + } + + if( mark ) { + *mark = 0; + return mark - line; + } + return len; +} + +/**************** + * remove trailing white spaces and return the length of the buffer + */ +unsigned +trim_trailing_ws( byte *line, unsigned len ) +{ + return trim_trailing_chars( line, len, " \t\r\n" ); +} + + +/*************** + * Extract from a given path the filename component. + * + */ +char * +make_basename(const char *filepath) +{ + char *p; + + if ( !(p=strrchr(filepath, '/')) ) + #ifdef HAVE_DRIVE_LETTERS + if ( !(p=strrchr(filepath, '\\')) ) + if ( !(p=strrchr(filepath, ':')) ) + #endif + { + return jnlib_xstrdup(filepath); + } + + return jnlib_xstrdup(p+1); +} + + + +/*************** + * Extract from a given filename the path prepended to it. + * If their isn't a path prepended to the filename, a dot + * is returned ('.'). + * + */ +char * +make_dirname(const char *filepath) +{ + char *dirname; + int dirname_length; + char *p; + + if ( !(p=strrchr(filepath, '/')) ) + #ifdef HAVE_DRIVE_LETTERS + if ( !(p=strrchr(filepath, '\\')) ) + if ( !(p=strrchr(filepath, ':')) ) + #endif + { + return jnlib_xstrdup("."); + } + + dirname_length = p-filepath; + dirname = jnlib_xmalloc(dirname_length+1); + strncpy(dirname, filepath, dirname_length); + dirname[dirname_length] = 0; + + return dirname; +} + + + +/**************** + * Construct a filename from the NULL terminated list of parts. + * Tilde expansion is done here. + */ +char * +make_filename( const char *first_part, ... ) +{ + va_list arg_ptr ; + size_t n; + const char *s; + char *name, *home, *p; + + va_start( arg_ptr, first_part ) ; + n = strlen(first_part)+1; + while( (s=va_arg(arg_ptr, const char *)) ) + n += strlen(s) + 1; + va_end(arg_ptr); + + home = NULL; + if( *first_part == '~' && first_part[1] == '/' + && (home = getenv("HOME")) && *home ) + n += strlen(home); + + name = jnlib_xmalloc(n); + p = home ? stpcpy(stpcpy(name,home), first_part+1) + : stpcpy(name, first_part); + va_start( arg_ptr, first_part ) ; + while( (s=va_arg(arg_ptr, const char *)) ) + p = stpcpy(stpcpy(p,"/"), s); + va_end(arg_ptr); + + return name; +} + + +int +compare_filenames( const char *a, const char *b ) +{ + /* ? check whether this is an absolute filename and + * resolve symlinks? + */ + #ifdef HAVE_DRIVE_LETTERS + return stricmp(a,b); + #else + return strcmp(a,b); + #endif +} + + +/********************************************* + ********** missing string functions ********* + *********************************************/ + +#ifndef HAVE_STPCPY +char * +stpcpy(char *a,const char *b) +{ + while( *b ) + *a++ = *b++; + *a = 0; + + return (char*)a; +} +#endif + +#ifndef HAVE_STRLWR +char * +strlwr(char *s) +{ + char *p; + for(p=s; *p; p++ ) + *p = tolower(*p); + return s; +} +#endif + + +#ifndef HAVE_STRCASECMP +int +strcasecmp( const char *a, const char *b ) +{ + for( ; *a && *b; a++, b++ ) { + if( *a != *b && toupper(*a) != toupper(*b) ) + break; + } + return *(const byte*)a - *(const byte*)b; +} +#endif + + +/**************** + * mingw32/cpd has a memicmp() + */ +#ifndef HAVE_MEMICMP +int +memicmp( const char *a, const char *b, size_t n ) +{ + for( ; n; n--, a++, b++ ) + if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) ) + return *(const byte *)a - *(const byte*)b; + return 0; +} +#endif + + + diff --git a/tags/GPGME-0-1-3/jnlib/stringhelp.h b/tags/GPGME-0-1-3/jnlib/stringhelp.h new file mode 100644 index 0000000..ebdd7b2 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/stringhelp.h @@ -0,0 +1,65 @@ +/* stringhelp.h + * Copyright (C) 1998,1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 LIBJNLIB_STRINGHELP_H +#define LIBJNLIB_STRINGHELP_H + +#include "types.h" + +const char *memistr( const char *buf, size_t buflen, const char *sub ); +char *mem2str( char *, const void *, size_t); +char *trim_spaces( char *string ); +char *trim_trailing_spaces( char *string ); +unsigned int trim_trailing_chars( unsigned char *line, unsigned len, + const char *trimchars); +unsigned int trim_trailing_ws( unsigned char *line, unsigned len ); + + +char *make_basename(const char *filepath); +char *make_dirname(const char *filepath); +char *make_filename( const char *first_part, ... ); +int compare_filenames( const char *a, const char *b ); + +#ifndef HAVE_MEMICMP +int memicmp( const char *a, const char *b, size_t n ); +#endif +#ifndef HAVE_STPCPY +char *stpcpy(char *a,const char *b); +#endif +#ifndef HAVE_STRLWR +char *strlwr(char *a); +#endif +#ifndef HAVE_STRTOUL + #define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c))) +#endif +#ifndef HAVE_MEMMOVE + #define memmove(d, s, n) bcopy((s), (d), (n)) +#endif +#ifndef HAVE_STRICMP + #define stricmp(a,b) strcasecmp( (a), (b) ) +#endif + +#ifndef STR + #define STR(v) #v +#endif +#define STR2(v) STR(v) + + +#endif /*LIBJNLIB_STRINGHELP_H*/ diff --git a/tags/GPGME-0-1-3/jnlib/types.h b/tags/GPGME-0-1-3/jnlib/types.h new file mode 100644 index 0000000..a5d0e42 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/types.h @@ -0,0 +1,101 @@ +/* types.h + * Copyright (C) 1999, 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 LIBJNLIB_TYPES_H +#define LIBJNLIB_TYPES_H + +/* The AC_CHECK_SIZEOF() in configure fails for some machines. + * we provide some fallback values here */ +#if !SIZEOF_UNSIGNED_SHORT + #undef SIZEOF_UNSIGNED_SHORT + #define SIZEOF_UNSIGNED_SHORT 2 +#endif +#if !SIZEOF_UNSIGNED_INT + #undef SIZEOF_UNSIGNED_INT + #define SIZEOF_UNSIGNED_INT 4 +#endif +#if !SIZEOF_UNSIGNED_LONG + #undef SIZEOF_UNSIGNED_LONG + #define SIZEOF_UNSIGNED_LONG 4 +#endif + + +#include + + +#ifndef HAVE_BYTE_TYPEDEF + #undef byte /* maybe there is a macro with this name */ + typedef unsigned char byte; + #define HAVE_BYTE_TYPEDEF +#endif + +#ifndef HAVE_USHORT_TYPEDEF + #undef ushort /* maybe there is a macro with this name */ + typedef unsigned short ushort; + #define HAVE_USHORT_TYPEDEF +#endif + +#ifndef HAVE_ULONG_TYPEDEF + #undef ulong /* maybe there is a macro with this name */ + typedef unsigned long ulong; + #define HAVE_ULONG_TYPEDEF +#endif + +#ifndef HAVE_U16_TYPEDEF + #undef u16 /* maybe there is a macro with this name */ + #if SIZEOF_UNSIGNED_INT == 2 + typedef unsigned int u16; + #elif SIZEOF_UNSIGNED_SHORT == 2 + typedef unsigned short u16; + #else + #error no typedef for u16 + #endif + #define HAVE_U16_TYPEDEF +#endif + +#ifndef HAVE_U32_TYPEDEF + #undef u32 /* maybe there is a macro with this name */ + #if SIZEOF_UNSIGNED_INT == 4 + typedef unsigned int u32; + #elif SIZEOF_UNSIGNED_LONG == 4 + typedef unsigned long u32; + #else + #error no typedef for u32 + #endif + #define HAVE_U32_TYPEDEF +#endif + +#ifndef HAVE_U64_TYPEDEF + #undef u64 /* maybe there is a macro with this name */ + #if SIZEOF_UNSIGNED_INT == 8 + typedef unsigned int u64; + #define HAVE_U64_TYPEDEF + #elif SIZEOF_UNSIGNED_LONG == 8 + typedef unsigned long u64; + #define HAVE_U64_TYPEDEF + #elif __GNUC__ >= 2 || defined(__SUNPRO_C) + typedef unsigned long long u64; + #define HAVE_U64_TYPEDEF + #endif +#endif + + + +#endif /*LIBJNLIB_TYPES_H*/ diff --git a/tags/GPGME-0-1-3/jnlib/xmalloc.c b/tags/GPGME-0-1-3/jnlib/xmalloc.c new file mode 100644 index 0000000..34ecc28 --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/xmalloc.c @@ -0,0 +1,88 @@ +/* xmalloc.c - standard malloc wrappers + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 "libjnlib-config.h" +#include "xmalloc.h" + +static void +out_of_core(void) +{ + fputs("\nfatal: out of memory\n", stderr ); + exit(2); +} + + +void * +xmalloc( size_t n ) +{ + void *p = malloc( n ); + if( !p ) + out_of_core(); + return p; +} + +void * +xrealloc( void *a, size_t n ) +{ + void *p = realloc( a, n ); + if( !p ) + out_of_core(); + return p; +} + +void * +xcalloc( size_t n, size_t m ) +{ + void *p = calloc( n, m ); + if( !p ) + out_of_core(); + return p; +} + +char * +xstrdup( const char *string ) +{ + void *p = xmalloc( strlen(string)+1 ); + strcpy( p, string ); + return p; +} + + +char * +xstrcat2( const char *a, const char *b ) +{ + size_t n1; + char *p; + + if( !b ) + return xstrdup( a ); + + n1 = strlen(a); + p = xmalloc( n1 + strlen(b) + 1 ); + memcpy(p, a, n1 ); + strcpy(p+n1, b ); + return p; +} + diff --git a/tags/GPGME-0-1-3/jnlib/xmalloc.h b/tags/GPGME-0-1-3/jnlib/xmalloc.h new file mode 100644 index 0000000..4dd88ec --- /dev/null +++ b/tags/GPGME-0-1-3/jnlib/xmalloc.h @@ -0,0 +1,31 @@ +/* xmalloc.h + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 LIBJNLIB_XMALLOC_H +#define LIBJNLIB_XMALLOC_H + +void *xmalloc( size_t n ); +void *xrealloc( void *a, size_t n ); +void *xcalloc( size_t n, size_t m ); +char *xstrdup( const char *string ); +char *xstrcat2( const char *a, const char *b ); + + +#endif /*LIBJNLIB_XMALLOC_H*/ diff --git a/tags/GPGME-0-1-3/tests/Makefile.am b/tags/GPGME-0-1-3/tests/Makefile.am new file mode 100644 index 0000000..de7a045 --- /dev/null +++ b/tags/GPGME-0-1-3/tests/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to create Makefile.in + +TESTS_ENVIRONMENT = GNUPGHOME=. + +TESTS = t-encrypt t-sign t-decrypt t-verify t-keylist t-export t-import + + +EXTRA_DIST = mkdemodirs pubdemo.asc secdemo.asc cipher-1.asc geheim.txt \ + pubkey-1.asc seckey-1.asc + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl + +INCLUDES = +LDADD = ../gpgme/libgpgme.la + +# We don't run t-genkey in the test suite, because it taes too long +noinst_PROGRAMS = $(TESTS) t-genkey + +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 . --allow-secret-key-import --import Alpha/Secret.gpg Zulu/Secret.gpg + +./Alpha/Secret.gpg: secdemo.asc + srcdir=$(srcdir) $(srcdir)/mkdemodirs + + + + + + + diff --git a/tags/GPGME-0-1-3/tests/cipher-1.asc b/tags/GPGME-0-1-3/tests/cipher-1.asc new file mode 100644 index 0000000..f0a8ca4 --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/tests/geheim.txt b/tags/GPGME-0-1-3/tests/geheim.txt new file mode 100644 index 0000000..99a5478 --- /dev/null +++ b/tags/GPGME-0-1-3/tests/geheim.txt @@ -0,0 +1,2 @@ +Wenn Sie dies lesen können, ist es wohl nicht +geheim genug. diff --git a/tags/GPGME-0-1-3/tests/mkdemodirs b/tags/GPGME-0-1-3/tests/mkdemodirs new file mode 100755 index 0000000..28b7835 --- /dev/null +++ b/tags/GPGME-0-1-3/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 --allow-secret-key-import --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/GPGME-0-1-3/tests/pubkey-1.asc b/tags/GPGME-0-1-3/tests/pubkey-1.asc new file mode 100644 index 0000000..bed1da3 --- /dev/null +++ b/tags/GPGME-0-1-3/tests/pubkey-1.asc @@ -0,0 +1,26 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.4b (GNU/Linux) +Comment: For info see http://www.gnupg.org + +mQGiBDo41NoRBADSfQazKGYf8nokq6zUKH/6INtV6MypSzSGmX2XErnARkIIPPYj +cQRQ8zCbGV7ZU2ezVbzhFLUSJveE8PZUzzCrLp1O2NSyBTRcR5HVSXW95nJfY8eV +pOvZRAKul0BVLh81kYTsrfzaaCjh9VWNP26LoeN2r+PjZyktXe7gM3C4SwCgoTxK +WUVi9HoT2HCLY7p7oig5hEcEALdCJal0UYomX3nJapIVLVZg3vkidr1RICYMb2vz +58i17h8sxEtobD1vdIKNejulntaRAXs4n0tDYD9z7pRlwG1CLz1R9WxYzeOOqUDr +fnVXdmU8L/oVWABat8v1V7QQhjMMf+41fuzVwDMMGqjVPLhu4X6wp3A8uyM3YDnQ +VMN1A/4n2G5gHoOvjqxn8Ch5tBAdMGfO8gH4RjQOwzm2R1wPQss/yzUN1+tlMZGX +K2dQ2FCWC/hDUSNaEQRlI15wxxBNZ2RQwlzE2A8v113DpvyzOtv0QO95gJ1teCXC +7j/BN9asgHaBBc39JLO/TcpuI7Hf8PQ5VcP2F0UE3lczGhXbLLQ/Sm9lIFJhbmRv +bSBIYWNrZXIgKHRlc3Qga2V5IHdpdGggcGFzc3BocmFzZSAieCIpIDxqb2VAc2V0 +cS5vcmc+iFcEExECABcFAjo41NoFCwcKAwQDFQMCAxYCAQIXgAAKCRCvgiRPnNn9 +VXm9AJ0auCQID9AQ4ic48A05OI4tcvs24ACgjsLML1iIYUtrSP1o6QSIYdnTUZy5 +AQ0EOjjU3RAEAJ50lvtCGbnQlI97VX6tJkosdPmdzeXaTWfv//A2wmSANbYnuych +GMa1LN43Ew+H6FXMWJ3MB/exs6UBFCgGsw88qmcla2bosQN/aVLA7fqXT9ujqoNG +aIVEmgdbK1MkSPFXBFyVW3hteod83D0UqFlltwp4A3ageCYFVJTp50d3AAMFA/44 +YCQQbg9x9JvzHX3VH7CRX+raEDkDL3Pbz0PHas7bwI7gzZ+GFyNKaCvrHQOyuR8R +IKIbjtQYnXr1675ConCTceIXhysY32sTn5V6UFUW2t0xaRfas8sZBbLDyIJkpt4f +yD+6OaRoui9KZqXMNwt7i/XFIto/sWd/OK3SIgZkAYhGBBgRAgAGBQI6ONTdAAoJ +EK+CJE+c2f1VVJoAn36uPWUhCdGXbSLxGibYfBt7et71AJ9JgWeRlTDTIoXYN8J+ +qsPN0YCxtg== +=4+Yp +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tags/GPGME-0-1-3/tests/seckey-1.asc b/tags/GPGME-0-1-3/tests/seckey-1.asc new file mode 100644 index 0000000..3934804 --- /dev/null +++ b/tags/GPGME-0-1-3/tests/seckey-1.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.0.4b (GNU/Linux) +Comment: For info see http://www.gnupg.org + +lQHPBDo41NoRBADSfQazKGYf8nokq6zUKH/6INtV6MypSzSGmX2XErnARkIIPPYj +cQRQ8zCbGV7ZU2ezVbzhFLUSJveE8PZUzzCrLp1O2NSyBTRcR5HVSXW95nJfY8eV +pOvZRAKul0BVLh81kYTsrfzaaCjh9VWNP26LoeN2r+PjZyktXe7gM3C4SwCgoTxK +WUVi9HoT2HCLY7p7oig5hEcEALdCJal0UYomX3nJapIVLVZg3vkidr1RICYMb2vz +58i17h8sxEtobD1vdIKNejulntaRAXs4n0tDYD9z7pRlwG1CLz1R9WxYzeOOqUDr +fnVXdmU8L/oVWABat8v1V7QQhjMMf+41fuzVwDMMGqjVPLhu4X6wp3A8uyM3YDnQ +VMN1A/4n2G5gHoOvjqxn8Ch5tBAdMGfO8gH4RjQOwzm2R1wPQss/yzUN1+tlMZGX +K2dQ2FCWC/hDUSNaEQRlI15wxxBNZ2RQwlzE2A8v113DpvyzOtv0QO95gJ1teCXC +7j/BN9asgHaBBc39JLO/TcpuI7Hf8PQ5VcP2F0UE3lczGhXbLP8DAwKVpe92I5n5 +JGBjXsTTnVLoJ1hrWTdbLvdbn882m5pHYeqFlvkqKYXJTf0mIzpEU0FfZmFjdG9y +OgAAr0JzPBwQoEmNI3YSC1MwimZ77bpvVKP9JiM6RFNBX2ZhY3RvcjoAAK9/fVBz +g73cYbgeNWbz2uITUwNd9KEN/SYjOkRTQV9mYWN0b3I6AACvWjjITYZwah6NiH6C +YgX52m55Dy5PX7Q/Sm9lIFJhbmRvbSBIYWNrZXIgKHRlc3Qga2V5IHdpdGggcGFz +c3BocmFzZSAieCIpIDxqb2VAc2V0cS5vcmc+iFcEExECABcFAjo41NoFCwcKAwQD +FQMCAxYCAQIXgAAKCRCvgiRPnNn9VXm9AKCFQ/t23GQnQEfnnAnvbRNfRo4zIQCb +BHwILsDBASB1rQzW68UA/XHze0WdAUYEOjjU3RAEAJ50lvtCGbnQlI97VX6tJkos +dPmdzeXaTWfv//A2wmSANbYnuychGMa1LN43Ew+H6FXMWJ3MB/exs6UBFCgGsw88 +qmcla2bosQN/aVLA7fqXT9ujqoNGaIVEmgdbK1MkSPFXBFyVW3hteod83D0UqFll +twp4A3ageCYFVJTp50d3AAMFA/44YCQQbg9x9JvzHX3VH7CRX+raEDkDL3Pbz0PH +as7bwI7gzZ+GFyNKaCvrHQOyuR8RIKIbjtQYnXr1675ConCTceIXhysY32sTn5V6 +UFUW2t0xaRfas8sZBbLDyIJkpt4fyD+6OaRoui9KZqXMNwt7i/XFIto/sWd/OK3S +IgZkAf8DAwKVpe92I5n5JGAHRuEKSSvGU+0my6zTf17bLWPpFPnICNJdaMfyx24Y +RZZa+nDpYrRznJ89vohGBBgRAgAGBQI6ONTeAAoJEK+CJE+c2f1V7iIAn0WsYyUV +Huz4ZZ/WxxN57Ku2Eqs9AJ9Klz9imzvZoUjuE9/Ihr0y56tVng== +=lKvj +-----END PGP PRIVATE KEY BLOCK----- diff --git a/tags/GPGME-0-1-3/tests/t-decrypt.c b/tags/GPGME-0-1-3/tests/t-decrypt.c new file mode 100644 index 0000000..677d382 --- /dev/null +++ b/tags/GPGME-0-1-3/tests/t-decrypt.c @@ -0,0 +1,138 @@ +/* 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" + +struct passphrase_cb_info_s { + GpgmeCtx c; + int did_it; +}; + + +#define fail_if_err(a) do { if(a) { int my_errno = errno; \ + fprintf (stderr, "%s:%d: GpgmeError %s\n", \ + __FILE__, __LINE__, gpgme_strerror(a)); \ + 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); +} + + +static const char * +passphrase_cb ( void *opaque, const char *desc, void *r_hd ) +{ + const char *pass; + + if ( !desc ) { + /* cleanup by looking at *r_hd */ + + + return NULL; + } + + pass = "abc"; + fprintf (stderr, "%% requesting passphrase for `%s': ", desc ); + fprintf (stderr, "sending `%s'\n", pass ); + + return pass; +} + + +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, pwdata = NULL; + struct passphrase_cb_info_s info; + const char *cipher_1_asc = mk_fname ("cipher-1.asc"); + + do { + err = gpgme_new (&ctx); + fail_if_err (err); + if ( !getenv("GPG_AGENT_INFO") ) { + memset ( &info, 0, sizeof info ); + info.c = ctx; + gpgme_set_passphrase_cb ( ctx, passphrase_cb, &info ); + } + + 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_data_release (pwdata); + gpgme_release (ctx); + } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + + return 0; +} + + diff --git a/tags/GPGME-0-1-3/tests/t-encrypt.c b/tags/GPGME-0-1-3/tests/t-encrypt.c new file mode 100644 index 0000000..01c5379 --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/tests/t-export.c b/tags/GPGME-0-1-3/tests/t-export.c new file mode 100644 index 0000000..768e739 --- /dev/null +++ b/tags/GPGME-0-1-3/tests/t-export.c @@ -0,0 +1,91 @@ +/* t-export.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 out; + GpgmeRecipients rset; + + do { + err = gpgme_new (&ctx); + 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); + + gpgme_set_armor (ctx, 1 ); + err = gpgme_op_export (ctx, rset, 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 (out); + gpgme_release (ctx); + } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + + return 0; +} + + diff --git a/tags/GPGME-0-1-3/tests/t-genkey.c b/tags/GPGME-0-1-3/tests/t-genkey.c new file mode 100644 index 0000000..d22b95e --- /dev/null +++ b/tags/GPGME-0-1-3/tests/t-genkey.c @@ -0,0 +1,83 @@ +/* t-genkey.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 +progress ( void *self, const char *what, int type, int current, int total) +{ + fprintf (stderr, "progress `%s' %d %d %d\n", what, type, current, total); +} + + +int +main (int argc, char **argv ) +{ + GpgmeCtx ctx; + GpgmeError err; + const char *format; + char *parms; + int count = 0; + + do { + err = gpgme_new (&ctx); + fail_if_err (err); + + gpgme_set_progress_cb (ctx, progress, NULL); + + format = "\n" + "Key-Type: DSA\n" + "Key-Length: 1024\n" + "Subkey-Type: ELG-E\n" + "Subkey-Length: 1024\n" + "Name-Real: Joe Tester\n" + "Name-Comment: (pp=abc,try=%d)\n" + "Name-Email: joe@foo.bar\n" + "Expire-Date: 0\n" + "Passphrase: abc\n" + "\n"; + parms = malloc ( strlen (format) + 1 + 20 ); + if (!parms) + exit (8); + sprintf (parms, format, ++count ); + err = gpgme_op_genkey (ctx, parms, NULL, NULL ); + fail_if_err (err); + free (parms); + + gpgme_release (ctx); + } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + + return 0; +} + + + diff --git a/tags/GPGME-0-1-3/tests/t-import.c b/tags/GPGME-0-1-3/tests/t-import.c new file mode 100644 index 0000000..9335339 --- /dev/null +++ b/tags/GPGME-0-1-3/tests/t-import.c @@ -0,0 +1,90 @@ +/* t-import.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 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; + const char *pubkey_1_asc = mk_fname ("pubkey-1.asc"); + const char *seckey_1_asc = mk_fname ("seckey-1.asc"); + + do { + err = gpgme_new (&ctx); + fail_if_err (err); + + err = gpgme_data_new_from_file ( &in, pubkey_1_asc, 1 ); + fail_if_err (err); + + err = gpgme_op_import (ctx, in ); + fail_if_err (err); + + gpgme_data_release (in); + + err = gpgme_data_new_from_file ( &in, seckey_1_asc, 1 ); + fail_if_err (err); + + err = gpgme_op_import (ctx, in ); + fail_if_err (err); + + gpgme_data_release (in); + gpgme_release (ctx); + } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + + return 0; +} + + diff --git a/tags/GPGME-0-1-3/tests/t-keylist.c b/tags/GPGME-0-1-3/tests/t-keylist.c new file mode 100644 index 0000000..a67d1ee --- /dev/null +++ b/tags/GPGME-0-1-3/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/GPGME-0-1-3/tests/t-sign.c b/tags/GPGME-0-1-3/tests/t-sign.c new file mode 100644 index 0000000..79f6b5c --- /dev/null +++ b/tags/GPGME-0-1-3/tests/t-sign.c @@ -0,0 +1,137 @@ +/* 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); +} + +static const char * +passphrase_cb ( void *opaque, const char *desc, void *r_hd ) +{ + const char *pass; + + if ( !desc ) { + /* cleanup by looking at *r_hd */ + + + return NULL; + } + + pass = "abc"; + fprintf (stderr, "%% requesting passphrase for `%s': ", desc ); + fprintf (stderr, "sending `%s'\n", pass ); + + return pass; +} + + +int +main (int argc, char **argv ) +{ + GpgmeCtx ctx; + GpgmeError err; + GpgmeData in, out; + + do { + err = gpgme_new (&ctx); + fail_if_err (err); + if ( !getenv("GPG_AGENT_INFO") ) { + gpgme_set_passphrase_cb ( ctx, passphrase_cb, NULL ); + } + + gpgme_set_textmode (ctx, 1); + gpgme_set_armor (ctx, 1); + + err = gpgme_data_new_from_mem ( &in, "Hallo Leute\n", 12, 0 ); + fail_if_err (err); + + /* first a normal signature */ + err = gpgme_data_new ( &out ); + fail_if_err (err); + err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_NORMAL ); + fail_if_err (err); + fflush (NULL); + fputs ("Begin Result:\n", stdout ); + print_data (out); + fputs ("End Result.\n", stdout ); + gpgme_data_release (out); + gpgme_data_rewind (in); + + /* now a detached signature */ + err = gpgme_data_new ( &out ); + fail_if_err (err); + err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_DETACH ); + fail_if_err (err); + fflush (NULL); + fputs ("Begin Result:\n", stdout ); + print_data (out); + fputs ("End Result.\n", stdout ); + gpgme_data_release (out); + gpgme_data_rewind (in); + + + /* And finally a cleartext signature */ + err = gpgme_data_new ( &out ); + fail_if_err (err); + err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_CLEAR ); + fail_if_err (err); + fflush (NULL); + fputs ("Begin Result:\n", stdout ); + print_data (out); + fputs ("End Result.\n", stdout ); + gpgme_data_release (out); + gpgme_data_rewind (in); + + /* ready */ + gpgme_data_release (in); + gpgme_release (ctx); + } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); + + return 0; +} + + + + diff --git a/tags/GPGME-0-1-3/tests/t-verify.c b/tags/GPGME-0-1-3/tests/t-verify.c new file mode 100644 index 0000000..2b91a99 --- /dev/null +++ b/tags/GPGME-0-1-3/tests/t-verify.c @@ -0,0 +1,149 @@ +/* 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); + #if 1 + err = gpgme_data_new_from_mem ( &sig, + test_sig1, strlen (test_sig1), 0 ); + #else + err = gpgme_data_new_from_file ( &sig, "xx1", 1 ); + #endif + 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; +} + + +