summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJinWang An <jinwang.an@samsung.com>2021-12-01 16:54:36 +0900
committerJinWang An <jinwang.an@samsung.com>2021-12-01 16:54:36 +0900
commite158cb38f461261d019c653a5f5e0ca9ddab8d6d (patch)
tree3872a21bc5b5797ee3c705509aace3393b0de251 /src
parentfd5caec0dccd1229c2b9dd5220c8e2b1ef966d0e (diff)
downloadgpgme-e158cb38f461261d019c653a5f5e0ca9ddab8d6d.tar.gz
gpgme-e158cb38f461261d019c653a5f5e0ca9ddab8d6d.tar.bz2
gpgme-e158cb38f461261d019c653a5f5e0ca9ddab8d6d.zip
Imported Upstream version 1.7.0upstream/1.7.0
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am42
-rw-r--r--src/Makefile.in272
-rw-r--r--src/argparse.c1610
-rw-r--r--src/argparse.h203
-rw-r--r--src/assuan-support.c17
-rw-r--r--src/b64dec.c251
-rw-r--r--src/context.h11
-rw-r--r--src/conversion.c67
-rw-r--r--src/data-compat.c6
-rw-r--r--src/data-identify.c279
-rw-r--r--src/data-mem.c3
-rw-r--r--src/data.c32
-rw-r--r--src/data.h6
-rw-r--r--src/decrypt.c2
-rw-r--r--src/delete.c38
-rw-r--r--src/dirinfo.c103
-rw-r--r--src/edit.c113
-rw-r--r--src/encrypt-sign.c2
-rw-r--r--src/encrypt.c38
-rw-r--r--src/engine-assuan.c34
-rw-r--r--src/engine-backend.h18
-rw-r--r--src/engine-g13.c31
-rw-r--r--src/engine-gpg.c552
-rw-r--r--src/engine-gpgconf.c18
-rw-r--r--src/engine-gpgsm.c170
-rw-r--r--src/engine-spawn.c11
-rw-r--r--src/engine-uiserver.c97
-rw-r--r--src/engine.c138
-rw-r--r--src/engine.h24
-rw-r--r--src/export.c2
-rw-r--r--src/funopen.c2
-rw-r--r--src/genkey.c401
-rw-r--r--src/getauditlog.c3
-rw-r--r--src/gpgme-config.in35
-rw-r--r--src/gpgme-tool.c611
-rw-r--r--src/gpgme.c120
-rw-r--r--src/gpgme.def21
-rw-r--r--src/gpgme.h.in429
-rw-r--r--src/kdpipeiodevice.cpp951
-rw-r--r--src/kdpipeiodevice.h73
-rw-r--r--src/kdpipeiodevice.moc183
-rw-r--r--src/key.c31
-rw-r--r--src/keylist.c150
-rw-r--r--src/keysign.c218
-rw-r--r--src/libgpgme.vers19
-rw-r--r--src/mbox-util.c257
-rw-r--r--src/mbox-util.h29
-rw-r--r--src/moc_kdpipeiodevice.cpp60
-rw-r--r--src/op-support.c73
-rw-r--r--src/ops.h12
-rw-r--r--src/passphrase.c11
-rw-r--r--src/passwd.c8
-rw-r--r--src/posix-io.c81
-rw-r--r--src/posix-util.c11
-rw-r--r--src/sign.c27
-rw-r--r--src/status-table.c17
-rw-r--r--src/sys-util.h1
-rw-r--r--src/tofupolicy.c184
-rw-r--r--src/trustlist.c3
-rw-r--r--src/util.h38
-rw-r--r--src/verify.c294
-rw-r--r--src/version.c6
-rw-r--r--src/versioninfo.rc.in2
-rw-r--r--src/vfs-create.c2
-rw-r--r--src/vfs-mount.c2
-rw-r--r--src/w32-glib-io.c2
-rw-r--r--src/w32-io.c37
-rw-r--r--src/w32-qt-io.cpp700
-rw-r--r--src/w32-util.c60
-rw-r--r--src/wait-global.c4
-rw-r--r--src/wait-private.c6
-rw-r--r--src/wait-user.c2
72 files changed, 6249 insertions, 3117 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 58922f9..f166f3b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,9 +18,8 @@
## Process this file with automake to produce Makefile.in
-# Note: moc_kdpipeiodevice should actually be a dependecy below.
EXTRA_DIST = gpgme-config.in gpgme.m4 libgpgme.vers ChangeLog-2011 \
- gpgme.h.in versioninfo.rc.in gpgme.def moc_kdpipeiodevice.cpp
+ gpgme.h.in versioninfo.rc.in gpgme.def
bin_SCRIPTS = gpgme-config
m4datadir = $(datadir)/aclocal
@@ -41,12 +40,6 @@ else
ltlib_gpgme_glib =
endif
-if BUILD_W32_QT
-ltlib_gpgme_qt = libgpgme-qt.la
-else
-ltlib_gpgme_qt =
-endif
-
lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \
$(ltlib_gpgme_pthread)
@@ -80,8 +73,9 @@ endif
# right linking order with libtool, as the non-installed version has
# unresolved symbols to the thread module.
main_sources = \
- util.h conversion.c get-env.c context.h ops.h \
+ util.h conversion.c b64dec.c get-env.c context.h ops.h \
parsetlv.c parsetlv.h \
+ mbox-util.c mbox-util.h \
data.h data.c data-fd.c data-stream.c data-mem.c data-user.c \
data-compat.c data-identify.c \
signers.c sig-notation.c \
@@ -89,7 +83,7 @@ main_sources = \
op-support.c \
encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \
sign.c passphrase.c progress.c \
- key.c keylist.c trust-item.c trustlist.c \
+ key.c keylist.c keysign.c trust-item.c trustlist.c tofupolicy.c \
import.c export.c genkey.c delete.c edit.c getauditlog.c \
opassuan.c passwd.c spawn.c assuan-support.c \
engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
@@ -110,24 +104,11 @@ if BUILD_W32_GLIB
libgpgme_glib_la_SOURCES = $(main_sources) ath.h ath.c w32-glib-io.c
endif
-if BUILD_W32_QT
-libgpgme_qt_la_SOURCES = $(main_sources) ath.h ath.c w32-qt-io.cpp \
- kdpipeiodevice.h kdpipeiodevice.cpp kdpipeiodevice.moc
-# FIXME: Add extra depedency: moc_kdpipeiodevice.cpp
-
-# These are built sources (normally).
-# moc_kdpipeiodevice.cpp: kdpipeiodevice.h
-# $(MOC4) -o $@ $<
-#
-# kdpipeiodevice.moc: kdpipeiodevice.cpp
-# $(MOC4) -o $@ $<
-endif
-
-# We use a global CFLAGS and CPPFLAGS setting for all library
+# We use a global CFLAGS setting for all library
# versions, because then every object file is only compiled once.
-AM_CPPFLAGS = @GPG_ERROR_CFLAGS@ @QT4_CORE_CFLAGS@
-AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@ @QT4_CORE_CFLAGS@
+AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@
+gpgme_tool_SOURCES = gpgme-tool.c argparse.c argparse.h
gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@
@@ -201,15 +182,6 @@ libgpgme_glib_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
@GPG_ERROR_LIBS@ @GLIB_LIBS@
endif
-if BUILD_W32_QT
-libgpgme_qt_la_LDFLAGS = $(no_undefined) \
- $(export_symbols) $(libgpgme_version_script_cmd) -version-info \
- @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
-libgpgme_qt_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps)
-libgpgme_qt_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
- @GPG_ERROR_LIBS@ @QT4_CORE_LIBS@
-endif
-
install-data-local: install-def-file
uninstall-local: uninstall-def-file
diff --git a/src/Makefile.in b/src/Makefile.in
index ec839e4..75d7659 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -107,15 +107,19 @@ subdir = src
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/build-aux/mkinstalldirs \
$(srcdir)/versioninfo.rc.in $(srcdir)/gpgme.h.in \
- $(srcdir)/gpgme-config.in stpcpy.c funopen.c vasprintf.c \
- setenv.c ttyname_r.c $(top_srcdir)/build-aux/depcomp
+ $(srcdir)/gpgme-config.in setenv.c stpcpy.c vasprintf.c \
+ ttyname_r.c funopen.c $(top_srcdir)/build-aux/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/glib-2.0.m4 \
- $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/gnupg-ttyname.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
$(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
- $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -155,16 +159,17 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
"$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(includedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
@HAVE_W32_SYSTEM_TRUE@am__DEPENDENCIES_1 = versioninfo.lo
-am__libgpgme_glib_la_SOURCES_DIST = util.h conversion.c get-env.c \
- context.h ops.h parsetlv.c parsetlv.h data.h data.c data-fd.c \
- data-stream.c data-mem.c data-user.c data-compat.c \
- data-identify.c signers.c sig-notation.c wait.c wait-global.c \
- wait-private.c wait-user.c wait.h op-support.c encrypt.c \
- encrypt-sign.c decrypt.c decrypt-verify.c verify.c sign.c \
- passphrase.c progress.c key.c keylist.c trust-item.c \
- trustlist.c import.c export.c genkey.c delete.c edit.c \
- getauditlog.c opassuan.c passwd.c spawn.c assuan-support.c \
- engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
+am__libgpgme_glib_la_SOURCES_DIST = util.h conversion.c b64dec.c \
+ get-env.c context.h ops.h parsetlv.c parsetlv.h mbox-util.c \
+ mbox-util.h data.h data.c data-fd.c data-stream.c data-mem.c \
+ data-user.c data-compat.c data-identify.c signers.c \
+ sig-notation.c wait.c wait-global.c wait-private.c wait-user.c \
+ wait.h op-support.c encrypt.c encrypt-sign.c decrypt.c \
+ decrypt-verify.c verify.c sign.c passphrase.c progress.c key.c \
+ keylist.c keysign.c trust-item.c trustlist.c tofupolicy.c \
+ import.c export.c genkey.c delete.c edit.c getauditlog.c \
+ opassuan.c passwd.c spawn.c assuan-support.c engine.h \
+ engine-backend.h engine.c engine-gpg.c status-table.c \
engine-gpgsm.c engine-assuan.c engine-gpgconf.c \
engine-uiserver.c engine-g13.c vfs-mount.c vfs-create.c \
engine-spawn.c gpgconf.c sema.h priv-io.h ath.h posix-util.c \
@@ -177,16 +182,17 @@ am__libgpgme_glib_la_SOURCES_DIST = util.h conversion.c get-env.c \
@HAVE_DOSISH_SYSTEM_FALSE@ posix-io.lo $(am__objects_2)
@HAVE_DOSISH_SYSTEM_TRUE@am__objects_3 = w32-util.lo w32-sema.lo \
@HAVE_DOSISH_SYSTEM_TRUE@ $(am__objects_2)
-am__objects_4 = conversion.lo get-env.lo parsetlv.lo data.lo \
- data-fd.lo data-stream.lo data-mem.lo data-user.lo \
- data-compat.lo data-identify.lo signers.lo sig-notation.lo \
- wait.lo wait-global.lo wait-private.lo wait-user.lo \
- op-support.lo encrypt.lo encrypt-sign.lo decrypt.lo \
- decrypt-verify.lo verify.lo sign.lo passphrase.lo progress.lo \
- key.lo keylist.lo trust-item.lo trustlist.lo import.lo \
- export.lo genkey.lo delete.lo edit.lo getauditlog.lo \
- opassuan.lo passwd.lo spawn.lo assuan-support.lo engine.lo \
- engine-gpg.lo status-table.lo engine-gpgsm.lo engine-assuan.lo \
+am__objects_4 = conversion.lo b64dec.lo get-env.lo parsetlv.lo \
+ mbox-util.lo data.lo data-fd.lo data-stream.lo data-mem.lo \
+ data-user.lo data-compat.lo data-identify.lo signers.lo \
+ sig-notation.lo wait.lo wait-global.lo wait-private.lo \
+ wait-user.lo op-support.lo encrypt.lo encrypt-sign.lo \
+ decrypt.lo decrypt-verify.lo verify.lo sign.lo passphrase.lo \
+ progress.lo key.lo keylist.lo keysign.lo trust-item.lo \
+ trustlist.lo tofupolicy.lo import.lo export.lo genkey.lo \
+ delete.lo edit.lo getauditlog.lo opassuan.lo passwd.lo \
+ spawn.lo assuan-support.lo engine.lo engine-gpg.lo \
+ status-table.lo engine-gpgsm.lo engine-assuan.lo \
engine-gpgconf.lo $(am__objects_1) engine-g13.lo vfs-mount.lo \
vfs-create.lo engine-spawn.lo gpgconf.lo $(am__objects_3) \
dirinfo.lo debug.lo gpgme.lo version.lo error.lo
@@ -202,16 +208,17 @@ libgpgme_glib_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_CFLAGS) $(CFLAGS) $(libgpgme_glib_la_LDFLAGS) $(LDFLAGS) \
-o $@
@BUILD_W32_GLIB_TRUE@am_libgpgme_glib_la_rpath = -rpath $(libdir)
-am__libgpgme_pthread_la_SOURCES_DIST = util.h conversion.c get-env.c \
- context.h ops.h parsetlv.c parsetlv.h data.h data.c data-fd.c \
- data-stream.c data-mem.c data-user.c data-compat.c \
- data-identify.c signers.c sig-notation.c wait.c wait-global.c \
- wait-private.c wait-user.c wait.h op-support.c encrypt.c \
- encrypt-sign.c decrypt.c decrypt-verify.c verify.c sign.c \
- passphrase.c progress.c key.c keylist.c trust-item.c \
- trustlist.c import.c export.c genkey.c delete.c edit.c \
- getauditlog.c opassuan.c passwd.c spawn.c assuan-support.c \
- engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
+am__libgpgme_pthread_la_SOURCES_DIST = util.h conversion.c b64dec.c \
+ get-env.c context.h ops.h parsetlv.c parsetlv.h mbox-util.c \
+ mbox-util.h data.h data.c data-fd.c data-stream.c data-mem.c \
+ data-user.c data-compat.c data-identify.c signers.c \
+ sig-notation.c wait.c wait-global.c wait-private.c wait-user.c \
+ wait.h op-support.c encrypt.c encrypt-sign.c decrypt.c \
+ decrypt-verify.c verify.c sign.c passphrase.c progress.c key.c \
+ keylist.c keysign.c trust-item.c trustlist.c tofupolicy.c \
+ import.c export.c genkey.c delete.c edit.c getauditlog.c \
+ opassuan.c passwd.c spawn.c assuan-support.c engine.h \
+ engine-backend.h engine.c engine-gpg.c status-table.c \
engine-gpgsm.c engine-assuan.c engine-gpgconf.c \
engine-uiserver.c engine-g13.c vfs-mount.c vfs-create.c \
engine-spawn.c gpgconf.c sema.h priv-io.h ath.h posix-util.c \
@@ -227,55 +234,30 @@ libgpgme_pthread_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_CFLAGS) $(CFLAGS) $(libgpgme_pthread_la_LDFLAGS) \
$(LDFLAGS) -o $@
@HAVE_PTHREAD_TRUE@am_libgpgme_pthread_la_rpath = -rpath $(libdir)
-am__libgpgme_qt_la_SOURCES_DIST = util.h conversion.c get-env.c \
- context.h ops.h parsetlv.c parsetlv.h data.h data.c data-fd.c \
- data-stream.c data-mem.c data-user.c data-compat.c \
- data-identify.c signers.c sig-notation.c wait.c wait-global.c \
- wait-private.c wait-user.c wait.h op-support.c encrypt.c \
- encrypt-sign.c decrypt.c decrypt-verify.c verify.c sign.c \
- passphrase.c progress.c key.c keylist.c trust-item.c \
- trustlist.c import.c export.c genkey.c delete.c edit.c \
- getauditlog.c opassuan.c passwd.c spawn.c assuan-support.c \
- engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
- engine-gpgsm.c engine-assuan.c engine-gpgconf.c \
- engine-uiserver.c engine-g13.c vfs-mount.c vfs-create.c \
- engine-spawn.c gpgconf.c sema.h priv-io.h ath.h posix-util.c \
- posix-sema.c posix-io.c w32-ce.h w32-ce.c w32-util.c \
- w32-sema.c sys-util.h dirinfo.c debug.c debug.h gpgme.c \
- version.c error.c ath.c w32-qt-io.cpp kdpipeiodevice.h \
- kdpipeiodevice.cpp kdpipeiodevice.moc
-@BUILD_W32_QT_TRUE@am_libgpgme_qt_la_OBJECTS = $(am__objects_4) ath.lo \
-@BUILD_W32_QT_TRUE@ w32-qt-io.lo kdpipeiodevice.lo
-libgpgme_qt_la_OBJECTS = $(am_libgpgme_qt_la_OBJECTS)
-libgpgme_qt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
- $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
- $(AM_CXXFLAGS) $(CXXFLAGS) $(libgpgme_qt_la_LDFLAGS) \
- $(LDFLAGS) -o $@
-@BUILD_W32_QT_TRUE@am_libgpgme_qt_la_rpath = -rpath $(libdir)
-am__libgpgme_la_SOURCES_DIST = util.h conversion.c get-env.c context.h \
- ops.h parsetlv.c parsetlv.h data.h data.c data-fd.c \
- data-stream.c data-mem.c data-user.c data-compat.c \
- data-identify.c signers.c sig-notation.c wait.c wait-global.c \
- wait-private.c wait-user.c wait.h op-support.c encrypt.c \
- encrypt-sign.c decrypt.c decrypt-verify.c verify.c sign.c \
- passphrase.c progress.c key.c keylist.c trust-item.c \
- trustlist.c import.c export.c genkey.c delete.c edit.c \
- getauditlog.c opassuan.c passwd.c spawn.c assuan-support.c \
- engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
- engine-gpgsm.c engine-assuan.c engine-gpgconf.c \
- engine-uiserver.c engine-g13.c vfs-mount.c vfs-create.c \
- engine-spawn.c gpgconf.c sema.h priv-io.h ath.h posix-util.c \
- posix-sema.c posix-io.c w32-ce.h w32-ce.c w32-util.c \
- w32-sema.c sys-util.h dirinfo.c debug.c debug.h gpgme.c \
- version.c error.c ath.c w32-io.c
+am__libgpgme_la_SOURCES_DIST = util.h conversion.c b64dec.c get-env.c \
+ context.h ops.h parsetlv.c parsetlv.h mbox-util.c mbox-util.h \
+ data.h data.c data-fd.c data-stream.c data-mem.c data-user.c \
+ data-compat.c data-identify.c signers.c sig-notation.c wait.c \
+ wait-global.c wait-private.c wait-user.c wait.h op-support.c \
+ encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \
+ sign.c passphrase.c progress.c key.c keylist.c keysign.c \
+ trust-item.c trustlist.c tofupolicy.c import.c export.c \
+ genkey.c delete.c edit.c getauditlog.c opassuan.c passwd.c \
+ spawn.c assuan-support.c engine.h engine-backend.h engine.c \
+ engine-gpg.c status-table.c engine-gpgsm.c engine-assuan.c \
+ engine-gpgconf.c engine-uiserver.c engine-g13.c vfs-mount.c \
+ vfs-create.c engine-spawn.c gpgconf.c sema.h priv-io.h ath.h \
+ posix-util.c posix-sema.c posix-io.c w32-ce.h w32-ce.c \
+ w32-util.c w32-sema.c sys-util.h dirinfo.c debug.c debug.h \
+ gpgme.c version.c error.c ath.c w32-io.c
am_libgpgme_la_OBJECTS = $(am__objects_4) ath.lo $(am__objects_5)
libgpgme_la_OBJECTS = $(am_libgpgme_la_OBJECTS)
libgpgme_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libgpgme_la_LDFLAGS) $(LDFLAGS) -o $@
PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS)
-gpgme_tool_SOURCES = gpgme-tool.c
-gpgme_tool_OBJECTS = gpgme-tool.$(OBJEXT)
+am_gpgme_tool_OBJECTS = gpgme-tool.$(OBJEXT) argparse.$(OBJEXT)
+gpgme_tool_OBJECTS = $(am_gpgme_tool_OBJECTS)
gpgme_tool_DEPENDENCIES = libgpgme.la
gpgme_w32spawn_SOURCES = gpgme-w32spawn.c
gpgme_w32spawn_OBJECTS = gpgme-w32spawn.$(OBJEXT)
@@ -315,31 +297,12 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
-CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
-LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
- $(AM_CXXFLAGS) $(CXXFLAGS)
-AM_V_CXX = $(am__v_CXX_@AM_V@)
-am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
-am__v_CXX_0 = @echo " CXX " $@;
-am__v_CXX_1 =
-CXXLD = $(CXX)
-CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
- $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
-AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
-am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
-am__v_CXXLD_0 = @echo " CXXLD " $@;
-am__v_CXXLD_1 =
SOURCES = $(libgpgme_glib_la_SOURCES) $(libgpgme_pthread_la_SOURCES) \
- $(libgpgme_qt_la_SOURCES) $(libgpgme_la_SOURCES) gpgme-tool.c \
- gpgme-w32spawn.c
+ $(libgpgme_la_SOURCES) $(gpgme_tool_SOURCES) gpgme-w32spawn.c
DIST_SOURCES = $(am__libgpgme_glib_la_SOURCES_DIST) \
$(am__libgpgme_pthread_la_SOURCES_DIST) \
- $(am__libgpgme_qt_la_SOURCES_DIST) \
- $(am__libgpgme_la_SOURCES_DIST) gpgme-tool.c gpgme-w32spawn.c
+ $(am__libgpgme_la_SOURCES_DIST) $(gpgme_tool_SOURCES) \
+ gpgme-w32spawn.c
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -381,6 +344,7 @@ BUILD_REVISION = @BUILD_REVISION@
BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
@@ -392,12 +356,14 @@ CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
@@ -408,15 +374,23 @@ GLIB_LIBS = @GLIB_LIBS@
GLIB_MKENUMS = @GLIB_MKENUMS@
GOBJECT_QUERY = @GOBJECT_QUERY@
GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -427,10 +401,16 @@ LDFLAGS = @LDFLAGS@
LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
@@ -440,6 +420,8 @@ MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
NM = @NM@
NMEDIT = @NMEDIT@
@@ -456,14 +438,27 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
-QT4_CORE_CFLAGS = @QT4_CORE_CFLAGS@
-QT4_CORE_LIBS = @QT4_CORE_LIBS@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
RANLIB = @RANLIB@
RC = @RC@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
SYSROOT = @SYSROOT@
VERSION = @VERSION@
VERSION_NUMBER = @VERSION_NUMBER@
@@ -512,9 +507,13 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -523,10 +522,8 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-
-# Note: moc_kdpipeiodevice should actually be a dependecy below.
EXTRA_DIST = gpgme-config.in gpgme.m4 libgpgme.vers ChangeLog-2011 \
- gpgme.h.in versioninfo.rc.in gpgme.def moc_kdpipeiodevice.cpp
+ gpgme.h.in versioninfo.rc.in gpgme.def
bin_SCRIPTS = gpgme-config
m4datadir = $(datadir)/aclocal
@@ -536,8 +533,6 @@ nodist_include_HEADERS = gpgme.h
@HAVE_PTHREAD_TRUE@ltlib_gpgme_pthread = libgpgme-pthread.la
@BUILD_W32_GLIB_FALSE@ltlib_gpgme_glib =
@BUILD_W32_GLIB_TRUE@ltlib_gpgme_glib = libgpgme-glib.la
-@BUILD_W32_QT_FALSE@ltlib_gpgme_qt =
-@BUILD_W32_QT_TRUE@ltlib_gpgme_qt = libgpgme-qt.la
lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \
$(ltlib_gpgme_pthread)
@@ -559,8 +554,9 @@ lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \
# right linking order with libtool, as the non-installed version has
# unresolved symbols to the thread module.
main_sources = \
- util.h conversion.c get-env.c context.h ops.h \
+ util.h conversion.c b64dec.c get-env.c context.h ops.h \
parsetlv.c parsetlv.h \
+ mbox-util.c mbox-util.h \
data.h data.c data-fd.c data-stream.c data-mem.c data-user.c \
data-compat.c data-identify.c \
signers.c sig-notation.c \
@@ -568,7 +564,7 @@ main_sources = \
op-support.c \
encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \
sign.c passphrase.c progress.c \
- key.c keylist.c trust-item.c trustlist.c \
+ key.c keylist.c keysign.c trust-item.c trustlist.c tofupolicy.c \
import.c export.c genkey.c delete.c edit.c getauditlog.c \
opassuan.c passwd.c spawn.c assuan-support.c \
engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
@@ -587,22 +583,11 @@ libgpgme_pthread_la_SOURCES = $(main_sources) \
ath.h ath-pthread.c $(system_components_not_extra)
@BUILD_W32_GLIB_TRUE@libgpgme_glib_la_SOURCES = $(main_sources) ath.h ath.c w32-glib-io.c
-@BUILD_W32_QT_TRUE@libgpgme_qt_la_SOURCES = $(main_sources) ath.h ath.c w32-qt-io.cpp \
-@BUILD_W32_QT_TRUE@ kdpipeiodevice.h kdpipeiodevice.cpp kdpipeiodevice.moc
-
-# FIXME: Add extra depedency: moc_kdpipeiodevice.cpp
-# These are built sources (normally).
-# moc_kdpipeiodevice.cpp: kdpipeiodevice.h
-# $(MOC4) -o $@ $<
-#
-# kdpipeiodevice.moc: kdpipeiodevice.cpp
-# $(MOC4) -o $@ $<
-
-# We use a global CFLAGS and CPPFLAGS setting for all library
+# We use a global CFLAGS setting for all library
# versions, because then every object file is only compiled once.
-AM_CPPFLAGS = @GPG_ERROR_CFLAGS@ @QT4_CORE_CFLAGS@
-AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@ @QT4_CORE_CFLAGS@
+AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@
+gpgme_tool_SOURCES = gpgme-tool.c argparse.c argparse.h
gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@
@HAVE_W32_SYSTEM_TRUE@RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES)
@HAVE_W32_SYSTEM_TRUE@LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE)
@@ -645,18 +630,10 @@ libgpgme_pthread_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
@BUILD_W32_GLIB_TRUE@libgpgme_glib_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
@BUILD_W32_GLIB_TRUE@ @GPG_ERROR_LIBS@ @GLIB_LIBS@
-@BUILD_W32_QT_TRUE@libgpgme_qt_la_LDFLAGS = $(no_undefined) \
-@BUILD_W32_QT_TRUE@ $(export_symbols) $(libgpgme_version_script_cmd) -version-info \
-@BUILD_W32_QT_TRUE@ @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
-
-@BUILD_W32_QT_TRUE@libgpgme_qt_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps)
-@BUILD_W32_QT_TRUE@libgpgme_qt_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
-@BUILD_W32_QT_TRUE@ @GPG_ERROR_LIBS@ @QT4_CORE_LIBS@
-
all: all-am
.SUFFIXES:
-.SUFFIXES: .rc .lo .c .cpp .o .obj
+.SUFFIXES: .rc .lo .c .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
@@ -735,9 +712,6 @@ libgpgme-glib.la: $(libgpgme_glib_la_OBJECTS) $(libgpgme_glib_la_DEPENDENCIES) $
libgpgme-pthread.la: $(libgpgme_pthread_la_OBJECTS) $(libgpgme_pthread_la_DEPENDENCIES) $(EXTRA_libgpgme_pthread_la_DEPENDENCIES)
$(AM_V_CCLD)$(libgpgme_pthread_la_LINK) $(am_libgpgme_pthread_la_rpath) $(libgpgme_pthread_la_OBJECTS) $(libgpgme_pthread_la_LIBADD) $(LIBS)
-libgpgme-qt.la: $(libgpgme_qt_la_OBJECTS) $(libgpgme_qt_la_DEPENDENCIES) $(EXTRA_libgpgme_qt_la_DEPENDENCIES)
- $(AM_V_CXXLD)$(libgpgme_qt_la_LINK) $(am_libgpgme_qt_la_rpath) $(libgpgme_qt_la_OBJECTS) $(libgpgme_qt_la_LIBADD) $(LIBS)
-
libgpgme.la: $(libgpgme_la_OBJECTS) $(libgpgme_la_DEPENDENCIES) $(EXTRA_libgpgme_la_DEPENDENCIES)
$(AM_V_CCLD)$(libgpgme_la_LINK) -rpath $(libdir) $(libgpgme_la_OBJECTS) $(libgpgme_la_LIBADD) $(LIBS)
install-binPROGRAMS: $(bin_PROGRAMS)
@@ -893,9 +867,11 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/stpcpy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ttyname_r.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/vasprintf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/argparse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/assuan-support.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ath-pthread.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/b64dec.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conversion.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-compat.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-fd.Plo@am__quote@
@@ -930,9 +906,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme-w32spawn.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/import.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kdpipeiodevice.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/key.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keylist.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keysign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbox-util.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/op-support.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opassuan.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parsetlv.Plo@am__quote@
@@ -947,6 +924,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signers.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spawn.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status-table.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tofupolicy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trust-item.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trustlist.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verify.Plo@am__quote@
@@ -956,7 +934,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-ce.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-glib-io.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-io.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-qt-io.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-sema.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-util.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wait-global.Plo@am__quote@
@@ -985,27 +962,6 @@ distclean-compile:
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
-.cpp.o:
-@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
-
-.cpp.obj:
-@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
-
-.cpp.lo:
-@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
-
mostlyclean-libtool:
-rm -f *.lo
diff --git a/src/argparse.c b/src/argparse.c
new file mode 100644
index 0000000..003334f
--- /dev/null
+++ b/src/argparse.c
@@ -0,0 +1,1610 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify it
+ * under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This file may be used as part of GnuPG or standalone. A GnuPG
+ build is detected by the presence of the macro GNUPG_MAJOR_VERSION.
+ Some feature are only availalbe in the GnuPG build mode.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+
+#ifdef GNUPG_MAJOR_VERSION
+# include "util.h"
+# include "common-defs.h"
+# include "i18n.h"
+# include "mischelp.h"
+# include "stringhelp.h"
+# include "logging.h"
+# include "utf8conv.h"
+#endif /*GNUPG_MAJOR_VERSION*/
+
+#include "argparse.h"
+
+/* GnuPG uses GPLv3+ but a standalone version of this defaults to
+ GPLv2+ because that is the license of this file. Change this if
+ you include it in a program which uses GPLv3. If you don't want to
+ set a a copyright string for your usage() you may also hardcode it
+ here. */
+#ifndef GNUPG_MAJOR_VERSION
+
+# define ARGPARSE_GPL_VERSION 2
+# define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME"
+
+#else /* Used by GnuPG */
+
+# define ARGPARSE_GPL_VERSION 3
+# define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc."
+
+#endif /*GNUPG_MAJOR_VERSION*/
+
+/* Replacements for standalone builds. */
+#ifndef GNUPG_MAJOR_VERSION
+# ifndef _
+# define _(a) (a)
+# endif
+# ifndef DIM
+# define DIM(v) (sizeof(v)/sizeof((v)[0]))
+# endif
+# define xtrymalloc(a) malloc ((a))
+# define xtryrealloc(a,b) realloc ((a), (b))
+# define xtrystrdup(a) strdup ((a))
+# define xfree(a) free ((a))
+# define log_error my_log_error
+# define log_bug my_log_bug
+# define trim_spaces(a) my_trim_spaces ((a))
+# define map_static_macro_string(a) (a)
+#endif /*!GNUPG_MAJOR_VERSION*/
+
+
+#define ARGPARSE_STR(v) #v
+#define ARGPARSE_STR2(v) ARGPARSE_STR(v)
+
+
+/* Replacements for standalone builds. */
+#ifndef GNUPG_MAJOR_VERSION
+static void
+my_log_error (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ fprintf (stderr, "%s: ", strusage (11));
+ vfprintf (stderr, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+static void
+my_log_bug (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));
+ vfprintf (stderr, fmt, arg_ptr);
+ va_end (arg_ptr);
+ abort ();
+}
+
+/* Return true if the native charset is utf-8. */
+static int
+is_native_utf8 (void)
+{
+ return 1;
+}
+
+static char *
+my_trim_spaces (char *str)
+{
+ char *string, *p, *mark;
+
+ string = str;
+ /* Find first non space character. */
+ for (p=string; *p && isspace (*(unsigned char*)p) ; p++)
+ ;
+ /* Move characters. */
+ for ((mark = NULL); (*string = *p); string++, p++)
+ if (isspace (*(unsigned char*)p))
+ {
+ if (!mark)
+ mark = string;
+ }
+ else
+ mark = NULL;
+ if (mark)
+ *mark = '\0' ; /* Remove trailing spaces. */
+
+ return str ;
+}
+
+#endif /*!GNUPG_MAJOR_VERSION*/
+
+
+
+/*********************************
+ * @Summary arg_parse
+ * #include "argparse.h"
+ *
+ * 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 6 : Ignore this option
+ * 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 },
+ * { 300, "ignored-long-option, ARGPARSE_OP_IGNORE},
+ * { 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 */
+};
+
+
+/* Object to store the names for the --ignore-invalid-option option.
+ This is a simple linked list. */
+typedef struct iio_item_def_s *IIO_ITEM_DEF;
+struct iio_item_def_s
+{
+ IIO_ITEM_DEF next;
+ char name[1]; /* String with the long option name. */
+};
+
+static const char *(*strusage_handler)( int ) = NULL;
+static int (*custom_outfnc) (int, const char *);
+
+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 int writestrings (int is_error, const char *string, ...)
+#if __GNUC__ >= 4
+ __attribute__ ((sentinel(0)))
+#endif
+ ;
+
+
+void
+argparse_register_outfnc (int (*fnc)(int, const char *))
+{
+ custom_outfnc = fnc;
+}
+
+
+/* Write STRING and all following const char * arguments either to
+ stdout or, if IS_ERROR is set, to stderr. The list of strings must
+ be terminated by a NULL. */
+static int
+writestrings (int is_error, const char *string, ...)
+{
+ va_list arg_ptr;
+ const char *s;
+ int count = 0;
+
+ if (string)
+ {
+ s = string;
+ va_start (arg_ptr, string);
+ do
+ {
+ if (custom_outfnc)
+ custom_outfnc (is_error? 2:1, s);
+ else
+ fputs (s, is_error? stderr : stdout);
+ count += strlen (s);
+ }
+ while ((s = va_arg (arg_ptr, const char *)));
+ va_end (arg_ptr);
+ }
+ return count;
+}
+
+
+static void
+flushstrings (int is_error)
+{
+ if (custom_outfnc)
+ custom_outfnc (is_error? 2:1, NULL);
+ else
+ fflush (is_error? stderr : stdout);
+}
+
+
+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->internal.iio_list = NULL;
+ arg->err = 0;
+ arg->flags |= 1<<15; /* Mark as initialized. */
+ if ( *arg->argc < 0 )
+ log_bug ("invalid argument for arg_parse\n");
+ }
+
+
+ if (arg->err)
+ {
+ /* Last option was erroneous. */
+ const char *s;
+
+ if (filename)
+ {
+ if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
+ s = _("argument not expected");
+ else if ( arg->r_opt == ARGPARSE_READ_ERROR )
+ s = _("read error");
+ else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
+ s = _("keyword too long");
+ else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
+ s = _("missing argument");
+ else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
+ s = _("invalid argument");
+ else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
+ s = _("invalid command");
+ else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
+ s = _("invalid alias definition");
+ else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
+ s = _("out of core");
+ else
+ s = _("invalid option");
+ log_error ("%s:%u: %s\n", filename, *lineno, s);
+ }
+ else
+ {
+ s = arg->internal.last? arg->internal.last:"[??]";
+
+ if ( arg->r_opt == ARGPARSE_MISSING_ARG )
+ log_error (_("missing argument for option \"%.50s\"\n"), s);
+ else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
+ log_error (_("invalid argument for option \"%.50s\"\n"), s);
+ else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
+ log_error (_("option \"%.50s\" does not expect an argument\n"), s);
+ else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
+ log_error (_("invalid command \"%.50s\"\n"), s);
+ else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
+ log_error (_("option \"%.50s\" is ambiguous\n"), s);
+ else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
+ log_error (_("command \"%.50s\" is ambiguous\n"),s );
+ else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
+ log_error ("%s\n", _("out of core\n"));
+ else
+ log_error (_("invalid option \"%.50s\"\n"), s);
+ }
+ if (arg->err != ARGPARSE_PRINT_WARNING)
+ exit (2);
+ arg->err = 0;
+ }
+
+ /* Zero out 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
+ */
+ (void)arg;
+ (void)name;
+ (void)value;
+#if 0
+ ALIAS_DEF a = xmalloc( sizeof *a );
+ a->name = name;
+ a->value = value;
+ a->next = (ALIAS_DEF)arg->internal.aliases;
+ (ALIAS_DEF)arg->internal.aliases = a;
+#endif
+}
+
+
+/* Return true if KEYWORD is in the ignore-invalid-option list. */
+static int
+ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
+{
+ IIO_ITEM_DEF item = arg->internal.iio_list;
+
+ for (; item; item = item->next)
+ if (!strcmp (item->name, keyword))
+ return 1;
+ return 0;
+}
+
+
+/* Add the keywords up to the next LF to the list of to be ignored
+ options. After returning FP will either be at EOF or the next
+ character read wll be the first of a new line. The function
+ returns 0 on success or true on malloc failure. */
+static int
+ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
+{
+ IIO_ITEM_DEF item;
+ int c;
+ char name[100];
+ int namelen = 0;
+ int ready = 0;
+ enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;
+
+ while (!ready)
+ {
+ c = getc (fp);
+ if (c == '\n')
+ ready = 1;
+ else if (c == EOF)
+ {
+ c = '\n';
+ ready = 1;
+ }
+ again:
+ switch (state)
+ {
+ case skipWS:
+ if (!isascii (c) || !isspace(c))
+ {
+ namelen = 0;
+ state = collectNAME;
+ goto again;
+ }
+ break;
+
+ case collectNAME:
+ if (isspace (c))
+ {
+ state = addNAME;
+ goto again;
+ }
+ else if (namelen < DIM(name)-1)
+ name[namelen++] = c;
+ else /* Too long. */
+ state = skipNAME;
+ break;
+
+ case skipNAME:
+ if (isspace (c))
+ {
+ state = skipWS;
+ goto again;
+ }
+ break;
+
+ case addNAME:
+ name[namelen] = 0;
+ if (!ignore_invalid_option_p (arg, name))
+ {
+ item = xtrymalloc (sizeof *item + namelen);
+ if (!item)
+ return 1;
+ strcpy (item->name, name);
+ item->next = (IIO_ITEM_DEF)arg->internal.iio_list;
+ arg->internal.iio_list = item;
+ }
+ state = skipWS;
+ goto again;
+ }
+ }
+ return 0;
+}
+
+
+/* Clear the entire ignore-invalid-option list. */
+static void
+ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
+{
+ IIO_ITEM_DEF item, tmpitem;
+
+ for (item = arg->internal.iio_list; item; item = tmpitem)
+ {
+ tmpitem = item->next;
+ xfree (item);
+ }
+ arg->internal.iio_list = NULL;
+}
+
+
+
+/****************
+ * 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.
+ * The option
+ * ignore-invalid-option OPTIONNAMEs
+ * is recognized and updates a list of option which should be ignored if they
+ * are not defined.
+ * 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 in_alias=0;
+
+ if (!fp) /* Divert to to 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 ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
+ {
+ state = i = 0;
+ continue;
+ }
+ else if (!opts[idx].short_opt )
+ {
+ if (!strcmp (keyword, "ignore-invalid-option"))
+ {
+ /* No argument - ignore this meta option. */
+ state = i = 0;
+ continue;
+ }
+ else if (ignore_invalid_option_p (arg, keyword))
+ {
+ /* This invalid option is in the iio list. */
+ state = i = 0;
+ continue;
+ }
+ arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+ ? ARGPARSE_INVALID_COMMAND
+ : ARGPARSE_INVALID_OPTION);
+ }
+ else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+ arg->r_type = 0; /* Does not take an arg. */
+ else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) )
+ arg->r_type = 0; /* Arg is optional. */
+ else
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+
+ break;
+ }
+ else if (state == 3)
+ {
+ /* No argument found. */
+ if (in_alias)
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+ arg->r_type = 0; /* Does not take an arg. */
+ else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
+ arg->r_type = 0; /* No optional argument. */
+ else
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+
+ break;
+ }
+ else if (state == 4)
+ {
+ /* Has an argument. */
+ if (in_alias)
+ {
+ if (!buffer)
+ arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+ else
+ {
+ char *p;
+
+ buffer[i] = 0;
+ p = strpbrk (buffer, " \t");
+ if (p)
+ {
+ *p++ = 0;
+ trim_spaces (p);
+ }
+ if (!p || !*p)
+ {
+ xfree (buffer);
+ arg->r_opt = ARGPARSE_INVALID_ALIAS;
+ }
+ else
+ {
+ store_alias (arg, buffer, p);
+ }
+ }
+ }
+ else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+ arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+ else
+ {
+ char *p;
+
+ if (!buffer)
+ {
+ keyword[i] = 0;
+ buffer = xtrystrdup (keyword);
+ if (!buffer)
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ }
+ else
+ buffer[i] = 0;
+
+ if (buffer)
+ {
+ 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))
+ xfree (buffer);
+ }
+ }
+ break;
+ }
+ else if (c == EOF)
+ {
+ ignore_invalid_option_clear (arg);
+ if (ferror (fp))
+ arg->r_opt = ARGPARSE_READ_ERROR;
+ else
+ arg->r_opt = 0; /* EOF. */
+ break;
+ }
+ state = 0;
+ i = 0;
+ }
+ else if (state == -1)
+ ; /* Skip. */
+ else if (state == 0 && isascii (c) && isspace(c))
+ ; /* Skip leading white space. */
+ else if (state == 0 && c == '#' )
+ state = 1; /* Start of a comment. */
+ else if (state == 1)
+ ; /* Skip comments. */
+ else if (state == 2 && isascii (c) && isspace(c))
+ {
+ /* Check keyword. */
+ 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].flags & ARGPARSE_OPT_IGNORE))
+ {
+ state = 1; /* Process like a comment. */
+ }
+ else if (!opts[idx].short_opt)
+ {
+ if (!strcmp (keyword, "alias"))
+ {
+ in_alias = 1;
+ state = 3;
+ }
+ else if (!strcmp (keyword, "ignore-invalid-option"))
+ {
+ if (ignore_invalid_option_add (arg, fp))
+ {
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ break;
+ }
+ state = i = 0;
+ ++*lineno;
+ }
+ else if (ignore_invalid_option_p (arg, keyword))
+ state = 1; /* Process like a comment. */
+ else
+ {
+ arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+ ? ARGPARSE_INVALID_COMMAND
+ : ARGPARSE_INVALID_OPTION);
+ state = -1; /* Skip rest of line and leave. */
+ }
+ }
+ else
+ state = 3;
+ }
+ else if (state == 3)
+ {
+ /* Skip leading spaces of the argument. */
+ if (!isascii (c) || !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
+ {
+ char *tmp;
+ size_t tmplen = buflen + 50;
+
+ tmp = xtryrealloc (buffer, tmplen);
+ if (tmp)
+ {
+ buflen = tmplen;
+ buffer = tmp;
+ buffer[i++] = c;
+ }
+ else
+ {
+ xfree (buffer);
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ break;
+ }
+ }
+ }
+ else if (i < DIM(keyword)-1)
+ keyword[i++] = c;
+ else
+ {
+ size_t tmplen = DIM(keyword) + 50;
+ buffer = xtrymalloc (tmplen);
+ if (buffer)
+ {
+ buflen = tmplen;
+ memcpy(buffer, keyword, i);
+ buffer[i++] = c;
+ }
+ else
+ {
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ break;
+ }
+ }
+ }
+ else if (i >= DIM(keyword)-1)
+ {
+ arg->r_opt = ARGPARSE_KEYWORD_TOO_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;
+
+ (void)arg;
+
+ /* 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 when 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; /* Not found. */
+}
+
+int
+arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+ int idx;
+ int argc;
+ char **argv;
+ char *s, *s2;
+ int i;
+ char string_with_x[] = "x";
+
+ initialize( arg, NULL, NULL );
+ argc = *arg->argc;
+ argv = *arg->argv;
+ idx = arg->internal.idx;
+
+ if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
+ {
+ /* Skip the first argument. */
+ 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 & ARGPARSE_FLAG_ALL))
+ {
+ arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--; argv++; idx++; /* set to next one */
+ }
+ else if( arg->internal.stopped )
+ {
+ arg->r_opt = 0;
+ goto leave; /* Ready. */
+ }
+ else if ( *s == '-' && s[1] == '-' )
+ {
+ /* Long option. */
+ char *argpos;
+
+ arg->internal.inarg = 0;
+ if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
+ {
+ /* Stop option processing. */
+ arg->internal.stopped = 1;
+ arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
+ 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 & ARGPARSE_FLAG_NOVERSION))
+ {
+ show_version ();
+ exit(0);
+ }
+ }
+ else if ( i < 0 && !strcmp( "warranty", s+2))
+ {
+ writestrings (0, strusage (16), "\n", NULL);
+ exit (0);
+ }
+ else if ( i < 0 && !strcmp( "dump-options", s+2) )
+ {
+ for (i=0; opts[i].short_opt; i++ )
+ {
+ if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
+ writestrings (0, "--", opts[i].long_opt, "\n", NULL);
+ }
+ writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
+ NULL);
+ exit (0);
+ }
+
+ if ( i == -2 )
+ arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
+ else if ( i == -1 )
+ {
+ arg->r_opt = ARGPARSE_INVALID_OPTION;
+ arg->r.ret_str = s+2;
+ }
+ else
+ arg->r_opt = opts[i].short_opt;
+ if ( i < 0 )
+ ;
+ else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
+ {
+ if ( argpos )
+ {
+ s2 = argpos+1;
+ if ( !*s2 )
+ s2 = NULL;
+ }
+ else
+ s2 = argv[1];
+ if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */
+ }
+ else if ( !s2 )
+ {
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ }
+ else if ( !argpos && *s2 == '-'
+ && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ /* 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 = ARGPARSE_TYPE_NONE;
+ }
+ 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 = ARGPARSE_UNEXPECTED_ARG;
+ 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 & ARGPARSE_FLAG_ONEDASH) )
+ {
+ 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 & ARGPARSE_OPT_COMMAND)?
+ ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
+ arg->internal.inarg++; /* Point to the next arg. */
+ arg->r.ret_str = s;
+ }
+ else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
+ {
+ 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 & ARGPARSE_OPT_OPTIONAL) )
+ {
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ }
+ else if ( !s2 )
+ {
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ }
+ else if ( *s2 == '-' && s2[1]
+ && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ /* 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 = ARGPARSE_TYPE_NONE;
+ }
+ else
+ {
+ set_opt_arg (arg, opts[i].flags, s2);
+ argc--; argv++; idx++; /* Skip one. */
+ }
+ }
+ s = string_with_x; /* This is so that !s[1] yields false. */
+ }
+ else
+ {
+ /* Does not take an argument. */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ 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 & ARGPARSE_FLAG_MIXED )
+ {
+ arg->r_opt = ARGPARSE_IS_ARG;
+ 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;
+}
+
+
+/* Returns: -1 on error, 0 for an integer type and 1 for a non integer
+ type argument. */
+static int
+set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
+{
+ int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
+ long l;
+
+ switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
+ {
+ case ARGPARSE_TYPE_LONG:
+ case ARGPARSE_TYPE_INT:
+ errno = 0;
+ l = strtol (s, NULL, base);
+ if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
+ {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ if (arg->r_type == ARGPARSE_TYPE_LONG)
+ arg->r.ret_long = l;
+ else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
+ {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ else
+ arg->r.ret_int = (int)l;
+ return 0;
+
+ case ARGPARSE_TYPE_ULONG:
+ while (isascii (*s) && isspace(*s))
+ s++;
+ if (*s == '-')
+ {
+ arg->r.ret_ulong = 0;
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ errno = 0;
+ arg->r.ret_ulong = strtoul (s, NULL, base);
+ if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
+ {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ return 0;
+
+ case ARGPARSE_TYPE_STRING:
+ 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;
+ int is_utf8 = is_native_utf8 ();
+
+ s=o->description+1;
+ if ( *s != '=' )
+ n++;
+ /* For a (mostly) correct length calculation we exclude
+ continuation bytes (10xxxxxx) if we are on a native utf8
+ terminal. */
+ for (; *s && *s != '|'; s++ )
+ if ( is_utf8 && (*s&0xc0) != 0x80 )
+ 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 int flags)
+{
+ const char *s;
+ char tmp[2];
+
+ show_version ();
+ writestrings (0, "\n", NULL);
+ s = strusage (42);
+ if (s && *s == '1')
+ {
+ s = strusage (40);
+ writestrings (1, s, NULL);
+ if (*s && s[strlen(s)] != '\n')
+ writestrings (1, "\n", NULL);
+ }
+ s = strusage(41);
+ writestrings (0, s, "\n", NULL);
+ 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 != '@' )
+ writestrings (0, "Options:", "\n", NULL);
+ for (i=0; opts[i].short_opt; i++ )
+ {
+ s = map_static_macro_string (_( 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] )
+ writestrings (0, "\n", NULL);
+ }
+ else
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings (0, tmp, NULL);
+ }
+ }
+ writestrings (0, "\n", NULL);
+ continue;
+ }
+
+ j = 3;
+ if ( opts[i].short_opt < 256 )
+ {
+ tmp[0] = opts[i].short_opt;
+ tmp[1] = 0;
+ writestrings (0, " -", tmp, NULL );
+ if ( !opts[i].long_opt )
+ {
+ if (s && *s == '|' )
+ {
+ writestrings (0, " ", NULL); j++;
+ for (s++ ; *s && *s != '|'; s++, j++ )
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings (0, tmp, NULL);
+ }
+ if ( *s )
+ s++;
+ }
+ }
+ }
+ else
+ writestrings (0, " ", NULL);
+ if ( opts[i].long_opt )
+ {
+ tmp[0] = opts[i].short_opt < 256?',':' ';
+ tmp[1] = 0;
+ j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
+ if (s && *s == '|' )
+ {
+ if ( *++s != '=' )
+ {
+ writestrings (0, " ", NULL);
+ j++;
+ }
+ for ( ; *s && *s != '|'; s++, j++ )
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings (0, tmp, NULL);
+ }
+ if ( *s )
+ s++;
+ }
+ writestrings (0, " ", NULL);
+ j += 3;
+ }
+ for (;j < indent; j++ )
+ writestrings (0, " ", NULL);
+ if ( s )
+ {
+ if ( *s && j > indent )
+ {
+ writestrings (0, "\n", NULL);
+ for (j=0;j < indent; j++ )
+ writestrings (0, " ", NULL);
+ }
+ for (; *s; s++ )
+ {
+ if ( *s == '\n' )
+ {
+ if ( s[1] )
+ {
+ writestrings (0, "\n", NULL);
+ for (j=0; j < indent; j++ )
+ writestrings (0, " ", NULL);
+ }
+ }
+ else
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings (0, tmp, NULL);
+ }
+ }
+ }
+ writestrings (0, "\n", NULL);
+ }
+ if ( (flags & ARGPARSE_FLAG_ONEDASH) )
+ writestrings (0, "\n(A single dash may be used "
+ "instead of the double ones)\n", NULL);
+ }
+ if ( (s=strusage(19)) )
+ {
+ writestrings (0, "\n", NULL);
+ writestrings (0, s, NULL);
+ }
+ flushstrings (0);
+ exit(0);
+}
+
+static void
+show_version ()
+{
+ const char *s;
+ int i;
+
+ /* Version line. */
+ writestrings (0, strusage (11), NULL);
+ if ((s=strusage (12)))
+ writestrings (0, " (", s, ")", NULL);
+ writestrings (0, " ", strusage (13), "\n", NULL);
+ /* Additional version lines. */
+ for (i=20; i < 30; i++)
+ if ((s=strusage (i)))
+ writestrings (0, s, "\n", NULL);
+ /* Copyright string. */
+ if ((s=strusage (14)))
+ writestrings (0, s, "\n", NULL);
+ /* Licence string. */
+ if( (s=strusage (10)) )
+ writestrings (0, s, "\n", NULL);
+ /* Copying conditions. */
+ if ( (s=strusage(15)) )
+ writestrings (0, s, NULL);
+ /* Thanks. */
+ if ((s=strusage(18)))
+ writestrings (0, s, NULL);
+ /* Additional program info. */
+ for (i=30; i < 40; i++ )
+ if ( (s=strusage (i)) )
+ writestrings (0, s, NULL);
+ flushstrings (0);
+}
+
+
+void
+usage (int level)
+{
+ const char *p;
+
+ if (!level)
+ {
+ writestrings (1, strusage(11), " ", strusage(13), "; ",
+ strusage (14), "\n", NULL);
+ flushstrings (1);
+ }
+ else if (level == 1)
+ {
+ p = strusage (40);
+ writestrings (1, p, NULL);
+ if (*p && p[strlen(p)] != '\n')
+ writestrings (1, "\n", NULL);
+ exit (2);
+ }
+ else if (level == 2)
+ {
+ p = strusage (42);
+ if (p && *p == '1')
+ {
+ p = strusage (40);
+ writestrings (1, p, NULL);
+ if (*p && p[strlen(p)] != '\n')
+ writestrings (1, "\n", NULL);
+ }
+ writestrings (0, strusage(41), "\n", NULL);
+ exit (0);
+ }
+}
+
+/* Level
+ * 0: Print copyright string to stderr
+ * 1: Print a short usage hint to stderr and terminate
+ * 2: Print a long usage hint to stdout and terminate
+ * 10: Return license info string
+ * 11: Return the name of the program
+ * 12: Return 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)
+ * 42: Flag string:
+ * First char is '1':
+ * The short usage notes needs to be printed
+ * before the long usage note.
+ */
+const char *
+strusage( int level )
+{
+ const char *p = strusage_handler? strusage_handler(level) : NULL;
+
+ if ( p )
+ return map_static_macro_string (p);
+
+ switch ( level )
+ {
+
+ case 10:
+#if ARGPARSE_GPL_VERSION == 3
+ p = ("License GPLv3+: GNU GPL version 3 or later "
+ "<http://gnu.org/licenses/gpl.html>");
+#else
+ p = ("License GPLv2+: GNU GPL version 2 or later "
+ "<http://gnu.org/licenses/>");
+#endif
+ break;
+ case 11: p = "foo"; break;
+ case 13: p = "0.0"; break;
+ case 14: p = ARGPARSE_CRIGHT_STR; break;
+ case 15: p =
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\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 "
+ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
+" 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 software. If not, see <http://www.gnu.org/licenses/>.\n";
+ break;
+ case 40: /* short and long usage */
+ case 41: p = ""; break;
+ }
+
+ return p;
+}
+
+
+/* Set the usage handler. This function is basically a constructor. */
+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[] = {
+ ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
+ ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
+ "was wir eingegeben haben")),
+ ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
+ ARGPARSE_s_s('o', "output", 0 ),
+ ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
+ /* Note that on a non-utf8 terminal the ß might garble the output. */
+ ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
+ ARGPARSE_o_i('m', "my-option", 0),
+ ARGPARSE_s_n(500, "a-long-option", 0 ),
+ ARGPARSE_end()
+ };
+ ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
+ | ARGPARSE_FLAG_MIXED
+ | ARGPARSE_FLAG_ONEDASH) };
+ int i;
+
+ while (arg_parse (&pargs, opts))
+ {
+ switch (pargs.r_opt)
+ {
+ case ARGPARSE_IS_ARG :
+ 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 = ARGPARSE_PRINT_WARNING; break;
+ }
+ }
+ 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 /*TEST*/
+
+/**** bottom of file ****/
diff --git a/src/argparse.h b/src/argparse.h
new file mode 100644
index 0000000..10b838f
--- /dev/null
+++ b/src/argparse.h
@@ -0,0 +1,203 @@
+/* argparse.h - Argument parser for option handling.
+ * Copyright (C) 1998,1999,2000,2001,2006 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 either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_ARGPARSE_H
+#define GNUPG_COMMON_ARGPARSE_H
+
+#include <stdio.h>
+
+typedef struct
+{
+ int *argc; /* Pointer to ARGC (value subject to change). */
+ char ***argv; /* Pointer to ARGV (value subject to change). */
+ unsigned int flags; /* Global flags. May be set prior to calling the
+ parser. The parser may change the value. */
+ int err; /* Print error description for last option.
+ Either 0, ARGPARSE_PRINT_WARNING or
+ ARGPARSE_PRINT_ERROR. */
+
+ int r_opt; /* Returns option code. */
+ int r_type; /* Returns type of option value. */
+ 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;
+ void *iio_list;
+ } internal; /* Private - do not change. */
+} ARGPARSE_ARGS;
+
+typedef struct
+{
+ int short_opt;
+ const char *long_opt;
+ unsigned int flags;
+ const char *description; /* Optional option description. */
+} ARGPARSE_OPTS;
+
+
+/* Global flags (ARGPARSE_ARGS). */
+#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */
+#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return
+ remaining args with R_OPT set to -1. */
+#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */
+#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */
+#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */
+#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */
+#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */
+
+#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */
+
+/* Flags for each option (ARGPARSE_OPTS). The type code may be
+ ORed with the OPT flags. */
+#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */
+#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */
+#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */
+#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */
+#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */
+#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */
+#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */
+#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */
+#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */
+
+#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */
+
+/* A set of macros to make option definitions easier to read. */
+#define ARGPARSE_x(s,l,t,f,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) }
+
+#define ARGPARSE_s(s,l,t,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t, (d) }
+#define ARGPARSE_s_n(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_NONE, (d) }
+#define ARGPARSE_s_i(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_INT, (d) }
+#define ARGPARSE_s_s(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_STRING, (d) }
+#define ARGPARSE_s_l(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_LONG, (d) }
+#define ARGPARSE_s_u(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_ULONG, (d) }
+
+#define ARGPARSE_o(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) }
+
+#define ARGPARSE_p(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_op(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_c(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) }
+
+#define ARGPARSE_ignore(s,l) \
+ { (s), (l), (ARGPARSE_OPT_IGNORE), "@" }
+
+#define ARGPARSE_group(s,d) \
+ { (s), NULL, 0, (d) }
+
+#define ARGPARSE_end() { 0, NULL, 0, NULL }
+
+
+/* Other constants. */
+#define ARGPARSE_PRINT_WARNING 1
+#define ARGPARSE_PRINT_ERROR 2
+
+
+/* Error values. */
+#define ARGPARSE_IS_ARG (-1)
+#define ARGPARSE_INVALID_OPTION (-2)
+#define ARGPARSE_MISSING_ARG (-3)
+#define ARGPARSE_KEYWORD_TOO_LONG (-4)
+#define ARGPARSE_READ_ERROR (-5)
+#define ARGPARSE_UNEXPECTED_ARG (-6)
+#define ARGPARSE_INVALID_COMMAND (-7)
+#define ARGPARSE_AMBIGUOUS_OPTION (-8)
+#define ARGPARSE_AMBIGUOUS_COMMAND (-9)
+#define ARGPARSE_INVALID_ALIAS (-10)
+#define ARGPARSE_OUT_OF_CORE (-11)
+#define ARGPARSE_INVALID_ARG (-12)
+
+
+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 ));
+void argparse_register_outfnc (int (*fnc)(int, const char *));
+
+#endif /*GNUPG_COMMON_ARGPARSE_H*/
diff --git a/src/assuan-support.c b/src/assuan-support.c
index 745d2aa..2cfdc35 100644
--- a/src/assuan-support.c
+++ b/src/assuan-support.c
@@ -26,6 +26,10 @@ int
_gpgme_assuan_log_cb (assuan_context_t ctx, void *hook,
unsigned int cat, const char *msg)
{
+ (void)ctx;
+ (void)hook;
+ (void)cat;
+
if (msg == NULL)
return 1;
@@ -49,6 +53,8 @@ my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
int res;
int gfds[2];
+ (void)ctx;
+
res = _gpgme_io_pipe (gfds, inherit_idx);
/* For now... */
@@ -64,6 +70,7 @@ my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
static int
my_close (assuan_context_t ctx, assuan_fd_t fd)
{
+ (void)ctx;
return _gpgme_io_close ((int) fd);
}
@@ -71,6 +78,7 @@ my_close (assuan_context_t ctx, assuan_fd_t fd)
static gpgme_ssize_t
my_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
{
+ (void)ctx;
return _gpgme_io_read ((int) fd, buffer, size);
}
@@ -78,6 +86,7 @@ my_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
static gpgme_ssize_t
my_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size)
{
+ (void)ctx;
return _gpgme_io_write ((int) fd, buffer, size);
}
@@ -86,6 +95,7 @@ static int
my_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
+ (void)ctx;
#ifdef HAVE_W32_SYSTEM
gpg_err_set_errno (ENOSYS);
return -1;
@@ -100,6 +110,7 @@ static int
my_sendmsg (assuan_context_t ctx, assuan_fd_t fd, const assuan_msghdr_t msg,
int flags)
{
+ (void)ctx;
#ifdef HAVE_W32_SYSTEM
gpg_err_set_errno (ENOSYS);
return -1;
@@ -124,6 +135,9 @@ my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
struct spawn_fd_item_s *fd_items;
int i;
+ (void)ctx;
+ (void)flags;
+
assert (name);
if (! name)
@@ -194,6 +208,7 @@ static pid_t
my_waitpid (assuan_context_t ctx, pid_t pid,
int nowait, int *status, int options)
{
+ (void)ctx;
#ifdef HAVE_W32_SYSTEM
CloseHandle ((HANDLE) pid);
#else
@@ -226,6 +241,7 @@ my_socketpair (assuan_context_t ctx, int namespace, int style,
static int
my_socket (assuan_context_t ctx, int namespace, int style, int protocol)
{
+ (void)ctx;
return _gpgme_io_socket (namespace, style, protocol);
}
@@ -234,6 +250,7 @@ static int
my_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
socklen_t length)
{
+ (void)ctx;
return _gpgme_io_connect (sock, addr, length);
}
diff --git a/src/b64dec.c b/src/b64dec.c
new file mode 100644
index 0000000..7965a30
--- /dev/null
+++ b/src/b64dec.c
@@ -0,0 +1,251 @@
+/* b64dec.c - Simple Base64 decoder.
+ * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2008, 2011, 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "gpgme.h"
+#include "util.h"
+
+
+/* The reverse base-64 list used for base-64 decoding. */
+static unsigned char const asctobin[128] =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+enum decoder_states
+ {
+ s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
+ s_b64_0, s_b64_1, s_b64_2, s_b64_3,
+ s_waitendtitle, s_waitend
+ };
+
+
+
+/* Initialize the context for the base64 decoder. If TITLE is NULL a
+ plain base64 decoding is done. If it is the empty string the
+ decoder will skip everything until a "-----BEGIN " line has been
+ seen, decoding ends at a "----END " line. */
+gpg_error_t
+_gpgme_b64dec_start (struct b64state *state, const char *title)
+{
+ memset (state, 0, sizeof *state);
+ if (title)
+ {
+ state->title = strdup (title);
+ if (!state->title)
+ state->lasterr = gpg_error_from_syserror ();
+ else
+ state->idx = s_init;
+ }
+ else
+ state->idx = s_b64_0;
+ return state->lasterr;
+}
+
+
+/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
+ new length of the buffer at R_NBYTES. */
+gpg_error_t
+_gpgme_b64dec_proc (struct b64state *state, void *buffer, size_t length,
+ size_t *r_nbytes)
+{
+ enum decoder_states ds = state->idx;
+ unsigned char val = state->radbuf[0];
+ int pos = state->quad_count;
+ char *d, *s;
+
+ if (state->lasterr)
+ return state->lasterr;
+
+ if (state->stop_seen)
+ {
+ *r_nbytes = 0;
+ state->lasterr = gpg_error (GPG_ERR_EOF);
+ free (state->title);
+ state->title = NULL;
+ return state->lasterr;
+ }
+
+ for (s=d=buffer; length && !state->stop_seen; length--, s++)
+ {
+ again:
+ switch (ds)
+ {
+ case s_idle:
+ if (*s == '\n')
+ {
+ ds = s_lfseen;
+ pos = 0;
+ }
+ break;
+ case s_init:
+ ds = s_lfseen;
+ case s_lfseen:
+ if (*s != "-----BEGIN "[pos])
+ {
+ ds = s_idle;
+ goto again;
+ }
+ else if (pos == 10)
+ {
+ pos = 0;
+ ds = s_beginseen;
+ }
+ else
+ pos++;
+ break;
+ case s_beginseen:
+ if (*s != "PGP "[pos])
+ ds = s_begin; /* Not a PGP armor. */
+ else if (pos == 3)
+ ds = s_waitheader;
+ else
+ pos++;
+ break;
+ case s_waitheader:
+ if (*s == '\n')
+ ds = s_waitblank;
+ break;
+ case s_waitblank:
+ if (*s == '\n')
+ ds = s_b64_0; /* blank line found. */
+ else if (*s == ' ' || *s == '\r' || *s == '\t')
+ ; /* Ignore spaces. */
+ else
+ {
+ /* Armor header line. Note that we don't care that our
+ * FSM accepts a header prefixed with spaces. */
+ ds = s_waitheader; /* Wait for next header. */
+ }
+ break;
+ case s_begin:
+ if (*s == '\n')
+ ds = s_b64_0;
+ break;
+ case s_b64_0:
+ case s_b64_1:
+ case s_b64_2:
+ case s_b64_3:
+ {
+ int c;
+
+ if (*s == '-' && state->title)
+ {
+ /* Not a valid Base64 character: assume end
+ header. */
+ ds = s_waitend;
+ }
+ else if (*s == '=')
+ {
+ /* Pad character: stop */
+ if (ds == s_b64_1)
+ *d++ = val;
+ ds = state->title? s_waitendtitle : s_waitend;
+ }
+ else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
+ ; /* Skip white spaces. */
+ else if ( (*s & 0x80)
+ || (c = asctobin[*(unsigned char *)s]) == 255)
+ {
+ /* Skip invalid encodings. */
+ state->invalid_encoding = 1;
+ }
+ else if (ds == s_b64_0)
+ {
+ val = c << 2;
+ ds = s_b64_1;
+ }
+ else if (ds == s_b64_1)
+ {
+ val |= (c>>4)&3;
+ *d++ = val;
+ val = (c<<4)&0xf0;
+ ds = s_b64_2;
+ }
+ else if (ds == s_b64_2)
+ {
+ val |= (c>>2)&15;
+ *d++ = val;
+ val = (c<<6)&0xc0;
+ ds = s_b64_3;
+ }
+ else
+ {
+ val |= c&0x3f;
+ *d++ = val;
+ ds = s_b64_0;
+ }
+ }
+ break;
+ case s_waitendtitle:
+ if (*s == '-')
+ ds = s_waitend;
+ break;
+ case s_waitend:
+ if ( *s == '\n')
+ state->stop_seen = 1;
+ break;
+ default:
+ assert (!"invalid state");
+ }
+ }
+
+
+ state->idx = ds;
+ state->radbuf[0] = val;
+ state->quad_count = pos;
+ *r_nbytes = (d -(char*) buffer);
+ return 0;
+}
+
+
+/* This function needs to be called before releasing the decoder
+ state. It may return an error code in case an encoding error has
+ been found during decoding. */
+gpg_error_t
+_gpgme_b64dec_finish (struct b64state *state)
+{
+ if (state->lasterr)
+ return state->lasterr;
+
+ free (state->title);
+ state->title = NULL;
+ return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
+}
diff --git a/src/context.h b/src/context.h
index 757d9b4..4b12c3b 100644
--- a/src/context.h
+++ b/src/context.h
@@ -38,7 +38,7 @@ typedef enum
OPDATA_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE,
OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT,
- OPDATA_PASSWD, OPDATA_EXPORT
+ OPDATA_PASSWD, OPDATA_EXPORT, OPDATA_KEYSIGN, OPDATA_TOFU_POLICY
} ctx_op_data_id_t;
@@ -101,6 +101,15 @@ struct gpgme_context
/* True if offline mode should be used. */
unsigned int offline : 1;
+ /* True if a status callback shall be called for nearly all status
+ * lines. */
+ unsigned int full_status : 1;
+
+ /* The Tofu info has a human readable string which is presented to
+ * the user in a directly usable format. By enabling this flag the
+ * unmodified string, as received form gpg, will be returned. */
+ unsigned int raw_description : 1;
+
/* Flags for keylist mode. */
gpgme_keylist_mode_t keylist_mode;
diff --git a/src/conversion.c b/src/conversion.c
index d04a6be..3df8fe5 100644
--- a/src/conversion.c
+++ b/src/conversion.c
@@ -317,6 +317,72 @@ _gpgme_encode_percent_string (const char *src, char **destp, size_t len)
}
+/* Split a string into space delimited fields and remove leading and
+ * trailing spaces from each field. A pointer to the each field is
+ * stored in ARRAY. Stop splitting at ARRAYSIZE fields. The function
+ * modifies STRING. The number of parsed fields is returned.
+ */
+int
+_gpgme_split_fields (char *string, char **array, int arraysize)
+{
+ int n = 0;
+ char *p, *pend;
+
+ for (p = string; *p == ' '; p++)
+ ;
+ do
+ {
+ if (n == arraysize)
+ break;
+ array[n++] = p;
+ pend = strchr (p, ' ');
+ if (!pend)
+ break;
+ *pend++ = 0;
+ for (p = pend; *p == ' '; p++)
+ ;
+ }
+ while (*p);
+
+ return n;
+}
+
+/* Convert the field STRING into an unsigned long value. Check for
+ * trailing garbage. */
+gpgme_error_t
+_gpgme_strtoul_field (const char *string, unsigned long *result)
+{
+ char *endp;
+
+ gpg_err_set_errno (0);
+ *result = strtoul (string, &endp, 0);
+ if (errno)
+ return gpg_error_from_syserror ();
+ if (endp == string || *endp)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ return 0;
+}
+
+
+/* Convert STRING into an offset value. Note that this functions only
+ * allows for a base-10 length. This function is similar to atoi()
+ * and thus there is no error checking. */
+gpgme_off_t
+_gpgme_string_to_off (const char *string)
+{
+ gpgme_off_t value = 0;
+
+ while (*string == ' ' || *string == '\t')
+ string++;
+ for (; *string >= '0' && *string <= '9'; string++)
+ {
+ value *= 10;
+ value += atoi_1 (string);
+ }
+ return value;
+}
+
+
#ifdef HAVE_W32_SYSTEM
static time_t
_gpgme_timegm (struct tm *tm)
@@ -427,6 +493,7 @@ _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol)
case 18: algo = GPGME_PK_ECDH; break;
case 19: algo = GPGME_PK_ECDSA; break;
case 20: break;
+ case 22: algo = GPGME_PK_EDDSA; break;
default: algo = 0; break; /* Unknown. */
}
}
diff --git a/src/data-compat.c b/src/data-compat.c
index 99827f1..5c7d543 100644
--- a/src/data-compat.c
+++ b/src/data-compat.c
@@ -128,7 +128,7 @@ gpgme_data_new_from_file (gpgme_data_t *r_dh, const char *fname, int copy)
#else
gpgme_error_t err;
struct stat statbuf;
- TRACE_BEG3 (DEBUG_DATA, "gpgme_data_new_from_filepart", r_dh,
+ TRACE_BEG3 (DEBUG_DATA, "gpgme_data_new_from_file", r_dh,
"file_name=%s, copy=%i (%s)", fname, copy, copy ? "yes" : "no");
if (!fname || !copy)
@@ -146,7 +146,7 @@ gpgme_data_new_from_file (gpgme_data_t *r_dh, const char *fname, int copy)
static int
gpgme_error_to_errno (gpgme_error_t err)
{
- int res = gpg_err_code_to_errno (err);
+ int res = gpg_err_code_to_errno (gpg_err_code (err));
if (!err)
{
@@ -187,7 +187,7 @@ old_user_read (gpgme_data_t dh, void *buffer, size_t size)
buffer, size, &amt);
if (err)
return TRACE_SYSRES (gpgme_error_to_errno (err));
- return TRACE_SYSRES (amt);
+ return TRACE_SYSRES ((gpgme_ssize_t)amt);
}
diff --git a/src/data-identify.c b/src/data-identify.c
index 9600633..a5da7f5 100644
--- a/src/data-identify.c
+++ b/src/data-identify.c
@@ -1,5 +1,5 @@
/* data-identify.c - Try to identify the data
- Copyright (C) 2013 g10 Code GmbH
+ Copyright (C) 2013, 2016 g10 Code GmbH
This file is part of GPGME.
@@ -29,17 +29,283 @@
#include "util.h"
#include "parsetlv.h"
+
/* The size of the sample data we take for detection. */
#define SAMPLE_SIZE 2048
+/* OpenPGP packet types. */
+enum
+ {
+ PKT_NONE = 0,
+ PKT_PUBKEY_ENC = 1, /* Public key encrypted packet. */
+ PKT_SIGNATURE = 2, /* Secret key encrypted packet. */
+ PKT_SYMKEY_ENC = 3, /* Session key packet. */
+ PKT_ONEPASS_SIG = 4, /* One pass sig packet. */
+ PKT_SECRET_KEY = 5, /* Secret key. */
+ PKT_PUBLIC_KEY = 6, /* Public key. */
+ PKT_SECRET_SUBKEY = 7, /* Secret subkey. */
+ PKT_COMPRESSED = 8, /* Compressed data packet. */
+ PKT_ENCRYPTED = 9, /* Conventional encrypted data. */
+ PKT_MARKER = 10, /* Marker packet. */
+ PKT_PLAINTEXT = 11, /* Literal data packet. */
+ PKT_RING_TRUST = 12, /* Keyring trust packet. */
+ PKT_USER_ID = 13, /* User id packet. */
+ PKT_PUBLIC_SUBKEY = 14, /* Public subkey. */
+ PKT_OLD_COMMENT = 16, /* Comment packet from an OpenPGP draft. */
+ PKT_ATTRIBUTE = 17, /* PGP's attribute packet. */
+ PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */
+ PKT_MDC = 19, /* Manipulation detection code packet. */
+ };
+
+
+static inline unsigned long
+buf32_to_ulong (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((unsigned long)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+
+/* Parse the next openpgp packet. This function assumes a valid
+ * OpenPGP packet at the address pointed to by BUFPTR which has a
+ * maximum length as stored at BUFLEN. Return the header information
+ * of that packet and advance the pointer stored at BUFPTR to the next
+ * packet; also adjust the length stored at BUFLEN to match the
+ * remaining bytes. If there are no more packets, store NULL at
+ * BUFPTR. Return an non-zero error code on failure or the following
+ * data on success:
+ *
+ * R_PKTTYPE = The packet type.
+ * R_NTOTAL = The total number of bytes of this packet
+ *
+ * If GPG_ERR_TRUNCATED is returned, a packet type is anyway stored at
+ * R_PKTTYPE but R_NOTAL won't have a usable value,
+ */
+static gpg_error_t
+next_openpgp_packet (unsigned char const **bufptr, size_t *buflen,
+ int *r_pkttype, size_t *r_ntotal)
+{
+ const unsigned char *buf = *bufptr;
+ size_t len = *buflen;
+ int c, ctb, pkttype;
+ unsigned long pktlen;
+
+ if (!len)
+ return gpg_error (GPG_ERR_NO_DATA);
+
+ /* First some blacklisting. */
+ if (len >= 4 && !memcmp (buf, "\x89PNG", 4))
+ return gpg_error (GPG_ERR_INV_PACKET); /* This is a PNG file. */
+
+ /* Start parsing. */
+ ctb = *buf++; len--;
+ if ( !(ctb & 0x80) )
+ return gpg_error (GPG_ERR_INV_PACKET); /* Invalid CTB. */
+
+ if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
+ {
+ pkttype = (ctb & 0x3f);
+ if (!len)
+ return gpg_error (GPG_ERR_INV_PACKET); /* No 1st length byte. */
+ c = *buf++; len--;
+ if ( c < 192 )
+ pktlen = c;
+ else if ( c < 224 )
+ {
+ pktlen = (c - 192) * 256;
+ if (!len)
+ return gpg_error (GPG_ERR_INV_PACKET); /* No 2nd length byte. */
+ c = *buf++; len--;
+ pktlen += c + 192;
+ }
+ else if (c == 255)
+ {
+ if (len < 4)
+ return gpg_error (GPG_ERR_INV_PACKET); /* No length bytes. */
+ pktlen = buf32_to_ulong (buf);
+ buf += 4;
+ len -= 4;
+ }
+ else /* Partial length encoding. */
+ {
+ pktlen = 0;
+ }
+ }
+ else /* Old style CTB. */
+ {
+ int lenbytes;
+
+ pktlen = 0;
+ pkttype = (ctb>>2)&0xf;
+ lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
+ if (len < lenbytes)
+ return gpg_error (GPG_ERR_INV_PACKET); /* Not enough length bytes. */
+ for (; lenbytes; lenbytes--)
+ {
+ pktlen <<= 8;
+ pktlen |= *buf++; len--;
+ }
+ }
+
+ /* Do some basic sanity check. */
+ switch (pkttype)
+ {
+ case PKT_PUBKEY_ENC:
+ case PKT_SIGNATURE:
+ case PKT_SYMKEY_ENC:
+ case PKT_ONEPASS_SIG:
+ case PKT_SECRET_KEY:
+ case PKT_PUBLIC_KEY:
+ case PKT_SECRET_SUBKEY:
+ case PKT_COMPRESSED:
+ case PKT_ENCRYPTED:
+ case PKT_MARKER:
+ case PKT_PLAINTEXT:
+ case PKT_RING_TRUST:
+ case PKT_USER_ID:
+ case PKT_PUBLIC_SUBKEY:
+ case PKT_OLD_COMMENT:
+ case PKT_ATTRIBUTE:
+ case PKT_ENCRYPTED_MDC:
+ case PKT_MDC:
+ break; /* Okay these are allowed packets. */
+ default:
+ return gpg_error (GPG_ERR_UNEXPECTED);
+ }
+
+ if (pktlen > len)
+ {
+ /* Packet length header too long. This is possible because we
+ * may have only a truncated image. */
+ *r_pkttype = pkttype;
+ *r_ntotal = 0;
+ *bufptr = NULL;
+ return gpg_error (GPG_ERR_TRUNCATED);
+ }
+
+ *r_pkttype = pkttype;
+ *r_ntotal = (buf - *bufptr) + pktlen;
+
+ *bufptr = buf + pktlen;
+ *buflen = len - pktlen;
+ if (!*buflen)
+ *bufptr = NULL;
+
+ return 0;
+}
+
+
+/* Detection of PGP binary data. This function parses an OpenPGP
+ * message. This parser is robust enough to work on a truncated
+ * version. Returns a GPGME_DATA_TYPE_. */
+static gpgme_data_type_t
+pgp_binary_detection (const void *image_arg, size_t imagelen)
+{
+ gpg_error_t err = 0;
+ const unsigned char *image = image_arg;
+ size_t n;
+ int pkttype;
+ int anypacket = 0;
+ int allsignatures = 0;
+
+ while (!err && image)
+ {
+ err = next_openpgp_packet (&image, &imagelen, &pkttype, &n);
+ if (gpg_err_code (err) == GPG_ERR_TRUNCATED)
+ ;
+ else if (err)
+ break;
+
+ /* Skip all leading marker packets. */
+ if (!anypacket && pkttype == PKT_MARKER)
+ continue;
+
+ if (pkttype == PKT_SIGNATURE)
+ {
+ if (!anypacket)
+ allsignatures = 1;
+ }
+ else
+ allsignatures = 0;
+
+ switch (pkttype)
+ {
+ case PKT_SIGNATURE:
+ break; /* We decide later. */
+
+ case PKT_PLAINTEXT:
+ /* Old style signature format: {sig}+,plaintext */
+ if (allsignatures)
+ return GPGME_DATA_TYPE_PGP_SIGNED;
+ break;
+
+ case PKT_ONEPASS_SIG:
+ return GPGME_DATA_TYPE_PGP_SIGNED;
+
+ case PKT_SECRET_KEY:
+ case PKT_PUBLIC_KEY:
+ return GPGME_DATA_TYPE_PGP_KEY;
+
+ case PKT_SECRET_SUBKEY:
+ case PKT_PUBLIC_SUBKEY:
+ return GPGME_DATA_TYPE_PGP_OTHER;
+ case PKT_PUBKEY_ENC:
+ case PKT_SYMKEY_ENC:
+ return GPGME_DATA_TYPE_PGP_ENCRYPTED;
+
+ case PKT_COMPRESSED:
+ /* If this is the first packet we assume that that a signed
+ * packet follows. We do not want to uncompress it here due
+ * to the need of a lot of code and the potentail DoS. */
+ if (!anypacket)
+ return GPGME_DATA_TYPE_PGP_SIGNED;
+ return GPGME_DATA_TYPE_PGP_OTHER;
+
+ default:
+ return GPGME_DATA_TYPE_PGP_OTHER;
+ }
+ anypacket = 1;
+ }
+
+ if (allsignatures)
+ return GPGME_DATA_TYPE_PGP_SIGNATURE;
+
+ return GPGME_DATA_TYPE_UNKNOWN;
+}
+
+
+/* This is probably an armored "PGP MESSAGE" which can encode
+ * different PGP data types. STRING is modified after a call to this
+ * fucntion. */
+static gpgme_data_type_t
+inspect_pgp_message (char *string)
+{
+ struct b64state state;
+ size_t nbytes;
+
+ if (_gpgme_b64dec_start (&state, ""))
+ return GPGME_DATA_TYPE_INVALID; /* oops */
+
+ if (_gpgme_b64dec_proc (&state, string, strlen (string), &nbytes))
+ {
+ _gpgme_b64dec_finish (&state);
+ return GPGME_DATA_TYPE_UNKNOWN; /* bad encoding etc. */
+ }
+ _gpgme_b64dec_finish (&state);
+ string[nbytes] = 0; /* Better append a Nul. */
+
+ return pgp_binary_detection (string, nbytes);
+}
+
/* Note that DATA may be binary but a final nul is required so that
string operations will find a terminator.
Returns: GPGME_DATA_TYPE_xxxx */
static gpgme_data_type_t
-basic_detection (const char *data, size_t datalen)
+basic_detection (char *data, size_t datalen)
{
tlvinfo_t ti;
const char *s;
@@ -167,7 +433,7 @@ basic_detection (const char *data, size_t datalen)
at all defined and in any case it is uncommon. Thus we don't
do any further plausibility checks but stupidly assume no CMS
armored data will follow. */
- return GPGME_DATA_TYPE_UNKNOWN;
+ return pgp_binary_detection (data, datalen);
}
/* Now check whether there are armor lines. */
@@ -182,7 +448,7 @@ basic_detection (const char *data, size_t datalen)
if (!strncmp (s+11, "PGP ", 4))
{
if (!strncmp (s+15, "SIGNATURE", 9))
- return GPGME_DATA_TYPE_PGP_SIGNED;
+ return GPGME_DATA_TYPE_PGP_SIGNATURE;
if (!strncmp (s+15, "SIGNED MESSAGE", 14))
return GPGME_DATA_TYPE_PGP_SIGNED;
if (!strncmp (s+15, "PUBLIC KEY BLOCK", 16))
@@ -193,7 +459,8 @@ basic_detection (const char *data, size_t datalen)
return GPGME_DATA_TYPE_PGP_KEY;
if (!strncmp (s+15, "ARMORED FILE", 12))
return GPGME_DATA_TYPE_UNKNOWN;
- return GPGME_DATA_TYPE_PGP_OTHER; /* PGP MESSAGE */
+
+ return inspect_pgp_message (data);
}
if (!strncmp (s+11, "CERTIFICATE", 11))
return GPGME_DATA_TYPE_X509_CERT;
@@ -222,6 +489,8 @@ gpgme_data_identify (gpgme_data_t dh, int reserved)
int n;
gpgme_off_t off;
+ (void)reserved;
+
/* Check whether we can seek the data object. */
off = gpgme_data_seek (dh, 0, SEEK_CUR);
if (off == (gpgme_off_t)(-1))
diff --git a/src/data-mem.c b/src/data-mem.c
index e06a920..a498b82 100644
--- a/src/data-mem.c
+++ b/src/data-mem.c
@@ -271,7 +271,8 @@ gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len)
}
-/* Release the memory returned by gpgme_data_release_and_get_mem(). */
+/* Release the memory returned by gpgme_data_release_and_get_mem() and
+ some other functions. */
void
gpgme_free (void *buffer)
{
diff --git a/src/data.c b/src/data.c
index 7123a82..6964246 100644
--- a/src/data.c
+++ b/src/data.c
@@ -193,7 +193,7 @@ gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
"encoding=%i", enc);
if (!dh)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (enc < 0 || enc > GPGME_DATA_ENCODING_URL0)
+ if (enc < 0 || enc > GPGME_DATA_ENCODING_MIME)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
dh->encoding = enc;
return TRACE_ERR (0);
@@ -243,6 +243,28 @@ gpgme_data_get_file_name (gpgme_data_t dh)
return dh->file_name;
}
+
+/* Set a flag for the data object DH. See the manual for details. */
+gpg_error_t
+gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
+{
+ TRACE_BEG2 (DEBUG_DATA, "gpgme_data_set_flag", dh,
+ "%s=%s", name, value);
+
+ if (!dh)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+ if (!strcmp (name, "size-hint"))
+ {
+ dh->size_hint= value? _gpgme_string_to_off (value) : 0;
+ }
+ else
+ return gpg_error (GPG_ERR_UNKNOWN_NAME);
+
+ return 0;
+}
+
+
/* Functions to support the wait interface. */
@@ -334,3 +356,11 @@ _gpgme_data_get_fd (gpgme_data_t dh)
return -1;
return (*dh->cbs->get_fd) (dh);
}
+
+
+/* Get the size-hint value for DH or 0 if not available. */
+gpgme_off_t
+_gpgme_data_get_size_hint (gpgme_data_t dh)
+{
+ return dh ? dh->size_hint : 0;
+}
diff --git a/src/data.h b/src/data.h
index 3d404af..0a15b61 100644
--- a/src/data.h
+++ b/src/data.h
@@ -89,6 +89,9 @@ struct gpgme_data
/* File name of the data object. */
char *file_name;
+ /* Hint on the to be expected toatl size of the data. */
+ gpgme_off_t size_hint;
+
union
{
/* For gpgme_data_new_from_fd. */
@@ -134,4 +137,7 @@ void _gpgme_data_release (gpgme_data_t dh);
return -1. */
int _gpgme_data_get_fd (gpgme_data_t dh);
+/* Get the size-hint value for DH or 0 if not available. */
+gpgme_off_t _gpgme_data_get_size_hint (gpgme_data_t dh);
+
#endif /* DATA_H */
diff --git a/src/decrypt.c b/src/decrypt.c
index 4db68a1..51e4292 100644
--- a/src/decrypt.c
+++ b/src/decrypt.c
@@ -303,7 +303,7 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
break;
case GPGME_STATUS_INQUIRE_MAXLEN:
- if (ctx->status_cb)
+ if (ctx->status_cb && !ctx->full_status)
{
err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
if (err)
diff --git a/src/delete.c b/src/delete.c
index 37e54f8..fc99aac 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -33,6 +33,8 @@
static gpgme_error_t
delete_status_handler (void *priv, gpgme_status_code_t code, char *args)
{
+ (void)priv;
+
if (code == GPGME_STATUS_DELETE_PROBLEM)
{
enum delete_problem
@@ -64,8 +66,40 @@ delete_status_handler (void *priv, gpgme_status_code_t code, char *args)
case DELETE_Ambiguous_Specification:
return gpg_error (GPG_ERR_AMBIGUOUS_NAME);
- default:
- return gpg_error (GPG_ERR_GENERAL);
+ }
+
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+ else if (code == GPGME_STATUS_ERROR)
+ {
+ /* Some error stati are informational, so we don't return an
+ error code if we are not ready to process this status. */
+ gpgme_error_t err;
+ char *where = strchr (args, ' ');
+ char *which;
+
+ if (where)
+ {
+ *where = '\0';
+ which = where + 1;
+
+ where = strchr (which, ' ');
+ if (where)
+ *where = '\0';
+
+ where = args;
+ }
+ else
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+ err = atoi (which);
+
+ if (!strcmp (where, "delete_key.secret")
+ && (gpg_err_code (err) == GPG_ERR_CANCELED
+ || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED))
+ {
+ /* This indicates a user cancellation on the confirmation dialog. */
+ return gpg_error (gpg_err_code (err));
}
}
return 0;
diff --git a/src/dirinfo.c b/src/dirinfo.c
index 8824c9a..b24a8a0 100644
--- a/src/dirinfo.c
+++ b/src/dirinfo.c
@@ -37,12 +37,20 @@ DEFINE_STATIC_LOCK (dirinfo_lock);
enum
{
WANT_HOMEDIR,
+ WANT_SYSCONFDIR,
+ WANT_BINDIR,
+ WANT_LIBEXECDIR,
+ WANT_LIBDIR,
+ WANT_DATADIR,
+ WANT_LOCALEDIR,
WANT_AGENT_SOCKET,
+ WANT_AGENT_SSH_SOCKET,
+ WANT_DIRMNGR_SOCKET,
+ WANT_UISRV_SOCKET,
WANT_GPGCONF_NAME,
WANT_GPG_NAME,
WANT_GPGSM_NAME,
WANT_G13_NAME,
- WANT_UISRV_SOCKET,
WANT_GPG_ONE_MODE
};
@@ -51,12 +59,20 @@ static struct {
int valid; /* Cached information is valid. */
int disable_gpgconf;
char *homedir;
+ char *sysconfdir;
+ char *bindir;
+ char *libexecdir;
+ char *libdir;
+ char *datadir;
+ char *localedir;
char *agent_socket;
+ char *agent_ssh_socket;
+ char *dirmngr_socket;
+ char *uisrv_socket;
char *gpgconf_name;
char *gpg_name;
char *gpgsm_name;
char *g13_name;
- char *uisrv_socket;
int gpg_one_mode; /* System is in gpg1 mode. */
} dirinfo;
@@ -70,6 +86,15 @@ _gpgme_dirinfo_disable_gpgconf (void)
}
+/* Return the length of the directory part including the trailing
+ * slash of NAME. */
+static size_t
+dirname_len (const char *name)
+{
+ return _gpgme_get_basename (name) - name;
+}
+
+
/* Parse the output of "gpgconf --list-dirs". This function expects
that DIRINFO_LOCK is held by the caller. If COMPONENTS is set, the
output of --list-components is expected. */
@@ -77,6 +102,7 @@ static void
parse_output (char *line, int components)
{
char *value, *p;
+ size_t n;
value = strchr (line, ':');
if (!value)
@@ -110,22 +136,41 @@ parse_output (char *line, int components)
else
{
if (!strcmp (line, "homedir") && !dirinfo.homedir)
+ dirinfo.homedir = strdup (value);
+ else if (!strcmp (line, "sysconfdir") && !dirinfo.sysconfdir)
+ dirinfo.sysconfdir = strdup (value);
+ else if (!strcmp (line, "bindir") && !dirinfo.bindir)
+ dirinfo.bindir = strdup (value);
+ else if (!strcmp (line, "libexecdir") && !dirinfo.libexecdir)
+ dirinfo.libexecdir = strdup (value);
+ else if (!strcmp (line, "libdir") && !dirinfo.libdir)
+ dirinfo.libdir = strdup (value);
+ else if (!strcmp (line, "datadir") && !dirinfo.datadir)
+ dirinfo.datadir = strdup (value);
+ else if (!strcmp (line, "localedir") && !dirinfo.localedir)
+ dirinfo.localedir = strdup (value);
+ else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
{
const char name[] = "S.uiserver";
+ char *buffer;
- dirinfo.homedir = strdup (value);
- if (dirinfo.homedir)
+ dirinfo.agent_socket = strdup (value);
+ if (dirinfo.agent_socket)
{
- dirinfo.uisrv_socket = malloc (strlen (dirinfo
- .homedir)
- + 1 + strlen (name) + 1);
- if (dirinfo.uisrv_socket)
- strcpy (stpcpy (stpcpy (dirinfo.uisrv_socket, dirinfo.homedir),
- DIRSEP_S), name);
+ n = dirname_len (dirinfo.agent_socket);
+ buffer = malloc (n + strlen (name) + 1);
+ if (buffer)
+ {
+ strncpy (buffer, dirinfo.agent_socket, n);
+ strcpy (buffer + n, name);
+ dirinfo.uisrv_socket = buffer;
+ }
}
}
- else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
- dirinfo.agent_socket = strdup (value);
+ else if (!strcmp (line, "dirmngr-socket") && !dirinfo.dirmngr_socket)
+ dirinfo.dirmngr_socket = strdup (value);
+ else if (!strcmp (line, "agent-ssh-socket") && !dirinfo.agent_ssh_socket)
+ dirinfo.agent_ssh_socket = strdup (value);
}
}
@@ -148,7 +193,7 @@ read_gpgconf_dirs (const char *pgmname, int components)
char *mark = NULL;
argv[0] = (char *)pgmname;
- argv[1] = components? "--list-components" : "--list-dirs";
+ argv[1] = (char*)(components? "--list-components" : "--list-dirs");
argv[2] = NULL;
if (_gpgme_io_pipe (rp, 1) < 0)
@@ -260,14 +305,28 @@ get_gpgconf_item (int what)
if (dirinfo.agent_socket)
_gpgme_debug (DEBUG_INIT, "gpgme-dinfo: agent='%s'\n",
dirinfo.agent_socket);
+ if (dirinfo.agent_ssh_socket)
+ _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: ssh='%s'\n",
+ dirinfo.agent_ssh_socket);
+ if (dirinfo.dirmngr_socket)
+ _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: dirmngr='%s'\n",
+ dirinfo.dirmngr_socket);
if (dirinfo.uisrv_socket)
_gpgme_debug (DEBUG_INIT, "gpgme-dinfo: uisrv='%s'\n",
dirinfo.uisrv_socket);
}
switch (what)
{
- case WANT_HOMEDIR: result = dirinfo.homedir; break;
+ case WANT_HOMEDIR: result = dirinfo.homedir; break;
+ case WANT_SYSCONFDIR: result = dirinfo.sysconfdir; break;
+ case WANT_BINDIR: result = dirinfo.bindir; break;
+ case WANT_LIBEXECDIR: result = dirinfo.libexecdir; break;
+ case WANT_LIBDIR: result = dirinfo.libdir; break;
+ case WANT_DATADIR: result = dirinfo.datadir; break;
+ case WANT_LOCALEDIR: result = dirinfo.localedir; break;
case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
+ case WANT_AGENT_SSH_SOCKET: result = dirinfo.agent_ssh_socket; break;
+ case WANT_DIRMNGR_SOCKET: result = dirinfo.dirmngr_socket; break;
case WANT_GPGCONF_NAME: result = dirinfo.gpgconf_name; break;
case WANT_GPG_NAME: result = dirinfo.gpg_name; break;
case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
@@ -379,6 +438,22 @@ gpgme_get_dirinfo (const char *what)
return get_gpgconf_item (WANT_GPGSM_NAME);
else if (!strcmp (what, "g13-name"))
return get_gpgconf_item (WANT_G13_NAME);
+ else if (!strcmp (what, "agent-ssh-socket"))
+ return get_gpgconf_item (WANT_AGENT_SSH_SOCKET);
+ else if (!strcmp (what, "dirmngr-socket"))
+ return get_gpgconf_item (WANT_DIRMNGR_SOCKET);
+ else if (!strcmp (what, "sysconfdir"))
+ return get_gpgconf_item (WANT_SYSCONFDIR);
+ else if (!strcmp (what, "bindir"))
+ return get_gpgconf_item (WANT_BINDIR);
+ else if (!strcmp (what, "libexecdir"))
+ return get_gpgconf_item (WANT_LIBEXECDIR);
+ else if (!strcmp (what, "libdir"))
+ return get_gpgconf_item (WANT_LIBDIR);
+ else if (!strcmp (what, "datadir"))
+ return get_gpgconf_item (WANT_DATADIR);
+ else if (!strcmp (what, "localedir"))
+ return get_gpgconf_item (WANT_LOCALEDIR);
else
return NULL;
}
diff --git a/src/edit.c b/src/edit.c
index 72fa458..887af73 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -27,12 +27,15 @@
#include "debug.h"
#include "context.h"
#include "ops.h"
+#include "util.h"
+
typedef struct
{
/* The user callback function and its hook value. */
- gpgme_edit_cb_t fnc;
+ gpgme_interact_cb_t fnc;
+ gpgme_edit_cb_t fnc_old;
void *fnc_value;
} *op_data_t;
@@ -58,7 +61,11 @@ edit_status_handler (void *priv, gpgme_status_code_t status, char *args)
if (err)
return err;
- return (*opd->fnc) (opd->fnc_value, status, args, -1);
+ if (opd->fnc_old)
+ return (*opd->fnc_old) (opd->fnc_value, status, args, -1);
+
+ return (*opd->fnc) (opd->fnc_value, _gpgme_status_to_string (status),
+ args, -1);
}
@@ -77,6 +84,8 @@ command_handler (void *priv, gpgme_status_code_t status, const char *args,
if (err)
return err;
}
+ else
+ err = 0;
if (!processed)
{
@@ -88,20 +97,105 @@ command_handler (void *priv, gpgme_status_code_t status, const char *args,
if (err)
return err;
- /* FIXME: We expect the user to handle _all_ status codes.
- Later, we may fix the callback interface to allow the user
- indicate if it processed the status code or not. */
- *processed_r = 1;
+ if (opd->fnc_old)
+ err = (*opd->fnc_old) (opd->fnc_value, status, args, fd);
+ else
+ err = (*opd->fnc) (opd->fnc_value, _gpgme_status_to_string (status),
+ args, fd);
- return (*opd->fnc) (opd->fnc_value, status, args, fd);
+ if (gpg_err_code (err) == GPG_ERR_FALSE)
+ err = 0;
+ else
+ processed = 1;
}
*processed_r = processed;
- return 0;
+ return err;
}
static gpgme_error_t
+interact_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key,
+ unsigned int flags,
+ gpgme_interact_cb_t fnc, void *fnc_value, gpgme_data_t out)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ if (!fnc || !out)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, sizeof (*opd), NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ opd->fnc = fnc;
+ opd->fnc_old = NULL;
+ opd->fnc_value = fnc_value;
+
+ err = _gpgme_engine_set_command_handler (ctx->engine, command_handler,
+ ctx, out);
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, edit_status_handler, ctx);
+
+ return _gpgme_engine_op_edit (ctx->engine,
+ (flags & GPGME_INTERACT_CARD)? 1: 0,
+ key, out, ctx);
+}
+
+
+gpgme_error_t
+gpgme_op_interact_start (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags,
+ gpgme_interact_cb_t fnc, void *fnc_value,
+ gpgme_data_t out)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG5 (DEBUG_CTX, "gpgme_op_interact_start", ctx,
+ "key=%p flags=0x%x fnc=%p fnc_value=%p, out=%p",
+ key, flags,fnc, fnc_value, out);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+ err = interact_start (ctx, 0, key, flags, fnc, fnc_value, out);
+ return err;
+}
+
+
+gpgme_error_t
+gpgme_op_interact (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags,
+ gpgme_interact_cb_t fnc, void *fnc_value,
+ gpgme_data_t out)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG5 (DEBUG_CTX, "gpgme_op_interact", ctx,
+ "key=%p flags=0x%x fnc=%p fnc_value=%p, out=%p",
+ key, flags,fnc, fnc_value, out);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+ err = interact_start (ctx, 1, key, flags, fnc, fnc_value, out);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
+
+
+
+
+/* The deprectated interface. */
+static gpgme_error_t
edit_start (gpgme_ctx_t ctx, int synchronous, int type, gpgme_key_t key,
gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
{
@@ -121,7 +215,8 @@ edit_start (gpgme_ctx_t ctx, int synchronous, int type, gpgme_key_t key,
if (err)
return err;
- opd->fnc = fnc;
+ opd->fnc = NULL;
+ opd->fnc_old = fnc;
opd->fnc_value = fnc_value;
err = _gpgme_engine_set_command_handler (ctx->engine, command_handler,
diff --git a/src/encrypt-sign.c b/src/encrypt-sign.c
index 4f484e9..af6de63 100644
--- a/src/encrypt-sign.c
+++ b/src/encrypt-sign.c
@@ -72,7 +72,7 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
if (err)
return err;
- symmetric = !recp;
+ symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC);
if (!plain)
return gpg_error (GPG_ERR_NO_DATA);
diff --git a/src/encrypt.c b/src/encrypt.c
index 9f5134d..4023654 100644
--- a/src/encrypt.c
+++ b/src/encrypt.c
@@ -39,6 +39,12 @@ typedef struct
/* The error code from a FAILURE status line or 0. */
gpg_error_t failure_code;
+ /* The fingerprint from the last KEY_CONSIDERED status line. */
+ char *kc_fpr;
+
+ /* The flags from the last KEY_CONSIDERED status line. */
+ unsigned int kc_flags;
+
/* A pointer to the next pointer of the last invalid recipient in
the list. This makes appending new invalid recipients painless
while preserving the order. */
@@ -60,6 +66,8 @@ release_op_data (void *hook)
free (invalid_recipient);
invalid_recipient = next;
}
+
+ free (opd->kc_fpr);
}
@@ -128,12 +136,26 @@ _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code,
return opd->failure_code;
break;
+ case GPGME_STATUS_KEY_CONSIDERED:
+ /* This is emitted during gpg's key lookup to give information
+ * about the lookup results. We store the last one so it can be
+ * used in connection with INV_RECP. */
+ free (opd->kc_fpr);
+ opd->kc_fpr = NULL;
+ err = _gpgme_parse_key_considered (args, &opd->kc_fpr, &opd->kc_flags);
+ if (err)
+ return err;
+ break;
+
case GPGME_STATUS_INV_RECP:
- err = _gpgme_parse_inv_recp (args, opd->lastp);
+ err = _gpgme_parse_inv_recp (args, 0, opd->kc_fpr, opd->kc_flags,
+ opd->lastp);
if (err)
- return err;
+ return err;
opd->lastp = &(*opd->lastp)->next;
+ free (opd->kc_fpr);
+ opd->kc_fpr = NULL;
break;
case GPGME_STATUS_NO_RECP:
@@ -162,8 +184,13 @@ encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args)
static gpgme_error_t
encrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
{
- return _gpgme_progress_status_handler (priv, code, args)
- || _gpgme_encrypt_status_handler (priv, code, args);
+ gpgme_error_t err;
+
+ err = _gpgme_progress_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_encrypt_status_handler (priv, code, args);
+
+ return err;
}
@@ -201,8 +228,7 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
if (err)
return err;
- if (!recp)
- symmetric = 1;
+ symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC);
if (!plain)
return gpg_error (GPG_ERR_NO_DATA);
diff --git a/src/engine-assuan.c b/src/engine-assuan.c
index 9902467..65924eb 100644
--- a/src/engine-assuan.c
+++ b/src/engine-assuan.c
@@ -131,14 +131,15 @@ llass_get_home_dir (void)
static char *
llass_get_version (const char *file_name)
{
- return strdup ("1.0");
+ (void)file_name;
+ return NULL;
}
static const char *
llass_get_req_version (void)
{
- return "1.0";
+ return NULL;
}
@@ -212,11 +213,15 @@ llass_release (void *engine)
/* Create a new instance. If HOME_DIR is NULL standard options for use
with gpg-agent are issued. */
static gpgme_error_t
-llass_new (void **engine, const char *file_name, const char *home_dir)
+llass_new (void **engine, const char *file_name, const char *home_dir,
+ const char *version)
{
gpgme_error_t err = 0;
engine_llass_t llass;
char *optstr;
+ char *env_tty = NULL;
+
+ (void)version; /* Not yet used. */
llass = calloc (1, sizeof *llass);
if (!llass)
@@ -245,6 +250,7 @@ llass_new (void **engine, const char *file_name, const char *home_dir)
if (err)
goto leave;
assuan_ctx_set_system_hooks (llass->assuan_ctx, &_gpgme_assuan_system_hooks);
+ assuan_set_flag (llass->assuan_ctx, ASSUAN_CONVEY_COMMENTS, 1);
err = assuan_socket_connect (llass->assuan_ctx, file_name, 0, 0);
if (err)
@@ -275,13 +281,24 @@ llass_new (void **engine, const char *file_name, const char *home_dir)
}
}
- if (llass->opt.gpg_agent && isatty (1))
+ if (llass->opt.gpg_agent)
+ err = _gpgme_getenv ("GPG_TTY", &env_tty);
+
+ if (llass->opt.gpg_agent && (isatty (1) || env_tty || err))
{
- int rc;
+ int rc = 0;
char dft_ttyname[64];
char *dft_ttytype = NULL;
- rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+ if (err)
+ goto leave;
+ else if (env_tty)
+ {
+ snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
+ free (env_tty);
+ }
+ else
+ rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
/* Even though isatty() returns 1, ttyname_r() may fail in many
ways, e.g., when /dev/pts is not accessible under chroot. */
@@ -354,7 +371,7 @@ llass_set_locale (void *engine, int category, const char *value)
gpgme_error_t err;
engine_llass_t llass = engine;
char *optstr;
- char *catstr;
+ const char *catstr;
if (!llass->opt.gpg_agent)
return 0;
@@ -752,6 +769,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
/* Member functions. */
llass_release,
NULL, /* reset */
+ NULL, /* set_status_cb */
NULL, /* set_status_handler */
NULL, /* set_command_handler */
NULL, /* set_colon_line_handler */
@@ -769,6 +787,8 @@ struct engine_ops _gpgme_engine_ops_assuan =
NULL, /* import */
NULL, /* keylist */
NULL, /* keylist_ext */
+ NULL, /* keysign */
+ NULL, /* tofu_policy */
NULL, /* sign */
NULL, /* trustlist */
NULL, /* verify */
diff --git a/src/engine-backend.h b/src/engine-backend.h
index 4f4519c..ccab0e3 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -44,11 +44,13 @@ struct engine_ops
const char *(*get_req_version) (void);
gpgme_error_t (*new) (void **r_engine,
- const char *file_name, const char *home_dir);
+ const char *file_name, const char *home_dir,
+ const char *version);
/* Member functions. */
void (*release) (void *engine);
gpgme_error_t (*reset) (void *engine);
+ void (*set_status_cb) (void *engine, gpgme_status_cb_t cb, void *cb_value);
void (*set_status_handler) (void *engine, engine_status_handler_t fnc,
void *fnc_value);
gpgme_error_t (*set_command_handler) (void *engine,
@@ -80,7 +82,12 @@ struct engine_ops
gpgme_error_t (*export_ext) (void *engine, const char *pattern[],
gpgme_export_mode_t mode, gpgme_data_t keydata,
int use_armor);
- gpgme_error_t (*genkey) (void *engine, gpgme_data_t help_data, int use_armor,
+ gpgme_error_t (*genkey) (void *engine,
+ const char *userid, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ gpgme_key_t key, unsigned int flags,
+ gpgme_data_t help_data,
+ unsigned int extraflags,
gpgme_data_t pubkey, gpgme_data_t seckey);
gpgme_error_t (*import) (void *engine, gpgme_data_t keydata,
gpgme_key_t *keyarray);
@@ -91,6 +98,13 @@ struct engine_ops
int secret_only, int reserved,
gpgme_keylist_mode_t mode,
int engine_flags);
+ gpgme_error_t (*keysign) (void *engine,
+ gpgme_key_t key, const char *userid,
+ unsigned long expires, unsigned int flags,
+ gpgme_ctx_t ctx);
+ gpgme_error_t (*tofu_policy) (void *engine,
+ gpgme_key_t key,
+ gpgme_tofu_policy_t policy);
gpgme_error_t (*sign) (void *engine, gpgme_data_t in, gpgme_data_t out,
gpgme_sig_mode_t mode, int use_armor,
int use_textmode, int include_certs,
diff --git a/src/engine-g13.c b/src/engine-g13.c
index 4a7b75c..d34db82 100644
--- a/src/engine-g13.c
+++ b/src/engine-g13.c
@@ -212,7 +212,8 @@ g13_release (void *engine)
static gpgme_error_t
-g13_new (void **engine, const char *file_name, const char *home_dir)
+g13_new (void **engine, const char *file_name, const char *home_dir,
+ const char *version)
{
gpgme_error_t err = 0;
engine_g13_t g13;
@@ -221,9 +222,12 @@ g13_new (void **engine, const char *file_name, const char *home_dir)
const char *argv[5];
char *dft_display = NULL;
char dft_ttyname[64];
+ char *env_tty = NULL;
char *dft_ttytype = NULL;
char *optstr;
+ (void)version; /* Not yet used. */
+
g13 = calloc (1, sizeof *g13);
if (!g13)
return gpg_error_from_syserror ();
@@ -281,11 +285,20 @@ g13_new (void **engine, const char *file_name, const char *home_dir)
goto leave;
}
- if (isatty (1))
+ err = _gpgme_getenv ("GPG_TTY", &env_tty);
+ if (isatty (1) || env_tty || err)
{
- int rc;
+ int rc = 0;
- rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+ if (err)
+ goto leave;
+ else if (env_tty)
+ {
+ snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
+ free (env_tty);
+ }
+ else
+ rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
/* Even though isatty() returns 1, ttyname_r() may fail in many
ways, e.g., when /dev/pts is not accessible under chroot. */
@@ -353,7 +366,7 @@ g13_set_locale (void *engine, int category, const char *value)
engine_g13_t g13 = engine;
gpgme_error_t err;
char *optstr;
- char *catstr;
+ const char *catstr;
/* FIXME: If value is NULL, we need to reset the option to default.
But we can't do this. So we error out here. G13 needs support
@@ -402,7 +415,7 @@ g13_set_locale (void *engine, int category, const char *value)
#if USE_DESCRIPTOR_PASSING
static gpgme_error_t
-g13_assuan_simple_command (assuan_context_t ctx, char *cmd,
+g13_assuan_simple_command (assuan_context_t ctx, const char *cmd,
engine_status_handler_t status_fnc,
void *status_fnc_value)
{
@@ -410,6 +423,9 @@ g13_assuan_simple_command (assuan_context_t ctx, char *cmd,
char *line;
size_t linelen;
+ (void)status_fnc;
+ (void)status_fnc_value;
+
err = assuan_write_line (ctx, cmd);
if (err)
return err;
@@ -768,6 +784,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
#else
NULL, /* reset */
#endif
+ NULL, /* set_status_cb */
NULL, /* set_status_handler */
NULL, /* set_command_handler */
NULL, /* set_colon_line_handler */
@@ -785,6 +802,8 @@ struct engine_ops _gpgme_engine_ops_g13 =
NULL, /* import */
NULL, /* keylist */
NULL, /* keylist_ext */
+ NULL, /* keysign */
+ NULL, /* tofu_policy */
NULL, /* sign */
NULL, /* trustlist */
NULL, /* verify */
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index 9efced2..8bb348f 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -42,6 +42,7 @@
#include "priv-io.h"
#include "sema.h"
#include "debug.h"
+#include "data.h"
#include "engine-backend.h"
@@ -78,6 +79,7 @@ typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline);
struct engine_gpg
{
char *file_name;
+ char *version;
char *lc_messages;
char *lc_ctype;
@@ -95,6 +97,8 @@ struct engine_gpg
int eof;
engine_status_handler_t fnc;
void *fnc_value;
+ gpgme_status_cb_t mon_cb;
+ void *mon_cb_value;
void *tag;
} status;
@@ -202,14 +206,16 @@ close_notify_handler (int fd, void *opaque)
/* If FRONT is true, push at the front of the list. Use this for
options added late in the process. */
static gpgme_error_t
-_add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
+_add_arg (engine_gpg_t gpg, const char *prefix, const char *arg, size_t arglen,
+ int front, int *arg_locp)
{
struct arg_and_data_s *a;
+ size_t prefixlen = prefix? strlen (prefix) : 0;
assert (gpg);
assert (arg);
- a = malloc (sizeof *a + strlen (arg));
+ a = malloc (sizeof *a + prefixlen + arglen);
if (!a)
return gpg_error_from_syserror ();
@@ -217,7 +223,10 @@ _add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
a->dup_to = -1;
a->arg_locp = arg_locp;
- strcpy (a->arg, arg);
+ if (prefixlen)
+ memcpy (a->arg, prefix, prefixlen);
+ memcpy (a->arg + prefixlen, arg, arglen);
+ a->arg[prefixlen + arglen] = 0;
if (front)
{
a->next = gpg->arglist;
@@ -239,24 +248,36 @@ _add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
return 0;
}
+
static gpgme_error_t
add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
{
- return _add_arg (gpg, arg, front, NULL);
+ return _add_arg (gpg, NULL, arg, strlen (arg), front, NULL);
}
-
static gpgme_error_t
add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
{
- return _add_arg (gpg, arg, 0, locp);
+ return _add_arg (gpg, NULL, arg, strlen (arg), 0, locp);
}
-
static gpgme_error_t
add_arg (engine_gpg_t gpg, const char *arg)
{
- return add_arg_ext (gpg, arg, 0);
+ return _add_arg (gpg, NULL, arg, strlen (arg), 0, NULL);
+}
+
+static gpgme_error_t
+add_arg_pfx (engine_gpg_t gpg, const char *prefix, const char *arg)
+{
+ return _add_arg (gpg, prefix, arg, strlen (arg), 0, NULL);
+}
+
+static gpgme_error_t
+add_arg_len (engine_gpg_t gpg, const char *prefix,
+ const char *arg, size_t arglen)
+{
+ return _add_arg (gpg, prefix, arg, arglen, 0, NULL);
}
@@ -291,6 +312,15 @@ add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
return 0;
}
+
+/* Return true if the engine's version is at least VERSION. */
+static int
+have_gpg_version (engine_gpg_t gpg, const char *version)
+{
+ return _gpgme_compare_versions (gpg->version, version);
+}
+
+
static char *
gpg_get_version (const char *file_name)
@@ -386,6 +416,8 @@ gpg_release (void *engine)
if (gpg->file_name)
free (gpg->file_name);
+ if (gpg->version)
+ free (gpg->version);
if (gpg->lc_messages)
free (gpg->lc_messages);
@@ -414,13 +446,15 @@ gpg_release (void *engine)
static gpgme_error_t
-gpg_new (void **engine, const char *file_name, const char *home_dir)
+gpg_new (void **engine, const char *file_name, const char *home_dir,
+ const char *version)
{
engine_gpg_t gpg;
gpgme_error_t rc = 0;
char *dft_display = NULL;
char dft_ttyname[64];
char *dft_ttytype = NULL;
+ char *env_tty = NULL;
gpg = calloc (1, sizeof *gpg);
if (!gpg)
@@ -436,6 +470,16 @@ gpg_new (void **engine, const char *file_name, const char *home_dir)
}
}
+ if (version)
+ {
+ gpg->version = strdup (version);
+ if (!gpg->version)
+ {
+ rc = gpg_error_from_syserror ();
+ goto leave;
+ }
+ }
+
gpg->argtail = &gpg->arglist;
gpg->status.fd[0] = -1;
gpg->status.fd[1] = -1;
@@ -517,11 +561,20 @@ gpg_new (void **engine, const char *file_name, const char *home_dir)
goto leave;
}
- if (isatty (1))
+ rc = _gpgme_getenv ("GPG_TTY", &env_tty);
+ if (isatty (1) || env_tty || rc)
{
- int err;
+ int err = 0;
- err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+ if (rc)
+ goto leave;
+ else if (env_tty)
+ {
+ snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
+ free (env_tty);
+ }
+ else
+ err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
/* Even though isatty() returns 1, ttyname_r() may fail in many
ways, e.g., when /dev/pts is not accessible under chroot. */
@@ -609,6 +662,17 @@ gpg_set_locale (void *engine, int category, const char *value)
return 0;
}
+/* This sets a status callback for monitoring status lines before they
+ * are passed to a caller set handler. */
+static void
+gpg_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
+{
+ engine_gpg_t gpg = engine;
+
+ gpg->status.mon_cb = cb;
+ gpg->status.mon_cb_value = cb_value;
+}
+
/* Note, that the status_handler is allowed to modifiy the args
value. */
@@ -829,7 +893,7 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
argc++;
}
- if (gpg->pinentry_mode)
+ if (gpg->pinentry_mode && have_gpg_version (gpg, "2.1.0"))
{
const char *s = NULL;
switch (gpg->pinentry_mode)
@@ -1019,6 +1083,7 @@ read_status (engine_gpg_t gpg)
size_t bufsize = gpg->status.bufsize;
char *buffer = gpg->status.buffer;
size_t readpos = gpg->status.readpos;
+ gpgme_error_t err;
assert (buffer);
if (bufsize - readpos < 256)
@@ -1037,15 +1102,20 @@ read_status (engine_gpg_t gpg)
if (!nread)
{
+ err = 0;
gpg->status.eof = 1;
+ if (gpg->status.mon_cb)
+ err = gpg->status.mon_cb (gpg->status.mon_cb_value, "", "");
if (gpg->status.fnc)
- {
- gpgme_error_t err;
- err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
- if (err)
- return err;
- }
- return 0;
+ {
+ char emptystring[1] = {0};
+ err = gpg->status.fnc (gpg->status.fnc_value,
+ GPGME_STATUS_EOF, emptystring);
+ if (gpg_err_code (err) == GPG_ERR_FALSE)
+ err = 0; /* Drop special error code. */
+ }
+
+ return err;
}
while (nread > 0)
@@ -1071,6 +1141,15 @@ read_status (engine_gpg_t gpg)
*rest++ = 0;
r = _gpgme_parse_status (buffer + 9);
+ if (gpg->status.mon_cb && r != GPGME_STATUS_PROGRESS)
+ {
+ /* Note that we call the monitor even if we do
+ * not know the status code (r < 0). */
+ err = gpg->status.mon_cb (gpg->status.mon_cb_value,
+ buffer + 9, rest);
+ if (err)
+ return err;
+ }
if (r >= 0)
{
if (gpg->cmd.used
@@ -1099,9 +1178,10 @@ read_status (engine_gpg_t gpg)
}
else if (gpg->status.fnc)
{
- gpgme_error_t err;
err = gpg->status.fnc (gpg->status.fnc_value,
r, rest);
+ if (gpg_err_code (err) == GPG_ERR_FALSE)
+ err = 0; /* Drop special error code. */
if (err)
return err;
}
@@ -1438,6 +1518,35 @@ start (engine_gpg_t gpg)
}
+/* Add the --input-size-hint option if requested. */
+static gpgme_error_t
+add_input_size_hint (engine_gpg_t gpg, gpgme_data_t data)
+{
+ gpgme_error_t err;
+ gpgme_off_t value = _gpgme_data_get_size_hint (data);
+ char numbuf[50]; /* Large enough for even 2^128 in base-10. */
+ char *p;
+
+ if (!value || !have_gpg_version (gpg, "2.1.15"))
+ return 0;
+
+ err = add_arg (gpg, "--input-size-hint");
+ if (!err)
+ {
+ p = numbuf + sizeof numbuf;
+ *--p = 0;
+ do
+ {
+ *--p = '0' + (value % 10);
+ value /= 10;
+ }
+ while (value);
+ err = add_arg (gpg, p);
+ }
+ return err;
+}
+
+
static gpgme_error_t
gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
{
@@ -1454,6 +1563,8 @@ gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
if (!err)
err = add_data (gpg, plain, 1, 1);
if (!err)
+ err = add_input_size_hint (gpg, ciph);
+ if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, ciph, -1, 0);
@@ -1493,6 +1604,8 @@ gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags)
engine_gpg_t gpg = engine;
gpgme_error_t err;
+ (void)flags;
+
if (!key || !key->subkeys || !key->subkeys->fpr)
return gpg_error (GPG_ERR_INV_CERT_OBJ);
@@ -1523,7 +1636,8 @@ append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
err = add_arg (gpg, s);
}
gpgme_key_unref (key);
- if (err) break;
+ if (err)
+ break;
}
return err;
}
@@ -1672,10 +1786,13 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
engine_gpg_t gpg = engine;
- gpgme_error_t err;
- int symmetric = !recp;
+ gpgme_error_t err = 0;
- err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
+ if (recp)
+ err = add_arg (gpg, "--encrypt");
+
+ if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+ err = add_arg (gpg, "--symmetric");
if (!err && use_armor)
err = add_arg (gpg, "--armor");
@@ -1683,7 +1800,11 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
err = add_arg (gpg, "--compress-algo=none");
- if (!symmetric)
+ if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
+ && have_gpg_version (gpg, "2.1.14"))
+ err = add_arg (gpg, "--mimemode");
+
+ if (recp)
{
/* If we know that all recipients are valid (full or ultimate trust)
we can suppress further checks. */
@@ -1712,6 +1833,8 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
err = add_arg (gpg, gpgme_data_get_file_name (plain));
}
if (!err)
+ err = add_input_size_hint (gpg, plain);
+ if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, plain, -1, 0);
@@ -1730,10 +1853,13 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
gpgme_ctx_t ctx /* FIXME */)
{
engine_gpg_t gpg = engine;
- gpgme_error_t err;
- int symmetric = !recp;
+ gpgme_error_t err = 0;
+
+ if (recp)
+ err = add_arg (gpg, "--encrypt");
- err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
+ if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+ err = add_arg (gpg, "--symmetric");
if (!err)
err = add_arg (gpg, "--sign");
@@ -1743,7 +1869,11 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
err = add_arg (gpg, "--compress-algo=none");
- if (!symmetric)
+ if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
+ && have_gpg_version (gpg, "2.1.14"))
+ err = add_arg (gpg, "--mimemode");
+
+ if (recp)
{
/* If we know that all recipients are valid (full or ultimate trust)
we can suppress further checks. */
@@ -1778,6 +1908,8 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
err = add_arg (gpg, gpgme_data_get_file_name (plain));
}
if (!err)
+ err = add_input_size_hint (gpg, plain);
+ if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, plain, -1, 0);
@@ -1868,33 +2000,210 @@ gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
}
+
+/* Helper to add algo, usage, and expire to the list of args. */
static gpgme_error_t
-gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
- gpgme_data_t pubkey, gpgme_data_t seckey)
+gpg_add_algo_usage_expire (engine_gpg_t gpg,
+ const char *algo,
+ unsigned long expires,
+ unsigned int flags)
{
- engine_gpg_t gpg = engine;
- gpgme_error_t err;
+ gpg_error_t err;
- if (!gpg)
- return gpg_error (GPG_ERR_INV_VALUE);
+ /* This condition is only required to allow the use of gpg < 2.1.16 */
+ if (algo
+ || (flags & (GPGME_CREATE_SIGN | GPGME_CREATE_ENCR
+ | GPGME_CREATE_CERT | GPGME_CREATE_AUTH))
+ || expires)
+ {
+ err = add_arg (gpg, algo? algo : "default");
+ if (!err)
+ {
+ char tmpbuf[5*4+1];
+ snprintf (tmpbuf, sizeof tmpbuf, "%s%s%s%s",
+ (flags & GPGME_CREATE_SIGN)? " sign":"",
+ (flags & GPGME_CREATE_ENCR)? " encr":"",
+ (flags & GPGME_CREATE_CERT)? " cert":"",
+ (flags & GPGME_CREATE_AUTH)? " auth":"");
+ err = add_arg (gpg, *tmpbuf? tmpbuf : "default");
+ }
+ if (!err && expires)
+ {
+ char tmpbuf[8+20];
+ snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
+ err = add_arg (gpg, tmpbuf);
+ }
+ }
+ else
+ err = 0;
+
+ return err;
+}
- /* 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)
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+static gpgme_error_t
+gpg_createkey_from_param (engine_gpg_t gpg,
+ gpgme_data_t help_data, unsigned int extraflags)
+{
+ gpgme_error_t err;
err = add_arg (gpg, "--gen-key");
- if (!err && use_armor)
+ if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
err = add_arg (gpg, "--armor");
if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, help_data, -1, 0);
+ if (!err)
+ err = start (gpg);
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_createkey (engine_gpg_t gpg,
+ const char *userid, const char *algo,
+ unsigned long expires,
+ unsigned int flags,
+ unsigned int extraflags)
+{
+ gpgme_error_t err;
+
+ err = add_arg (gpg, "--quick-gen-key");
+ if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
+ err = add_arg (gpg, "--armor");
+ if (!err && (flags & GPGME_CREATE_NOPASSWD))
+ {
+ err = add_arg (gpg, "--passphrase");
+ if (!err)
+ err = add_arg (gpg, "");
+ }
+ if (!err && (flags & GPGME_CREATE_FORCE))
+ err = add_arg (gpg, "--yes");
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_arg (gpg, userid);
+
+ if (!err)
+ err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
if (!err)
err = start (gpg);
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_addkey (engine_gpg_t gpg,
+ const char *algo,
+ unsigned long expires,
+ gpgme_key_t key,
+ unsigned int flags,
+ unsigned int extraflags)
+{
+ gpgme_error_t err;
+
+ if (!key || !key->fpr)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ err = add_arg (gpg, "--quick-addkey");
+ if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
+ err = add_arg (gpg, "--armor");
+ if (!err && (flags & GPGME_CREATE_NOPASSWD))
+ {
+ err = add_arg (gpg, "--passphrase");
+ if (!err)
+ err = add_arg (gpg, "");
+ }
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_arg (gpg, key->fpr);
+
+ if (!err)
+ err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
+
+ if (!err)
+ err = start (gpg);
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_adduid (engine_gpg_t gpg,
+ gpgme_key_t key,
+ const char *userid,
+ unsigned int extraflags)
+{
+ gpgme_error_t err;
+
+ if (!key || !key->fpr || !userid)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if ((extraflags & GENKEY_EXTRAFLAG_REVOKE))
+ err = add_arg (gpg, "--quick-revuid");
+ else
+ err = add_arg (gpg, "--quick-adduid");
+
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_arg (gpg, key->fpr);
+ if (!err)
+ err = add_arg (gpg, userid);
+
+ if (!err)
+ err = start (gpg);
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_genkey (void *engine,
+ const char *userid, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ gpgme_key_t key, unsigned int flags,
+ gpgme_data_t help_data, unsigned int extraflags,
+ gpgme_data_t pubkey, gpgme_data_t seckey)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ (void)reserved;
+
+ if (!gpg)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* If HELP_DATA is given the use of the old interface
+ * (gpgme_op_genkey) has been requested. The other modes are:
+ *
+ * USERID && !KEY - Create a new keyblock.
+ * !USERID && KEY - Add a new subkey to KEY (gpg >= 2.1.14)
+ * USERID && KEY && !ALGO - Add a new user id to KEY (gpg >= 2.1.14).
+ *
+ */
+ if (help_data)
+ {
+ /* 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)
+ err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ else
+ err = gpg_createkey_from_param (gpg, help_data, extraflags);
+ }
+ else if (!have_gpg_version (gpg, "2.1.13"))
+ err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+ else if (userid && !key)
+ err = gpg_createkey (gpg, userid, algo, expires, flags, extraflags);
+ else if (!userid && key)
+ err = gpg_addkey (gpg, algo, expires, key, flags, extraflags);
+ else if (userid && key && !algo)
+ err = gpg_adduid (gpg, key, userid, extraflags);
+ else
+ err = gpg_error (GPG_ERR_INV_VALUE);
return err;
}
@@ -2230,14 +2539,26 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
gpg_error_t err;
err = add_arg (gpg, "--with-colons");
- if (!err)
- err = add_arg (gpg, "--fixed-list-mode");
- if (!err)
- err = add_arg (gpg, "--with-fingerprint");
- if (!err)
- err = add_arg (gpg, "--with-fingerprint");
+
+ /* Since gpg 2.1.15 fingerprints are always printed, thus there is
+ * no more need to explictly request them. */
+ if (!have_gpg_version (gpg, "2.1.15"))
+ {
+ if (!err)
+ err = add_arg (gpg, "--fixed-list-mode");
+ if (!err)
+ err = add_arg (gpg, "--with-fingerprint");
+ if (!err)
+ err = add_arg (gpg, "--with-fingerprint");
+ }
+
+ if (!err && (mode & GPGME_KEYLIST_MODE_WITH_TOFU)
+ && have_gpg_version (gpg, "2.1.16"))
+ err = add_arg (gpg, "--with-tofu-info");
+
if (!err && (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
err = add_arg (gpg, "--with-secret");
+
if (!err
&& (mode & GPGME_KEYLIST_MODE_SIGS)
&& (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
@@ -2246,6 +2567,7 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
if (!err)
err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
}
+
if (!err)
{
if ( (mode & GPGME_KEYLIST_MODE_EXTERN) )
@@ -2277,6 +2599,7 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
? "--check-sigs" : "--list-keys"));
}
}
+
if (!err)
err = add_arg (gpg, "--");
@@ -2291,6 +2614,8 @@ gpg_keylist (void *engine, const char *pattern, int secret_only,
engine_gpg_t gpg = engine;
gpgme_error_t err;
+ (void)engine_flags;
+
err = gpg_keylist_build_options (gpg, secret_only, mode);
if (!err && pattern && *pattern)
@@ -2310,6 +2635,8 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
engine_gpg_t gpg = engine;
gpgme_error_t err;
+ (void)engine_flags;
+
if (reserved)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -2329,6 +2656,111 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
static gpgme_error_t
+gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
+ unsigned long expire, unsigned int flags,
+ gpgme_ctx_t ctx)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+ const char *s;
+
+ if (!key || !key->fpr)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if (!have_gpg_version (gpg, "2.1.12"))
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ if ((flags & GPGME_KEYSIGN_LOCAL))
+ err = add_arg (gpg, "--quick-lsign-key");
+ else
+ err = add_arg (gpg, "--quick-sign-key");
+
+ if (!err)
+ err = append_args_from_signers (gpg, ctx);
+
+ /* If an expiration time has been given use that. If none has been
+ * given the default from gpg.conf is used. To make sure not to set
+ * an expiration time at all the flag GPGME_KEYSIGN_NOEXPIRE can be
+ * used. */
+ if (!err && (expire || (flags & GPGME_KEYSIGN_NOEXPIRE)))
+ {
+ char tmpbuf[8+20];
+
+ if ((flags & GPGME_KEYSIGN_NOEXPIRE))
+ expire = 0;
+ snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expire);
+ err = add_arg (gpg, "--default-cert-expire");
+ if (!err)
+ err = add_arg (gpg, tmpbuf);
+ }
+
+ if (!err)
+ err = add_arg (gpg, "--");
+
+ if (!err)
+ err = add_arg (gpg, key->fpr);
+ if (!err && userid)
+ {
+ if ((flags & GPGME_KEYSIGN_LFSEP))
+ {
+ for (; !err && (s = strchr (userid, '\n')); userid = s + 1)
+ if ((s - userid))
+ err = add_arg_len (gpg, "=", userid, s - userid);
+ if (!err && *userid)
+ err = add_arg_pfx (gpg, "=", userid);
+ }
+ else
+ err = add_arg_pfx (gpg, "=", userid);
+ }
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_tofu_policy (void *engine, gpgme_key_t key, gpgme_tofu_policy_t policy)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+ const char *policystr = NULL;
+
+ if (!key || !key->fpr)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ switch (policy)
+ {
+ case GPGME_TOFU_POLICY_NONE: break;
+ case GPGME_TOFU_POLICY_AUTO: policystr = "auto"; break;
+ case GPGME_TOFU_POLICY_GOOD: policystr = "good"; break;
+ case GPGME_TOFU_POLICY_BAD: policystr = "bad"; break;
+ case GPGME_TOFU_POLICY_ASK: policystr = "ask"; break;
+ case GPGME_TOFU_POLICY_UNKNOWN: policystr = "unknown"; break;
+ }
+ if (!policystr)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!have_gpg_version (gpg, "2.1.10"))
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ err = add_arg (gpg, "--tofu-policy");
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_arg (gpg, policystr);
+ if (!err)
+ err = add_arg (gpg, key->fpr);
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
gpgme_sig_mode_t mode, int use_armor, int use_textmode,
int include_certs, gpgme_ctx_t ctx /* FIXME */)
@@ -2336,6 +2768,8 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
engine_gpg_t gpg = engine;
gpgme_error_t err;
+ (void)include_certs;
+
if (mode == GPGME_SIG_MODE_CLEAR)
err = add_arg (gpg, "--clearsign");
else
@@ -2345,8 +2779,14 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
err = add_arg (gpg, "--detach");
if (!err && use_armor)
err = add_arg (gpg, "--armor");
- if (!err && use_textmode)
- err = add_arg (gpg, "--textmode");
+ if (!err)
+ {
+ if (gpgme_data_get_encoding (in) == GPGME_DATA_ENCODING_MIME
+ && have_gpg_version (gpg, "2.1.14"))
+ err = add_arg (gpg, "--mimemode");
+ else if (use_textmode)
+ err = add_arg (gpg, "--textmode");
+ }
}
if (!err)
@@ -2364,6 +2804,8 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
/* Tell the gpg object about the data. */
if (!err)
+ err = add_input_size_hint (gpg, in);
+ if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, in, -1, 0);
@@ -2409,11 +2851,12 @@ gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
if (plaintext)
{
/* Normal or cleartext signature. */
-
err = add_arg (gpg, "--output");
if (!err)
err = add_arg (gpg, "-");
if (!err)
+ err = add_input_size_hint (gpg, sig);
+ if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, sig, -1, 0);
@@ -2424,6 +2867,8 @@ gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
{
err = add_arg (gpg, "--verify");
if (!err)
+ err = add_input_size_hint (gpg, signed_text);
+ if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, sig, -1, 0);
@@ -2470,6 +2915,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
/* Member functions. */
gpg_release,
NULL, /* reset */
+ gpg_set_status_cb,
gpg_set_status_handler,
gpg_set_command_handler,
gpg_set_colon_line_handler,
@@ -2487,6 +2933,8 @@ struct engine_ops _gpgme_engine_ops_gpg =
gpg_import,
gpg_keylist,
gpg_keylist_ext,
+ gpg_keysign,
+ gpg_tofu_policy, /* tofu_policy */
gpg_sign,
gpg_trustlist,
gpg_verify,
diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c
index a2407ac..90f32c7 100644
--- a/src/engine-gpgconf.c
+++ b/src/engine-gpgconf.c
@@ -90,11 +90,14 @@ gpgconf_release (void *engine)
static gpgme_error_t
-gpgconf_new (void **engine, const char *file_name, const char *home_dir)
+gpgconf_new (void **engine, const char *file_name, const char *home_dir,
+ const char *version)
{
gpgme_error_t err = 0;
engine_gpgconf_t gpgconf;
+ (void)version; /* Not yet used. */
+
gpgconf = calloc (1, sizeof *gpgconf);
if (!gpgconf)
return gpg_error_from_syserror ();
@@ -197,7 +200,7 @@ gpgconf_config_release (gpgme_conf_comp_t conf)
allow for quite a long "group" line, which is usually the longest
line (mine is currently ~3k). */
static gpgme_error_t
-gpgconf_read (void *engine, char *arg1, char *arg2,
+gpgconf_read (void *engine, const char *arg1, char *arg2,
gpgme_error_t (*cb) (void *hook, char *line),
void *hook)
{
@@ -214,7 +217,7 @@ gpgconf_read (void *engine, char *arg1, char *arg2,
int nread;
char *mark = NULL;
- argv[1] = arg1;
+ argv[1] = (char*)arg1;
argv[2] = arg2;
@@ -675,14 +678,14 @@ _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
/* FIXME: Major problem: We don't get errors from gpgconf. */
static gpgme_error_t
-gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
+gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
{
struct engine_gpgconf *gpgconf = engine;
gpgme_error_t err = 0;
#define BUFLEN 1024
char buf[BUFLEN];
int buflen = 0;
- char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
+ char *argv[] = { NULL /* file_name */, (char*)arg1, arg2, 0 };
int rp[2];
struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
int status;
@@ -909,6 +912,8 @@ gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
static void
gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
{
+ (void)engine;
+ (void)io_cbs;
/* Nothing to do. */
}
@@ -934,6 +939,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
/* Member functions. */
gpgconf_release,
NULL, /* reset */
+ NULL, /* set_status_cb */
NULL, /* set_status_handler */
NULL, /* set_command_handler */
NULL, /* set_colon_line_handler */
@@ -951,6 +957,8 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
NULL, /* import */
NULL, /* keylist */
NULL, /* keylist_ext */
+ NULL, /* keysign */
+ NULL, /* tofu_policy */
NULL, /* sign */
NULL, /* trustlist */
NULL, /* verify */
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index 476e9ef..e7e2a20 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -88,6 +88,8 @@ struct engine_gpgsm
{
engine_status_handler_t fnc;
void *fnc_value;
+ gpgme_status_cb_t mon_cb;
+ void *mon_cb_value;
} status;
struct
@@ -183,6 +185,8 @@ close_notify_handler (int fd, void *opaque)
static gpgme_error_t
default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
{
+ (void)gpgsm;
+
if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
{
_gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
@@ -235,7 +239,8 @@ gpgsm_release (void *engine)
static gpgme_error_t
-gpgsm_new (void **engine, const char *file_name, const char *home_dir)
+gpgsm_new (void **engine, const char *file_name, const char *home_dir,
+ const char *version)
{
gpgme_error_t err = 0;
engine_gpgsm_t gpgsm;
@@ -248,9 +253,12 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir)
#endif
char *dft_display = NULL;
char dft_ttyname[64];
+ char *env_tty = NULL;
char *dft_ttytype = NULL;
char *optstr;
+ (void)version; /* Not yet used. */
+
gpgsm = calloc (1, sizeof *gpgsm);
if (!gpgsm)
return gpg_error_from_syserror ();
@@ -403,11 +411,20 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir)
goto leave;
}
- if (isatty (1))
+ err = _gpgme_getenv ("GPG_TTY", &env_tty);
+ if (isatty (1) || env_tty || err)
{
- int rc;
+ int rc = 0;
- rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+ if (err)
+ goto leave;
+ else if (env_tty)
+ {
+ snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
+ free (env_tty);
+ }
+ else
+ rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
/* Even though isatty() returns 1, ttyname_r() may fail in many
ways, e.g., when /dev/pts is not accessible under chroot. */
@@ -510,7 +527,7 @@ gpgsm_set_locale (void *engine, int category, const char *value)
engine_gpgsm_t gpgsm = engine;
gpgme_error_t err;
char *optstr;
- char *catstr;
+ const char *catstr;
/* FIXME: If value is NULL, we need to reset the option to default.
But we can't do this. So we error out here. GPGSM needs support
@@ -558,10 +575,11 @@ gpgsm_set_locale (void *engine, int category, const char *value)
static gpgme_error_t
-gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
+gpgsm_assuan_simple_command (engine_gpgsm_t gpgsm, const char *cmd,
engine_status_handler_t status_fnc,
void *status_fnc_value)
{
+ assuan_context_t ctx = gpgsm->assuan_ctx;
gpg_error_t err, cb_err;
char *line;
size_t linelen;
@@ -610,8 +628,15 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
*(rest++) = 0;
r = _gpgme_parse_status (line + 2);
+ if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
+ {
+ /* Note that we call the monitor even if we do
+ * not know the status code (r < 0). */
+ cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
+ line + 2, rest);
+ }
- if (r >= 0 && status_fnc)
+ if (r >= 0 && status_fnc && !cb_err)
cb_err = status_fnc (status_fnc_value, r, rest);
}
}
@@ -647,6 +672,9 @@ gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
_gpgme_io_close (gpgsm->message_cb.fd);
break;
}
+#else
+ (void)gpgsm;
+ (void)fd_type;
#endif
}
@@ -656,7 +684,7 @@ gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
{
gpg_error_t err = 0;
char line[COMMANDLINELEN];
- char *which;
+ const char *which;
iocb_data_t *iocb_data;
#if USE_DESCRIPTOR_PASSING
int dir;
@@ -726,7 +754,7 @@ gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
which, iocb_data->server_fd_str);
#endif
- err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
+ err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
#if USE_DESCRIPTOR_PASSING
leave_set_fd:
@@ -805,8 +833,13 @@ status_handler (void *opaque, int fd)
&& (line[2] == '\0' || line[2] == ' '))
{
if (gpgsm->status.fnc)
- err = gpgsm->status.fnc (gpgsm->status.fnc_value,
- GPGME_STATUS_EOF, "");
+ {
+ char emptystring[1] = {0};
+ err = gpgsm->status.fnc (gpgsm->status.fnc_value,
+ GPGME_STATUS_EOF, emptystring);
+ if (gpg_err_code (err) == GPG_ERR_FALSE)
+ err = 0; /* Drop special error code. */
+ }
if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
{
@@ -957,7 +990,11 @@ status_handler (void *opaque, int fd)
if (r >= 0)
{
if (gpgsm->status.fnc)
- err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
+ {
+ err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
+ if (gpg_err_code (err) == GPG_ERR_FALSE)
+ err = 0; /* Drop special error code. */
+ }
}
else
fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
@@ -1075,8 +1112,7 @@ gpgsm_reset (void *engine)
need to reset the list of signers. Note that RESET does not
reset OPTION commands. */
return (gpgsm->assuan_ctx
- ? gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET",
- NULL, NULL)
+ ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL)
: 0);
}
#endif
@@ -1118,6 +1154,8 @@ gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
char *line;
int length = 8; /* "DELKEYS " */
+ (void)allow_secret;
+
if (!fpr)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -1180,7 +1218,6 @@ static gpgme_error_t
set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
{
gpgme_error_t err = 0;
- assuan_context_t ctx = gpgsm->assuan_ctx;
char *line;
int linelen;
int invalid_recipients = 0;
@@ -1218,7 +1255,7 @@ set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
}
strcpy (&line[10], fpr);
- err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc,
+ err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
gpgsm->status.fnc_value);
/* FIXME: This requires more work. */
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
@@ -1249,7 +1286,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
{
- err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ err = gpgsm_assuan_simple_command (gpgsm,
"OPTION no-encrypt-to", NULL, NULL);
if (err)
return err;
@@ -1422,29 +1459,51 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
static gpgme_error_t
-gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
+gpgsm_genkey (void *engine,
+ const char *userid, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ gpgme_key_t key, unsigned int flags,
+ gpgme_data_t help_data, unsigned int extraflags,
gpgme_data_t pubkey, gpgme_data_t seckey)
{
engine_gpgsm_t gpgsm = engine;
gpgme_error_t err;
- if (!gpgsm || !pubkey || seckey)
+ (void)reserved;
+
+ if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE);
- gpgsm->input_cb.data = help_data;
- err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
- if (err)
- return err;
- gpgsm->output_cb.data = pubkey;
- err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
- : map_data_enc (gpgsm->output_cb.data));
- if (err)
- return err;
- gpgsm_clear_fd (gpgsm, MESSAGE_FD);
- gpgsm->inline_data = NULL;
+ if (help_data)
+ {
+ if (!pubkey || seckey)
+ return gpg_error (GPG_ERR_INV_VALUE);
- err = start (gpgsm, "GENKEY");
- return err;
+ gpgsm->input_cb.data = help_data;
+ err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
+ if (err)
+ return err;
+ gpgsm->output_cb.data = pubkey;
+ err = gpgsm_set_fd (gpgsm, OUTPUT_FD,
+ (extraflags & GENKEY_EXTRAFLAG_ARMOR)? "--armor"
+ : map_data_enc (gpgsm->output_cb.data));
+ if (err)
+ return err;
+ gpgsm_clear_fd (gpgsm, MESSAGE_FD);
+ gpgsm->inline_data = NULL;
+
+ err = start (gpgsm, "GENKEY");
+ return err;
+ }
+
+ (void)userid;
+ (void)algo;
+ (void)expires;
+ (void)key;
+ (void)flags;
+
+ /* The new interface has not yet been implemented, */
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
@@ -1472,8 +1531,7 @@ gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
/* Fist check whether the engine already features the
--re-import option. */
err = gpgsm_assuan_simple_command
- (gpgsm->assuan_ctx,
- "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
+ (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
if (err)
return gpg_error (GPG_ERR_NOT_SUPPORTED);
@@ -1575,13 +1633,12 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only,
available and thus there is no need for gpgsm to ask the agent
whether a secret key exists for the public key. */
if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
- gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "GETINFO agent-check",
- NULL, NULL);
+ gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL);
/* Always send list-mode option because RESET does not reset it. */
if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
return gpg_error_from_syserror ();
- err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
+ err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
free (line);
if (err)
return err;
@@ -1591,24 +1648,24 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only,
/* Use the validation mode if requested. We don't check for an error
yet because this is a pretty fresh gpgsm features. */
- gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ gpgsm_assuan_simple_command (gpgsm,
(mode & GPGME_KEYLIST_MODE_VALIDATE)?
"OPTION with-validation=1":
"OPTION with-validation=0" ,
NULL, NULL);
/* Include the ephemeral keys if requested. We don't check for an error
yet because this is a pretty fresh gpgsm features. */
- gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ gpgsm_assuan_simple_command (gpgsm,
(mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
"OPTION with-ephemeral-keys=1":
"OPTION with-ephemeral-keys=0" ,
NULL, NULL);
- gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ gpgsm_assuan_simple_command (gpgsm,
(mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
"OPTION with-secret=1":
"OPTION with-secret=0" ,
NULL, NULL);
- gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ gpgsm_assuan_simple_command (gpgsm,
(engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
"OPTION offline=1":
"OPTION offline=0" ,
@@ -1665,7 +1722,7 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
/* Always send list-mode option because RESET does not reset it. */
if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
return gpg_error_from_syserror ();
- err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
+ err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
free (line);
if (err)
return err;
@@ -1673,17 +1730,17 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
/* Always send key validation because RESET does not reset it. */
/* Use the validation mode if required. We don't check for an error
yet because this is a pretty fresh gpgsm features. */
- gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ gpgsm_assuan_simple_command (gpgsm,
(mode & GPGME_KEYLIST_MODE_VALIDATE)?
"OPTION with-validation=1":
"OPTION with-validation=0" ,
NULL, NULL);
- gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ gpgsm_assuan_simple_command (gpgsm,
(mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
"OPTION with-secret=1":
"OPTION with-secret=0" ,
NULL, NULL);
- gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ gpgsm_assuan_simple_command (gpgsm,
(engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
"OPTION offline=1":
"OPTION offline=0" ,
@@ -1784,6 +1841,8 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
int i;
gpgme_key_t key;
+ (void)use_textmode;
+
if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -1797,8 +1856,7 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
return gpg_error_from_syserror ();
- err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd,
- NULL, NULL);
+ err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL);
free (assuan_cmd);
if (err)
return err;
@@ -1812,7 +1870,7 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
char buf[100];
strcpy (stpcpy (buf, "SIGNER "), s);
- err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf,
+ err = gpgsm_assuan_simple_command (gpgsm, buf,
gpgsm->status.fnc,
gpgsm->status.fnc_value);
}
@@ -1913,6 +1971,17 @@ gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
}
+/* This sets a status callback for monitoring status lines before they
+ * are passed to a caller set handler. */
+static void
+gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
+{
+ engine_gpgsm_t gpgsm = engine;
+
+ gpgsm->status.mon_cb = cb;
+ gpgsm->status.mon_cb_value = cb_value;
+}
+
static void
gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
@@ -1966,6 +2035,8 @@ gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
gpgme_error_t err;
char *line;
+ (void)flags;
+
if (!key || !key->subkeys || !key->subkeys->fpr)
return gpg_error (GPG_ERR_INV_CERT_OBJ);
@@ -2001,6 +2072,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
#else
NULL, /* reset */
#endif
+ gpgsm_set_status_cb,
gpgsm_set_status_handler,
NULL, /* set_command_handler */
gpgsm_set_colon_line_handler,
@@ -2018,6 +2090,8 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
gpgsm_import,
gpgsm_keylist,
gpgsm_keylist_ext,
+ NULL, /* keysign */
+ NULL, /* tofu_policy */
gpgsm_sign,
NULL, /* trustlist */
gpgsm_verify,
diff --git a/src/engine-spawn.c b/src/engine-spawn.c
index eb4e038..df90cb2 100644
--- a/src/engine-spawn.c
+++ b/src/engine-spawn.c
@@ -312,24 +312,26 @@ static char *
engspawn_get_version (const char *file_name)
{
(void)file_name;
- return strdup ("1.0");
+ return NULL;
}
static const char *
engspawn_get_req_version (void)
{
- return "1.0";
+ return NULL;
}
static gpgme_error_t
-engspawn_new (void **engine, const char *file_name, const char *home_dir)
+engspawn_new (void **engine, const char *file_name, const char *home_dir,
+ const char *version)
{
engine_spawn_t esp;
(void)file_name;
(void)home_dir;
+ (void)version;
esp = calloc (1, sizeof *esp);
if (!esp)
@@ -440,6 +442,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
/* Member functions. */
engspawn_release,
NULL, /* reset */
+ NULL, /* set_status_cb */
NULL, /* set_status_handler */
NULL, /* set_command_handler */
NULL, /* set_colon_line_handler */
@@ -457,6 +460,8 @@ struct engine_ops _gpgme_engine_ops_spawn =
NULL, /* import */
NULL, /* keylist */
NULL, /* keylist_ext */
+ NULL, /* keysign */
+ NULL, /* tofu_policy */
NULL, /* sign */
NULL, /* trustlist */
NULL, /* verify */
diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c
index e4fd47c..63e77de 100644
--- a/src/engine-uiserver.c
+++ b/src/engine-uiserver.c
@@ -90,6 +90,8 @@ struct engine_uiserver
{
engine_status_handler_t fnc;
void *fnc_value;
+ gpgme_status_cb_t mon_cb;
+ void *mon_cb_value;
} status;
struct
@@ -121,14 +123,15 @@ static void uiserver_io_event (void *engine,
static char *
uiserver_get_version (const char *file_name)
{
- return strdup ("1.0");
+ (void)file_name;
+ return NULL;
}
static const char *
uiserver_get_req_version (void)
{
- return "1.0";
+ return NULL;
}
@@ -184,6 +187,8 @@ close_notify_handler (int fd, void *opaque)
static gpgme_error_t
default_inq_cb (engine_uiserver_t uiserver, const char *line)
{
+ (void)uiserver;
+
if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
{
_gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
@@ -236,15 +241,20 @@ uiserver_release (void *engine)
static gpgme_error_t
-uiserver_new (void **engine, const char *file_name, const char *home_dir)
+uiserver_new (void **engine, const char *file_name, const char *home_dir,
+ const char *version)
{
gpgme_error_t err = 0;
engine_uiserver_t uiserver;
char *dft_display = NULL;
char dft_ttyname[64];
+ char *env_tty = NULL;
char *dft_ttytype = NULL;
char *optstr;
+ (void)home_dir;
+ (void)version; /* Not yet used. */
+
uiserver = calloc (1, sizeof *uiserver);
if (!uiserver)
return gpg_error_from_syserror ();
@@ -321,11 +331,20 @@ uiserver_new (void **engine, const char *file_name, const char *home_dir)
goto leave;
}
- if (isatty (1))
+ err = _gpgme_getenv ("GPG_TTY", &env_tty);
+ if (isatty (1) || env_tty || err)
{
- int rc;
+ int rc = 0;
- rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+ if (err)
+ goto leave;
+ else if (env_tty)
+ {
+ snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
+ free (env_tty);
+ }
+ else
+ rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
/* Even though isatty() returns 1, ttyname_r() may fail in many
ways, e.g., when /dev/pts is not accessible under chroot. */
@@ -392,7 +411,7 @@ uiserver_set_locale (void *engine, int category, const char *value)
engine_uiserver_t uiserver = engine;
gpgme_error_t err;
char *optstr;
- char *catstr;
+ const char *catstr;
/* FIXME: If value is NULL, we need to reset the option to default.
But we can't do this. So we error out here. UISERVER needs support
@@ -451,10 +470,11 @@ uiserver_set_protocol (void *engine, gpgme_protocol_t protocol)
static gpgme_error_t
-uiserver_assuan_simple_command (assuan_context_t ctx, char *cmd,
- engine_status_handler_t status_fnc,
- void *status_fnc_value)
+uiserver_assuan_simple_command (engine_uiserver_t uiserver, const char *cmd,
+ engine_status_handler_t status_fnc,
+ void *status_fnc_value)
{
+ assuan_context_t ctx = uiserver->assuan_ctx;
gpg_error_t err;
char *line;
size_t linelen;
@@ -493,8 +513,17 @@ uiserver_assuan_simple_command (assuan_context_t ctx, char *cmd,
*(rest++) = 0;
r = _gpgme_parse_status (line + 2);
+ if (uiserver->status.mon_cb && r != GPGME_STATUS_PROGRESS)
+ {
+ /* Note that we call the monitor even if we do
+ * not know the status code (r < 0). */
+ err = uiserver->status.mon_cb (uiserver->status.mon_cb_value,
+ line + 2, rest);
+ }
- if (r >= 0 && status_fnc)
+ if (err)
+ ;
+ else if (r >= 0 && status_fnc)
err = status_fnc (status_fnc_value, r, rest);
else
err = gpg_error (GPG_ERR_GENERAL);
@@ -516,7 +545,7 @@ uiserver_set_fd (engine_uiserver_t uiserver, fd_type_t fd_type, const char *opt)
{
gpg_error_t err = 0;
char line[COMMANDLINELEN];
- char *which;
+ const char *which;
iocb_data_t *iocb_data;
int dir;
@@ -576,7 +605,7 @@ uiserver_set_fd (engine_uiserver_t uiserver, fd_type_t fd_type, const char *opt)
else
snprintf (line, COMMANDLINELEN, "%s FD", which);
- err = uiserver_assuan_simple_command (uiserver->assuan_ctx, line, NULL, NULL);
+ err = uiserver_assuan_simple_command (uiserver, line, NULL, NULL);
leave_set_fd:
if (err)
@@ -653,8 +682,13 @@ status_handler (void *opaque, int fd)
&& (line[2] == '\0' || line[2] == ' '))
{
if (uiserver->status.fnc)
- err = uiserver->status.fnc (uiserver->status.fnc_value,
- GPGME_STATUS_EOF, "");
+ {
+ char emptystring[1] = {0};
+ err = uiserver->status.fnc (uiserver->status.fnc_value,
+ GPGME_STATUS_EOF, emptystring);
+ if (gpg_err_code (err) == GPG_ERR_FALSE)
+ err = 0; /* Drop special error code. */
+ }
if (!err && uiserver->colon.fnc && uiserver->colon.any)
{
@@ -805,7 +839,12 @@ status_handler (void *opaque, int fd)
if (r >= 0)
{
if (uiserver->status.fnc)
- err = uiserver->status.fnc (uiserver->status.fnc_value, r, rest);
+ {
+ err = uiserver->status.fnc (uiserver->status.fnc_value,
+ r, rest);
+ if (gpg_err_code (err) == GPG_ERR_FALSE)
+ err = 0; /* Drop special error code. */
+ }
}
else
fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
@@ -915,7 +954,7 @@ uiserver_reset (void *engine)
/* We must send a reset because we need to reset the list of
signers. Note that RESET does not reset OPTION commands. */
- return uiserver_assuan_simple_command (uiserver->assuan_ctx, "RESET", NULL, NULL);
+ return uiserver_assuan_simple_command (uiserver, "RESET", NULL, NULL);
}
@@ -984,7 +1023,6 @@ static gpgme_error_t
set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[])
{
gpgme_error_t err = 0;
- assuan_context_t ctx = uiserver->assuan_ctx;
char *line;
int linelen;
int invalid_recipients = 0;
@@ -1023,7 +1061,8 @@ set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[])
/* FIXME: need to do proper escaping */
strcpy (&line[10], uid);
- err = uiserver_assuan_simple_command (ctx, line, uiserver->status.fnc,
+ err = uiserver_assuan_simple_command (uiserver, line,
+ uiserver->status.fnc,
uiserver->status.fnc_value);
/* FIXME: This might requires more work. */
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
@@ -1132,6 +1171,9 @@ uiserver_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
char *cmd;
gpgme_key_t key;
+ (void)use_textmode;
+ (void)include_certs;
+
if (!uiserver || !in || !out)
return gpg_error (GPG_ERR_INV_VALUE);
if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
@@ -1160,7 +1202,7 @@ uiserver_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
char buf[100];
strcpy (stpcpy (buf, "SENDER --info "), s);
- err = uiserver_assuan_simple_command (uiserver->assuan_ctx, buf,
+ err = uiserver_assuan_simple_command (uiserver, buf,
uiserver->status.fnc,
uiserver->status.fnc_value);
}
@@ -1252,6 +1294,18 @@ uiserver_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
}
+/* This sets a status callback for monitoring status lines before they
+ * are passed to a caller set handler. */
+static void
+uiserver_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
+{
+ engine_uiserver_t uiserver = engine;
+
+ uiserver->status.mon_cb = cb;
+ uiserver->status.mon_cb_value = cb_value;
+}
+
+
static void
uiserver_set_status_handler (void *engine, engine_status_handler_t fnc,
void *fnc_value)
@@ -1309,6 +1363,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
/* Member functions. */
uiserver_release,
uiserver_reset,
+ uiserver_set_status_cb,
uiserver_set_status_handler,
NULL, /* set_command_handler */
uiserver_set_colon_line_handler,
@@ -1326,6 +1381,8 @@ struct engine_ops _gpgme_engine_ops_uiserver =
NULL, /* import */
NULL, /* keylist */
NULL, /* keylist_ext */
+ NULL, /* keysign */
+ NULL, /* tofu_policy */
uiserver_sign,
NULL, /* trustlist */
uiserver_verify,
diff --git a/src/engine.c b/src/engine.c
index 8e84da9..a1173a0 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -63,6 +63,10 @@ static struct engine_ops *engine_ops[] =
static gpgme_engine_info_t engine_info;
DEFINE_STATIC_LOCK (engine_info_lock);
+/* If non-NULL, the minimal version required for all engines. */
+static char *engine_minimal_version;
+
+
/* Get the file name of the engine for PROTOCOL. */
static const char *
@@ -93,7 +97,8 @@ engine_get_home_dir (gpgme_protocol_t proto)
/* Get a malloced string containing the version number of the engine
- for PROTOCOL. */
+ * for PROTOCOL. If this function returns NULL for a valid protocol,
+ * it should be assumed that the engine is a pseudo engine. */
static char *
engine_get_version (gpgme_protocol_t proto, const char *file_name)
{
@@ -107,7 +112,8 @@ engine_get_version (gpgme_protocol_t proto, const char *file_name)
}
-/* Get the required version number of the engine for PROTOCOL. */
+/* Get the required version number of the engine for PROTOCOL. This
+ * may be NULL. */
static const char *
engine_get_req_version (gpgme_protocol_t proto)
{
@@ -164,8 +170,8 @@ _gpgme_engine_info_release (gpgme_engine_info_t info)
{
gpgme_engine_info_t next_info = info->next;
- assert (info->file_name);
- free (info->file_name);
+ if (info->file_name)
+ free (info->file_name);
if (info->home_dir)
free (info->home_dir);
if (info->version)
@@ -176,6 +182,26 @@ _gpgme_engine_info_release (gpgme_engine_info_t info)
}
+/* This is an internal function to set a mimimal required version.
+ * This function must only be called by gpgme_set_global_flag.
+ * Returns 0 on success. */
+int
+_gpgme_set_engine_minimal_version (const char *value)
+{
+ free (engine_minimal_version);
+ if (value)
+ {
+ engine_minimal_version = strdup (value);
+ return !engine_minimal_version;
+ }
+ else
+ {
+ engine_minimal_version = NULL;
+ return 0;
+ }
+}
+
+
/* Get the information about the configured and installed engines. A
pointer to the first engine in the statically allocated linked list
is returned in *INFO. If an error occurs, it is returned. The
@@ -203,6 +229,7 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
{
const char *ofile_name = engine_get_file_name (proto_list[proto]);
const char *ohome_dir = engine_get_home_dir (proto_list[proto]);
+ char *version = engine_get_version (proto_list[proto], NULL);
char *file_name;
char *home_dir;
@@ -222,10 +249,29 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
else
home_dir = NULL;
- *lastp = malloc (sizeof (*engine_info));
+ *lastp = calloc (1, sizeof (*engine_info));
if (!*lastp && !err)
err = gpg_error_from_syserror ();
+ /* Check against the optional minimal engine version. */
+ if (!err && version && engine_minimal_version
+ && !_gpgme_compare_versions (version, engine_minimal_version))
+ {
+#if GPG_ERROR_VERSION_NUMBER < 0x011900 /* 1.25 */
+ err = gpg_error (GPG_ERR_NO_ENGINE);
+#else
+ err = gpg_error (GPG_ERR_ENGINE_TOO_OLD);
+#endif
+ }
+
+ /* Now set the dummy version for pseudo engines. */
+ if (!err && !version)
+ {
+ version = strdup ("1.0.0");
+ if (!version)
+ err = gpg_error_from_syserror ();
+ }
+
if (err)
{
_gpgme_engine_info_release (engine_info);
@@ -235,6 +281,8 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
free (file_name);
if (home_dir)
free (home_dir);
+ if (version)
+ free (version);
UNLOCK (engine_info_lock);
return err;
@@ -243,8 +291,10 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
(*lastp)->protocol = proto_list[proto];
(*lastp)->file_name = file_name;
(*lastp)->home_dir = home_dir;
- (*lastp)->version = engine_get_version (proto_list[proto], NULL);
+ (*lastp)->version = version;
(*lastp)->req_version = engine_get_req_version (proto_list[proto]);
+ if (!(*lastp)->req_version)
+ (*lastp)->req_version = "1.0.0"; /* Dummy for pseudo engines. */
(*lastp)->next = NULL;
lastp = &(*lastp)->next;
}
@@ -353,6 +403,7 @@ _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto,
{
char *new_file_name;
char *new_home_dir;
+ char *new_version;
/* FIXME: Use some PROTO_MAX definition. */
if (proto > DIM (engine_ops))
@@ -401,6 +452,17 @@ _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto,
new_home_dir = NULL;
}
+ new_version = engine_get_version (proto, new_file_name);
+ if (!new_version)
+ {
+ new_version = strdup ("1.0.0"); /* Fake one for dummy entries. */
+ if (!new_version)
+ {
+ free (new_file_name);
+ free (new_home_dir);
+ }
+ }
+
/* Remove the old members. */
assert (info->file_name);
free (info->file_name);
@@ -412,7 +474,7 @@ _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto,
/* Install the new members. */
info->file_name = new_file_name;
info->home_dir = new_home_dir;
- info->version = engine_get_version (proto, new_file_name);
+ info->version = new_version;
return 0;
}
@@ -463,7 +525,8 @@ _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine)
{
gpgme_error_t err;
err = (*engine->ops->new) (&engine->engine,
- info->file_name, info->home_dir);
+ info->file_name, info->home_dir,
+ info->version);
if (err)
{
free (engine);
@@ -503,6 +566,21 @@ _gpgme_engine_release (engine_t engine)
}
+/* Set a status callback which is used to monitor the status values
+ * before they are passed to a handler set with
+ * _gpgme_engine_set_status_handler. */
+void
+_gpgme_engine_set_status_cb (engine_t engine,
+ gpgme_status_cb_t cb, void *cb_value)
+{
+ if (!engine)
+ return;
+
+ if (engine->ops->set_status_cb)
+ (*engine->ops->set_status_cb) (engine->engine, cb, cb_value);
+}
+
+
void
_gpgme_engine_set_status_handler (engine_t engine,
engine_status_handler_t fnc, void *fnc_value)
@@ -695,9 +773,13 @@ _gpgme_engine_op_export_ext (engine_t engine, const char *pattern[],
gpgme_error_t
-_gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
- int use_armor, gpgme_data_t pubkey,
- gpgme_data_t seckey)
+_gpgme_engine_op_genkey (engine_t engine,
+ const char *userid, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ gpgme_key_t key, unsigned int flags,
+ gpgme_data_t help_data,
+ unsigned int extraflags,
+ gpgme_data_t pubkey, gpgme_data_t seckey)
{
if (!engine)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -705,12 +787,44 @@ _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
if (!engine->ops->genkey)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- return (*engine->ops->genkey) (engine->engine, help_data, use_armor,
+ return (*engine->ops->genkey) (engine->engine,
+ userid, algo, reserved, expires, key, flags,
+ help_data, extraflags,
pubkey, seckey);
}
gpgme_error_t
+_gpgme_engine_op_keysign (engine_t engine, gpgme_key_t key, const char *userid,
+ unsigned long expires, unsigned int flags,
+ gpgme_ctx_t ctx)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->keysign)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->keysign) (engine->engine,
+ key, userid, expires, flags, ctx);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_tofu_policy (engine_t engine,
+ gpgme_key_t key, gpgme_tofu_policy_t policy)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->tofu_policy)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->tofu_policy) (engine->engine, key, policy);
+}
+
+
+gpgme_error_t
_gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata,
gpgme_key_t *keyarray)
{
diff --git a/src/engine.h b/src/engine.h
index 56fcc42..4ce2bed 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -24,6 +24,11 @@
#include "gpgme.h"
+/* Flags used by the EXTRAFLAGS arg of _gpgme_engine_op_genkey. */
+#define GENKEY_EXTRAFLAG_ARMOR 1
+#define GENKEY_EXTRAFLAG_REVOKE 2
+
+
struct engine;
typedef struct engine *engine_t;
@@ -38,6 +43,8 @@ typedef gpgme_error_t (*engine_command_handler_t) (void *priv,
typedef gpgme_error_t (*engine_assuan_result_cb_t) (void *priv,
gpgme_error_t result);
+/* Helper for gpgme_set_global_flag. */
+int _gpgme_set_engine_minimal_version (const char *value);
/* Get a deep copy of the engine info and return it in INFO. */
gpgme_error_t _gpgme_engine_info_copy (gpgme_engine_info_t *r_info);
@@ -62,6 +69,8 @@ gpgme_error_t _gpgme_engine_set_locale (engine_t engine, int category,
gpgme_error_t _gpgme_engine_set_protocol (engine_t engine,
gpgme_protocol_t protocol);
void _gpgme_engine_release (engine_t engine);
+void _gpgme_engine_set_status_cb (engine_t engine,
+ gpgme_status_cb_t cb, void *cb_value);
void _gpgme_engine_set_status_handler (engine_t engine,
engine_status_handler_t fnc,
void *fnc_value);
@@ -104,9 +113,22 @@ gpgme_error_t _gpgme_engine_op_export_ext (engine_t engine,
gpgme_data_t keydata,
int use_armor);
gpgme_error_t _gpgme_engine_op_genkey (engine_t engine,
+ const char *userid, const char *algo,
+ unsigned long reserved,
+ unsigned long expires,
+ gpgme_key_t key, unsigned int flags,
gpgme_data_t help_data,
- int use_armor, gpgme_data_t pubkey,
+ unsigned int extraflags,
+ gpgme_data_t pubkey,
gpgme_data_t seckey);
+gpgme_error_t _gpgme_engine_op_keysign (engine_t engine,
+ gpgme_key_t key, const char *userid,
+ unsigned long expires,
+ unsigned int flags,
+ gpgme_ctx_t ctx);
+gpgme_error_t _gpgme_engine_op_tofu_policy (engine_t engine,
+ gpgme_key_t key,
+ gpgme_tofu_policy_t policy);
gpgme_error_t _gpgme_engine_op_import (engine_t engine,
gpgme_data_t keydata,
gpgme_key_t *keyarray);
diff --git a/src/export.c b/src/export.c
index a29fbde..41a9eba 100644
--- a/src/export.c
+++ b/src/export.c
@@ -34,7 +34,7 @@
/* Local operation data. */
typedef struct
{
- gpg_error_t err; /* Error encountred during the export. */
+ gpg_error_t err; /* Error encountered during the export. */
} *op_data_t;
diff --git a/src/funopen.c b/src/funopen.c
index b71d3ae..b722020 100644
--- a/src/funopen.c
+++ b/src/funopen.c
@@ -35,7 +35,7 @@
The functions to provide my either be NULL if not required or
similar to the unistd function with the exception of using the
- cookie instead of the fiel descripor.
+ cookie instead of the file descriptor.
*/
diff --git a/src/genkey.c b/src/genkey.c
index 3afd3b4..9dcf0be 100644
--- a/src/genkey.c
+++ b/src/genkey.c
@@ -1,23 +1,22 @@
/* genkey.c - Key generation.
- Copyright (C) 2000 Werner Koch (dd9jn)
- Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
-
- This file is part of GPGME.
-
- GPGME is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of
- the License, or (at your option) any later version.
-
- GPGME is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ * Copyright (C) 2001, 2002, 2003, 2004, 2016 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
#if HAVE_CONFIG_H
#include <config.h>
@@ -40,6 +39,12 @@ typedef struct
/* The error code from a FAILURE status line or 0. */
gpg_error_t failure_code;
+ /* The error code from certain ERROR status lines or 0. */
+ gpg_error_t error_code;
+
+ /* Flag to indicate that a UID is to be added. */
+ gpg_error_t uidmode;
+
/* The key parameters passed to the crypto engine. */
gpgme_data_t key_parameter;
} *op_data_t;
@@ -82,7 +87,39 @@ gpgme_op_genkey_result (gpgme_ctx_t ctx)
return &opd->result;
}
+
+/* Parse an error status line. Return the error location and the
+ error code. The function may modify ARGS. */
+static char *
+parse_error (char *args, gpg_error_t *r_err)
+{
+ char *where = strchr (args, ' ');
+ char *which;
+
+ if (where)
+ {
+ *where = '\0';
+ which = where + 1;
+
+ where = strchr (which, ' ');
+ if (where)
+ *where = '\0';
+
+ where = args;
+ }
+ else
+ {
+ *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
+ return NULL;
+ }
+
+ *r_err = atoi (which);
+
+ return where;
+}
+
+
static gpgme_error_t
genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
{
@@ -90,6 +127,7 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
gpgme_error_t err;
void *hook;
op_data_t opd;
+ char *loc;
/* Pipe the status code through the progress status handler. */
err = _gpgme_progress_status_handler (ctx, code, args);
@@ -107,7 +145,10 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
if (args && *args)
{
if (*args == 'B' || *args == 'P')
- opd->result.primary = 1;
+ {
+ opd->result.primary = 1;
+ opd->result.uid = 1;
+ }
if (*args == 'B' || *args == 'S')
opd->result.sub = 1;
if (args[1] == ' ')
@@ -121,20 +162,31 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
}
break;
+ case GPGME_STATUS_ERROR:
+ loc = parse_error (args, &err);
+ if (!loc)
+ return err;
+ if (!opd->error_code)
+ opd->error_code = err;
+ break;
+
case GPGME_STATUS_FAILURE:
opd->failure_code = _gpgme_parse_failure (args);
break;
case GPGME_STATUS_EOF:
- /* FIXME: Should return some more useful error value. */
- if (!opd->result.primary && !opd->result.sub)
+ if (opd->error_code)
+ return opd->error_code;
+ else if (!opd->uidmode && !opd->result.primary && !opd->result.sub)
return gpg_error (GPG_ERR_GENERAL);
else if (opd->failure_code)
return opd->failure_code;
+ else if (opd->uidmode == 1)
+ opd->result.uid = 1; /* We have no status line, thus this hack. */
break;
case GPGME_STATUS_INQUIRE_MAXLEN:
- if (ctx->status_cb)
+ if (ctx->status_cb && !ctx->full_status)
{
err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
if (err)
@@ -212,8 +264,11 @@ genkey_start (gpgme_ctx_t ctx, int synchronous, const char *parms,
return err;
}
- return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter,
- ctx->use_armor, pubkey, seckey);
+ return _gpgme_engine_op_genkey (ctx->engine,
+ NULL, NULL, 0, 0, NULL, 0,
+ opd->key_parameter,
+ ctx->use_armor? GENKEY_EXTRAFLAG_ARMOR:0,
+ pubkey, seckey);
}
@@ -231,7 +286,7 @@ gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
TRACE_LOGBUF (parms, strlen (parms));
if (!ctx)
- return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
err = genkey_start (ctx, 0, parms, pubkey, seckey);
return TRACE_ERR (err);
@@ -252,10 +307,302 @@ gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, gpgme_data_t pubkey,
TRACE_LOGBUF (parms, strlen (parms));
if (!ctx)
- return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
err = genkey_start (ctx, 1, parms, pubkey, seckey);
if (!err)
err = _gpgme_wait_one (ctx);
return TRACE_ERR (err);
}
+
+
+
+static gpgme_error_t
+createkey_start (gpgme_ctx_t ctx, int synchronous,
+ const char *userid, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ gpgme_key_t anchorkey, unsigned int flags)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ if (reserved || anchorkey || !userid)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ return _gpgme_engine_op_genkey (ctx->engine,
+ userid, algo, reserved, expires,
+ anchorkey, flags,
+ NULL,
+ ctx->use_armor? GENKEY_EXTRAFLAG_ARMOR:0,
+ NULL, NULL);
+
+}
+
+
+gpgme_error_t
+gpgme_op_createkey_start (gpgme_ctx_t ctx, const char *userid, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ gpgme_key_t anchorkey, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_createkey_start", ctx,
+ "userid='%s', algo='%s' flags=0x%x", userid, algo, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = createkey_start (ctx, 0,
+ userid, algo, reserved, expires, anchorkey, flags);
+ return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_createkey (gpgme_ctx_t ctx, const char *userid, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ gpgme_key_t anchorkey, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_createkey", ctx,
+ "userid='%s', algo='%s' flags=0x%x", userid, algo, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = createkey_start (ctx, 1,
+ userid, algo, reserved, expires, anchorkey, flags);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
+
+
+
+static gpgme_error_t
+createsubkey_start (gpgme_ctx_t ctx, int synchronous,
+ gpgme_key_t key,
+ const char *algo,
+ unsigned long reserved, unsigned long expires,
+ unsigned int flags)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
+ return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ if (reserved || !key)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ return _gpgme_engine_op_genkey (ctx->engine,
+ NULL, algo, reserved, expires,
+ key, flags,
+ NULL,
+ ctx->use_armor? GENKEY_EXTRAFLAG_ARMOR:0,
+ NULL, NULL);
+
+}
+
+
+/* Add a subkey to an existing KEY. */
+gpgme_error_t
+gpgme_op_createsubkey_start (gpgme_ctx_t ctx, gpgme_key_t key, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_createsubkey_start", ctx,
+ "key=%p, algo='%s' flags=0x%x", key, algo, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = createsubkey_start (ctx, 0, key, algo, reserved, expires, flags);
+ return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_createsubkey (gpgme_ctx_t ctx, gpgme_key_t key, const char *algo,
+ unsigned long reserved, unsigned long expires,
+ unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_createsubkey", ctx,
+ "key=%p, algo='%s' flags=0x%x", key, algo, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = createsubkey_start (ctx, 1, key, algo, reserved, expires, flags);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
+
+
+
+static gpgme_error_t
+addrevuid_start (gpgme_ctx_t ctx, int synchronous, int revoke,
+ gpgme_key_t key, const char *userid, unsigned int flags)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
+ return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+ if (!key || !userid)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ opd->uidmode = revoke? 2 : 1;
+
+ _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ return _gpgme_engine_op_genkey (ctx->engine,
+ userid, NULL, 0, 0,
+ key, flags,
+ NULL,
+ revoke? GENKEY_EXTRAFLAG_REVOKE : 0,
+ NULL, NULL);
+
+}
+
+
+/* Add USERID to an existing KEY. */
+gpgme_error_t
+gpgme_op_adduid_start (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG2 (DEBUG_CTX, "gpgme_op_adduid_start", ctx,
+ "uid='%s' flags=0x%x", userid, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = addrevuid_start (ctx, 0, 0, key, userid, flags);
+ return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_adduid (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG2 (DEBUG_CTX, "gpgme_op_adduid", ctx,
+ "uid='%s' flags=0x%x", userid, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = addrevuid_start (ctx, 1, 0, key, userid, flags);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
+
+
+/* Revoke USERID from KEY. */
+gpgme_error_t
+gpgme_op_revuid_start (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG2 (DEBUG_CTX, "gpgme_op_revuid_start", ctx,
+ "uid='%s' flags=0x%x", userid, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = addrevuid_start (ctx, 0, 1, key, userid, flags);
+ return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_revuid (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG2 (DEBUG_CTX, "gpgme_op_revuid", ctx,
+ "uid='%s' flags=0x%x", userid, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = addrevuid_start (ctx, 1, 1, key, userid, flags);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
diff --git a/src/getauditlog.c b/src/getauditlog.c
index 3bb4138..e2ba25e 100644
--- a/src/getauditlog.c
+++ b/src/getauditlog.c
@@ -31,6 +31,9 @@
static gpgme_error_t
getauditlog_status_handler (void *priv, gpgme_status_code_t code, char *args)
{
+ (void)priv;
+ (void)code;
+ (void)args;
return 0;
}
diff --git a/src/gpgme-config.in b/src/gpgme-config.in
index 4be1e08..0d9fda2 100644
--- a/src/gpgme-config.in
+++ b/src/gpgme-config.in
@@ -36,6 +36,8 @@ thread_modules=""
libs_pthread="-lpthread"
cflags_pthread=""
+avail_lang='c @GPGME_CONFIG_AVAIL_LANG@'
+
# Configure glib.
libs_glib="@GLIB_LIBS@"
cflags_glib="@GLIB_CFLAGS@"
@@ -48,16 +50,16 @@ usage()
cat <<EOF
Usage: gpgme-config [OPTIONS]
Options:
- [--thread={${thread_modules}}]
- [--prefix]
- [--exec-prefix]
- [--version]
- [--api-version]
- [--host]
- [--libs]
- [--cflags]
- [--get-gpg]
- [--get-gpgsm]
+ --thread={${thread_modules}}]
+ --prefix
+ --exec-prefix
+ --version
+ --api-version
+ --host
+ --libs
+ --cflags
+ --print-lang Print available language bindings
+ --have-lang=LANG Return success if LANG is available
EOF
exit $1
}
@@ -178,10 +180,23 @@ while test $# -gt 0; do
usage 1 1>&2
fi
;;
+ --print-lang)
+ output="$avail_lang"
+ ;;
+ --have-lang=*)
+ for lang in $avail_lang; do
+ if test x"$lang" = x"$optarg"; then
+ exit 0
+ fi
+ done
+ exit 1
+ ;;
--get-gpg)
+ # Deprecated
output="$output @GPG@"
;;
--get-gpgsm)
+ # Deprecated
output="$output @GPGSM@"
;;
*)
diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c
index e5e5707..fb158f1 100644
--- a/src/gpgme-tool.c
+++ b/src/gpgme-tool.c
@@ -32,12 +32,10 @@
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
-#ifdef HAVE_ARGP_H
-#include <argp.h>
-#endif
#include <assuan.h>
+#include "argparse.h"
#include "gpgme.h"
/* GCC attributes. */
@@ -60,421 +58,6 @@
-#ifndef HAVE_ARGP_H
-/* Minimal argp implementation. */
-
-/* Differences to ARGP:
- argp_program_version: Required.
- argp_program_bug_address: Required.
- argp_program_version_hook: Not supported.
- argp_err_exit_status: Required.
- struct argp: Children and help_filter not supported.
- argp_domain: Not supported.
- struct argp_option: Group not supported. Options are printed in
- order given. Flags OPTION_ALIAS, OPTION_DOC and OPTION_NO_USAGE
- are not supported.
- argp_parse: No flags are supported (ARGP_PARSE_ARGV0, ARGP_NO_ERRS,
- ARGP_NO_ARGS, ARGP_IN_ORDER, ARGP_NO_HELP, ARGP_NO_EXIT,
- ARGP_LONG_ONLY, ARGP_SILENT). ARGP must not be NULL.
- argp_help: Flag ARGP_HELP_LONG_ONLY not supported.
- argp_state: argc, argv, next may not be modified and should not be used. */
-
-extern const char *argp_program_version;
-extern const char *argp_program_bug_address;
-extern error_t argp_err_exit_status;
-
-struct argp_option
-{
- const char *name;
- int key;
- const char *arg;
-#define OPTION_ARG_OPTIONAL 0x1
-#define OPTION_HIDDEN 0x2
- int flags;
- const char *doc;
- int group;
-};
-
-struct argp;
-struct argp_state
-{
- const struct argp *const root_argp;
- int argc;
- char **argv;
- int next;
- unsigned flags;
- unsigned arg_num;
- int quoted;
- void *input;
- void **child_inputs;
- void *hook;
- char *name;
- FILE *err_stream;
- FILE *out_stream;
- void *pstate;
-};
-
-#ifdef EDEADLK
-# define ARGP_ERR_UNKNOWN EDEADLK /* POSIX */
-#else
-# define ARGP_ERR_UNKNOWN EDEADLOCK /* *GNU/kFreebsd does not define this) */
-#endif
-#define ARGP_KEY_ARG 0
-#define ARGP_KEY_ARGS 0x1000006
-#define ARGP_KEY_END 0x1000001
-#define ARGP_KEY_NO_ARGS 0x1000002
-#define ARGP_KEY_INIT 0x1000003
-#define ARGP_KEY_FINI 0x1000007
-#define ARGP_KEY_SUCCESS 0x1000004
-#define ARGP_KEY_ERROR 0x1000005
-typedef error_t (*argp_parser_t) (int key, char *arg, struct argp_state *state);
-
-struct argp
-{
- const struct argp_option *options;
- argp_parser_t parser;
- const char *args_doc;
- const char *doc;
-
- const struct argp_child *children;
- char *(*help_filter) (int key, const char *text, void *input);
- const char *argp_domain;
-};
-
-#define ARGP_HELP_USAGE ARGP_HELP_SHORT_USAGE
-#define ARGP_HELP_SHORT_USAGE 0x02
-#define ARGP_HELP_SEE 0x04
-#define ARGP_HELP_LONG 0x08
-#define ARGP_HELP_PRE_DOC 0x10
-#define ARGP_HELP_POST_DOC 0x20
-#define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC)
-#define ARGP_HELP_BUG_ADDR 0x40
-#define ARGP_HELP_EXIT_ERR 0x100
-#define ARGP_HELP_EXIT_OK 0x200
-#define ARGP_HELP_STD_ERR (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
-#define ARGP_HELP_STD_USAGE \
- (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
-#define ARGP_HELP_STD_HELP \
- (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK \
- | ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR)
-
-
-void argp_error (const struct argp_state *state,
- const char *fmt, ...) GT_GCC_A_PRINTF(2, 3);
-
-
-
-char *
-_argp_pname (char *name)
-{
- char *pname = name;
- char *bname = strrchr (pname, '/');
- if (! bname)
- bname = strrchr (pname, '\\');
- if (bname)
- pname = bname + 1;
- return pname;
-}
-
-
-void
-_argp_state_help (const struct argp *argp, const struct argp_state *state,
- FILE *stream, unsigned flags, char *name)
-{
- if (state)
- name = state->name;
-
- if (flags & ARGP_HELP_SHORT_USAGE)
- fprintf (stream, "Usage: %s [OPTIONS...] %s\n", name, argp->args_doc);
- if (flags & ARGP_HELP_SEE)
- fprintf (stream, "Try `%s --help' or `%s --usage' for more information.\n",
- name, name);
- if (flags & ARGP_HELP_PRE_DOC)
- {
- char buf[1024];
- char *end;
- strncpy (buf, argp->doc, sizeof (buf));
- buf[sizeof (buf) - 1] = '\0';
- end = strchr (buf, '\v');
- if (end)
- *end = '\0';
- fprintf (stream, "%s\n%s", buf, buf[0] ? "\n" : "");
- }
- if (flags & ARGP_HELP_LONG)
- {
- const struct argp_option *opt = argp->options;
- while (opt->key)
- {
- #define NSPACES 29
- char spaces[NSPACES + 1] = " ";
- int len = 0;
- fprintf (stream, " ");
- len += 2;
- if (isascii (opt->key))
- {
- fprintf (stream, "-%c", opt->key);
- len += 2;
- if (opt->name)
- {
- fprintf (stream, ", ");
- len += 2;
- }
- }
- if (opt->name)
- {
- fprintf (stream, "--%s", opt->name);
- len += 2 + strlen (opt->name);
- }
- if (opt->arg && (opt->flags & OPTION_ARG_OPTIONAL))
- {
- fprintf (stream, "[=%s]", opt->arg);
- len += 3 + strlen (opt->arg);
- }
- else if (opt->arg)
- {
- fprintf (stream, "=%s", opt->arg);
- len += 1 + strlen (opt->arg);
- }
- if (len >= NSPACES)
- len = NSPACES - 1;
- spaces[NSPACES - len] = '\0';
- fprintf (stream, "%s%s\n", spaces, opt->doc);
- opt++;
- }
- fprintf (stream, " -?, --help Give this help list\n");
- fprintf (stream, " --usage Give a short usage "
- "message\n");
- }
- if (flags & ARGP_HELP_POST_DOC)
- {
- char buf[1024];
- char *end;
- strncpy (buf, argp->doc, sizeof (buf));
- buf[sizeof (buf) - 1] = '\0';
- end = strchr (buf, '\v');
- if (end)
- {
- end++;
- if (*end)
- fprintf (stream, "\n%s\n", end);
- }
- fprintf (stream, "\nMandatory or optional arguments to long options are also mandatory or optional\n");
- fprintf (stream, "for any corresponding short options.\n");
- }
- if (flags & ARGP_HELP_BUG_ADDR)
- fprintf (stream, "\nReport bugs to %s.\n", argp_program_bug_address);
-
- if (flags & ARGP_HELP_EXIT_ERR)
- exit (argp_err_exit_status);
- if (flags & ARGP_HELP_EXIT_OK)
- exit (0);
-}
-
-
-void
-argp_usage (const struct argp_state *state)
-{
- _argp_state_help (state->root_argp, state, state->err_stream,
- ARGP_HELP_STD_USAGE, state->name);
-}
-
-
-void
-argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags)
-{
- _argp_state_help (state->root_argp, state, stream, flags, state->name);
-}
-
-
-void
-argp_error (const struct argp_state *state, const char *fmt, ...)
-{
- va_list ap;
-
- fprintf (state->err_stream, "%s: ", state->name);
- va_start (ap, fmt);
- vfprintf (state->err_stream, fmt, ap);
- va_end (ap);
- fprintf (state->err_stream, "\n");
- argp_state_help (state, state->err_stream, ARGP_HELP_STD_ERR);
- exit (argp_err_exit_status);
-}
-
-
-void
-argp_help (const struct argp *argp, FILE *stream, unsigned flags, char *name)
-{
- _argp_state_help (argp, NULL, stream, flags, name);
-}
-
-
-error_t
-argp_parse (const struct argp *argp, int argc,
- char **argv, unsigned flags, int *arg_index, void *input)
-{
- int rc = 0;
- struct argp_state state = { argp, argc, argv, 1, flags, 0, 0, input,
- NULL, NULL, _argp_pname (argv[0]),
- stderr, stdout, NULL };
- /* All non-option arguments are collected at the beginning of
- &argv[1] during processing. This is a counter for their number. */
- int non_opt_args = 0;
-
- rc = argp->parser (ARGP_KEY_INIT, NULL, &state);
- if (rc && rc != ARGP_ERR_UNKNOWN)
- goto argperror;
-
- while (state.next < state.argc - non_opt_args)
- {
- int idx = state.next;
- state.next++;
-
- if (! strcasecmp (state.argv[idx], "--"))
- {
- state.quoted = idx;
- continue;
- }
-
- if (state.quoted || state.argv[idx][0] != '-')
- {
- char *arg_saved = state.argv[idx];
- non_opt_args++;
- memmove (&state.argv[idx], &state.argv[idx + 1],
- (state.argc - 1 - idx) * sizeof (char *));
- state.argv[argc - 1] = arg_saved;
- state.next--;
- }
- else if (! strcasecmp (state.argv[idx], "--help")
- || !strcmp (state.argv[idx], "-?"))
- {
- argp_state_help (&state, state.out_stream, ARGP_HELP_STD_HELP);
- }
- else if (! strcasecmp (state.argv[idx], "--usage"))
- {
- argp_state_help (&state, state.out_stream,
- ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
- }
- else if (! strcasecmp (state.argv[idx], "--version")
- || !strcmp (state.argv[idx], "-V"))
- {
- fprintf (state.out_stream, "%s\n", argp_program_version);
- exit (0);
- }
- else
- {
- /* Search for option and call parser with its KEY. */
- int key = ARGP_KEY_ARG; /* Just some dummy value. */
- const struct argp_option *opt = argp->options;
- char *arg = NULL;
- int found = 0;
-
- /* Check for --opt=value syntax. */
- arg = strchr (state.argv[idx], '=');
- if (arg)
- {
- *arg = '\0';
- arg++;
- }
-
- if (state.argv[idx][1] != '-')
- key = state.argv[idx][1];
-
- while (! found && opt->key)
- {
- if (key == opt->key
- || (key == ARGP_KEY_ARG
- && ! strcasecmp (&state.argv[idx][2], opt->name)))
- {
- if (arg && !opt->arg)
- argp_error (&state, "Option %s does not take an argument",
- state.argv[idx]);
- if (opt->arg && state.next < state.argc
- && state.argv[idx + 1][0] != '-')
- {
- arg = state.argv[idx + 1];
- state.next++;
- }
- if (opt->arg && !(opt->flags & OPTION_ARG_OPTIONAL))
- argp_error (&state, "Option %s requires an argument",
- state.argv[idx]);
-
- rc = argp->parser (opt->key, arg, &state);
- if (rc == ARGP_ERR_UNKNOWN)
- break;
- else if (rc)
- goto argperror;
- found = 1;
- }
- opt++;
- }
- if (! found)
- argp_error (&state, "Unknown option %s", state.argv[idx]);
- }
- }
-
- while (state.next < state.argc)
- {
- /* Call parser for all non-option args. */
- int idx = state.next;
- state.next++;
- rc = argp->parser (ARGP_KEY_ARG, state.argv[idx], &state);
- if (rc && rc != ARGP_ERR_UNKNOWN)
- goto argperror;
- if (rc == ARGP_ERR_UNKNOWN)
- {
- int old_next = state.next;
- rc = argp->parser (ARGP_KEY_ARGS, NULL, &state);
- if (rc == ARGP_ERR_UNKNOWN)
- {
- argp_error (&state, "Too many arguments");
- goto argperror;
- }
- if (! rc && state.next == old_next)
- {
- state.arg_num += state.argc - state.next;
- state.next = state.argc;
- }
- }
- else
- state.arg_num++;
- }
-
- if (state.arg_num == 0)
- {
- rc = argp->parser (ARGP_KEY_NO_ARGS, NULL, &state);
- if (rc && rc != ARGP_ERR_UNKNOWN)
- goto argperror;
- }
- if (state.next == state.argc)
- {
- rc = argp->parser (ARGP_KEY_END, NULL, &state);
- if (rc && rc != ARGP_ERR_UNKNOWN)
- goto argperror;
- }
- rc = argp->parser (ARGP_KEY_FINI, NULL, &state);
- if (rc && rc != ARGP_ERR_UNKNOWN)
- goto argperror;
-
- rc = 0;
- argp->parser (ARGP_KEY_SUCCESS, NULL, &state);
-
- argperror:
- if (rc)
- {
- argp_error (&state, "unexpected error: %s", strerror (rc));
- argp->parser (ARGP_KEY_ERROR, NULL, &state);
- }
-
- argp->parser (ARGP_KEY_FINI, NULL, &state);
-
- if (arg_index)
- *arg_index = state.next - 1;
-
- return 0;
-}
-#endif
-
-
/* MEMBUF */
/* A simple implementation of a dynamic buffer. Use init_membuf() to
@@ -619,7 +202,7 @@ peek_membuf (membuf_t *mb, size_t *len)
/* SUPPORT. */
FILE *log_stream;
-char *program_name = "gpgme-tool";
+char program_name[] = "gpgme-tool";
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
@@ -725,7 +308,7 @@ struct result_xml_state
#define MAX_TAGS 20
int next_tag;
- char *tag[MAX_TAGS];
+ const char *tag[MAX_TAGS];
int had_data[MAX_TAGS];
};
@@ -754,13 +337,14 @@ result_xml_indent (struct result_xml_state *state)
gpg_error_t
-result_xml_tag_start (struct result_xml_state *state, char *name, ...)
+result_xml_tag_start (struct result_xml_state *state, const char *name, ...)
{
result_xml_write_cb_t cb = state->cb;
void *hook = state->hook;
va_list ap;
char *attr;
char *attr_val;
+ char string_null[] = "(null)";
va_start (ap, name);
@@ -791,7 +375,7 @@ result_xml_tag_start (struct result_xml_state *state, char *name, ...)
attr_val = va_arg (ap, char *);
if (attr_val == NULL)
- attr_val = "(null)";
+ attr_val = string_null;
(*cb) (hook, " ", 1);
(*cb) (hook, attr, strlen (attr));
@@ -908,7 +492,8 @@ result_xml_tag_end (struct result_xml_state *state)
gpg_error_t
-result_add_error (struct result_xml_state *state, char *name, gpg_error_t err)
+result_add_error (struct result_xml_state *state,
+ const char *name, gpg_error_t err)
{
char code[20];
char msg[1024];
@@ -924,7 +509,7 @@ result_add_error (struct result_xml_state *state, char *name, gpg_error_t err)
gpg_error_t
result_add_pubkey_algo (struct result_xml_state *state,
- char *name, gpgme_pubkey_algo_t algo)
+ const char *name, gpgme_pubkey_algo_t algo)
{
char code[20];
char msg[80];
@@ -940,10 +525,11 @@ result_add_pubkey_algo (struct result_xml_state *state,
gpg_error_t
result_add_hash_algo (struct result_xml_state *state,
- char *name, gpgme_hash_algo_t algo)
+ const char *name, gpgme_hash_algo_t algo)
{
char code[20];
char msg[80];
+
snprintf (code, sizeof (code) - 1, "0x%x", algo);
snprintf (msg, sizeof (msg) - 1, "%s",
gpgme_hash_algo_name (algo));
@@ -955,7 +541,8 @@ result_add_hash_algo (struct result_xml_state *state,
gpg_error_t
-result_add_keyid (struct result_xml_state *state, char *name, char *keyid)
+result_add_keyid (struct result_xml_state *state,
+ const char *name, const char *keyid)
{
result_xml_tag_start (state, name, NULL);
result_xml_tag_data (state, keyid);
@@ -965,7 +552,8 @@ result_add_keyid (struct result_xml_state *state, char *name, char *keyid)
gpg_error_t
-result_add_fpr (struct result_xml_state *state, char *name, char *fpr)
+result_add_fpr (struct result_xml_state *state,
+ const char *name, const char *fpr)
{
result_xml_tag_start (state, name, NULL);
result_xml_tag_data (state, fpr);
@@ -975,7 +563,7 @@ result_add_fpr (struct result_xml_state *state, char *name, char *fpr)
gpg_error_t
-result_add_timestamp (struct result_xml_state *state, char *name,
+result_add_timestamp (struct result_xml_state *state, const char *name,
unsigned int timestamp)
{
char code[20];
@@ -988,10 +576,10 @@ result_add_timestamp (struct result_xml_state *state, char *name,
gpg_error_t
-result_add_sig_mode (struct result_xml_state *state, char *name,
+result_add_sig_mode (struct result_xml_state *state, const char *name,
gpgme_sig_mode_t sig_mode)
{
- char *mode;
+ const char *mode;
char code[20];
snprintf (code, sizeof (code) - 1, "%i", sig_mode);
@@ -1018,7 +606,7 @@ result_add_sig_mode (struct result_xml_state *state, char *name,
gpg_error_t
-result_add_protocol (struct result_xml_state *state, char *name,
+result_add_protocol (struct result_xml_state *state, const char *name,
gpgme_protocol_t protocol)
{
const char *str;
@@ -1036,7 +624,7 @@ result_add_protocol (struct result_xml_state *state, char *name,
gpg_error_t
-result_add_validity (struct result_xml_state *state, char *name,
+result_add_validity (struct result_xml_state *state, const char *name,
gpgme_validity_t validity)
{
const char *str;
@@ -1073,7 +661,7 @@ result_add_validity (struct result_xml_state *state, char *name,
gpg_error_t
result_add_value (struct result_xml_state *state,
- char *name, unsigned int val)
+ const char *name, unsigned int val)
{
char code[20];
@@ -1086,7 +674,7 @@ result_add_value (struct result_xml_state *state,
gpg_error_t
result_add_string (struct result_xml_state *state,
- char *name, char *str)
+ const char *name, const char *str)
{
if (!str)
str = "";
@@ -2100,6 +1688,8 @@ gt_identify (gpgme_tool_t gt, gpgme_data_t data)
case GPGME_DATA_TYPE_INVALID: return gpg_error (GPG_ERR_GENERAL);
case GPGME_DATA_TYPE_UNKNOWN : s = "unknown"; break;
case GPGME_DATA_TYPE_PGP_SIGNED : s = "PGP-signed"; break;
+ case GPGME_DATA_TYPE_PGP_SIGNATURE: s = "PGP-signature"; break;
+ case GPGME_DATA_TYPE_PGP_ENCRYPTED: s = "PGP-encrypted"; break;
case GPGME_DATA_TYPE_PGP_OTHER : s = "PGP"; break;
case GPGME_DATA_TYPE_PGP_KEY : s = "PGP-key"; break;
case GPGME_DATA_TYPE_CMS_SIGNED : s = "CMS-signed"; break;
@@ -2140,9 +1730,9 @@ gt_result (gpgme_tool_t gt, unsigned int flags)
{
int indent = 2;
- gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
+ gt_write_data (gt, xml_preamble1, strlen (xml_preamble1));
gt_write_data (gt, NULL, 0);
- gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
+ gt_write_data (gt, xml_preamble2, strlen (xml_preamble2));
gt_write_data (gt, NULL, 0);
if (flags & GT_RESULT_ENCRYPT)
result_encrypt_to_xml (gt->ctx, indent,
@@ -2168,7 +1758,7 @@ gt_result (gpgme_tool_t gt, unsigned int flags)
if (flags & GT_RESULT_VFS_MOUNT)
result_vfs_mount_to_xml (gt->ctx, indent,
(result_xml_write_cb_t) gt_write_data, gt);
- gt_write_data (gt, xml_end, sizeof (xml_end));
+ gt_write_data (gt, xml_end, strlen (xml_end));
return 0;
}
@@ -2223,6 +1813,8 @@ server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
unsigned char *buf = NULL;
size_t buflen = 0;
+ (void)was_bad;
+
if (server && server->assuan_ctx)
{
if (uid_hint)
@@ -2291,6 +1883,8 @@ server_data_encoding (const char *line)
return GPGME_DATA_ENCODING_URLESC;
if (strstr (line, "--url0"))
return GPGME_DATA_ENCODING_URL0;
+ if (strstr (line, "--mime"))
+ return GPGME_DATA_ENCODING_MIME;
return GPGME_DATA_ENCODING_NONE;
}
@@ -2395,6 +1989,9 @@ static gpg_error_t
reset_notify (assuan_context_t ctx, char *line)
{
struct server *server = assuan_get_pointer (ctx);
+
+ (void)line;
+
server_reset_fds (server);
gt_reset (server->gt);
return 0;
@@ -2718,6 +2315,8 @@ cmd_signers_clear (assuan_context_t ctx, char *line)
{
struct server *server = assuan_get_pointer (ctx);
+ (void)line;
+
return gt_signers_clear (server->gt);
}
@@ -2734,6 +2333,8 @@ _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
gpgme_data_t inp_data;
gpgme_data_t out_data;
+ (void)line;
+
inp_fd = server->input_fd;
inp_fn = server->input_filename;
if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
@@ -2960,6 +2561,8 @@ cmd_verify (assuan_context_t ctx, char *line)
gpgme_data_t msg_data = NULL;
gpgme_data_t out_data = NULL;
+ (void)line;
+
inp_fd = server->input_fd;
inp_fn = server->input_filename;
if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
@@ -3135,6 +2738,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
gpgme_data_t parms_data = NULL;
const char *parms;
+ (void)line;
+
inp_fd = server->input_fd;
inp_fn = server->input_filename;
if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
@@ -3266,9 +2871,9 @@ cmd_keylist (assuan_context_t ctx, char *line)
}
pattern[idx] = NULL;
- gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
+ gt_write_data (gt, xml_preamble1, strlen (xml_preamble1));
gt_write_data (gt, NULL, 0);
- gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
+ gt_write_data (gt, xml_preamble2, strlen (xml_preamble2));
gt_write_data (gt, NULL, 0);
result_init (&state, indent, (result_xml_write_cb_t) gt_write_data, gt);
result_xml_tag_start (&state, "keylist", NULL);
@@ -3343,7 +2948,7 @@ cmd_keylist (assuan_context_t ctx, char *line)
}
result_xml_tag_end (&state); /* keylist */
- gt_write_data (gt, xml_end, sizeof (xml_end));
+ gt_write_data (gt, xml_end, strlen (xml_end));
server_reset_fds (server);
@@ -3450,6 +3055,9 @@ static gpg_error_t
cmd_result (assuan_context_t ctx, char *line)
{
struct server *server = assuan_get_pointer (ctx);
+
+ (void)line;
+
return gt_result (server->gt, GT_RESULT_ALL);
}
@@ -3505,6 +3113,8 @@ cmd_identify (assuan_context_t ctx, char *line)
char *inp_fn;
gpgme_data_t inp_data;
+ (void)line;
+
inp_fd = server->input_fd;
inp_fn = server->input_filename;
if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
@@ -3722,85 +3332,51 @@ gpgme_server (gpgme_tool_t gt)
-/* MAIN PROGRAM STARTS HERE. */
-
-const char *argp_program_version = VERSION;
-const char *argp_program_bug_address = "bug-gpgme@gnupg.org";
-error_t argp_err_exit_status = 1;
-
-static char doc[] = "GPGME Tool -- Assuan server exposing GPGME operations";
-static char args_doc[] = "COMMAND [OPTIONS...]";
-
-static struct argp_option options[] = {
- { "server", 's', 0, 0, "Server mode" },
- { "gpg-binary", 501, "FILE", 0, "Use FILE for the GPG backend" },
- { "lib-version", 502, 0, 0, "Show library version" },
- { 0 }
-};
-
-static error_t parse_options (int key, char *arg, struct argp_state *state);
-static struct argp argp = { options, parse_options, args_doc, doc };
-
-struct args
-{
- enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd;
- const char *gpg_binary;
-};
-
-void
-args_init (struct args *args)
-{
- memset (args, '\0', sizeof (*args));
- args->cmd = CMD_DEFAULT;
-}
-
-
-static error_t
-parse_options (int key, char *arg, struct argp_state *state)
+static const char *
+my_strusage( int level )
{
- struct args *args = state->input;
+ const char *p;
- switch (key)
+ switch (level)
{
- case 's':
- args->cmd = CMD_SERVER;
- break;
-
- case 501:
- args->gpg_binary = arg;
+ case 11: p = "gpgme-tool"; break;
+ case 13: p = PACKAGE_VERSION; break;
+ case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break;
+ case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
+ case 1:
+ case 40:
+ p = "Usage: gpgme-tool [OPTIONS] [COMMANDS]";
break;
-
- case 502:
- args->cmd = CMD_LIBVERSION;
- break;
-
-#if 0
- case ARGP_KEY_ARG:
- if (state->arg_num >= 2)
- argp_usage (state);
- printf ("Arg[%i] = %s\n", state->arg_num, arg);
+ case 41:
+ p = "GPGME Tool -- Assuan server exposing GPGME operations\n";
break;
- case ARGP_KEY_END:
- if (state->arg_num < 2)
- argp_usage (state);
+ case 42:
+ p = "1"; /* Flag print 40 as part of 41. */
break;
-#endif
-
- default:
- return ARGP_ERR_UNKNOWN;
+ default: p = NULL; break;
}
- return 0;
+ return p;
}
-
+
int
main (int argc, char *argv[])
{
- struct args args;
+ static ARGPARSE_OPTS opts[] = {
+ ARGPARSE_c ('s', "server", "Server mode"),
+ ARGPARSE_s_s(501, "gpg-binary", "|FILE|Use FILE for the GPG backend"),
+ ARGPARSE_c (502, "lib-version", "Show library version"),
+ ARGPARSE_end()
+ };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
+ enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd = CMD_DEFAULT;
+ const char *gpg_binary = NULL;
struct gpgme_tool gt;
gpg_error_t err;
int needgt = 1;
+ set_strusage (my_strusage);
+
#ifdef HAVE_SETLOCALE
setlocale (LC_ALL, "");
#endif
@@ -3812,30 +3388,40 @@ main (int argc, char *argv[])
gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
#endif
- args_init (&args);
-
- argp_parse (&argp, argc, argv, 0, 0, &args);
log_init ();
- if (args.cmd == CMD_LIBVERSION)
+ while (arg_parse (&pargs, opts))
+ {
+ switch (pargs.r_opt)
+ {
+ case 's': cmd = CMD_SERVER; break;
+ case 501: gpg_binary = pargs.r.ret_str; break;
+ case 502: cmd = CMD_LIBVERSION; break;
+ default:
+ pargs.err = ARGPARSE_PRINT_WARNING;
+ break;
+ }
+ }
+
+ if (cmd == CMD_LIBVERSION)
needgt = 0;
- if (needgt && args.gpg_binary)
+ if (needgt && gpg_binary)
{
- if (access (args.gpg_binary, X_OK))
+ if (access (gpg_binary, X_OK))
err = gpg_error_from_syserror ();
else
err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP,
- args.gpg_binary, NULL);
+ gpg_binary, NULL);
if (err)
log_error (1, err, "error witching OpenPGP engine to '%s'",
- args.gpg_binary);
+ gpg_binary);
}
if (needgt)
gt_init (&gt);
- switch (args.cmd)
+ switch (cmd)
{
case CMD_DEFAULT:
case CMD_SERVER:
@@ -3860,4 +3446,3 @@ main (int argc, char *argv[])
return 0;
}
-
diff --git a/src/gpgme.c b/src/gpgme.c
index 0cf999a..d59f808 100644
--- a/src/gpgme.c
+++ b/src/gpgme.c
@@ -1,7 +1,7 @@
/* gpgme.c - GnuPG Made Easy.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2012,
- 2014 g10 Code GmbH
+ 2014, 2015 g10 Code GmbH
This file is part of GPGME.
@@ -71,15 +71,52 @@ gpgme_set_global_flag (const char *name, const char *value)
_gpgme_dirinfo_disable_gpgconf ();
return 0;
}
+ else if (!strcmp (name, "require-gnupg"))
+ return _gpgme_set_engine_minimal_version (value);
else if (!strcmp (name, "gpgconf-name"))
return _gpgme_set_default_gpgconf_name (value);
else if (!strcmp (name, "gpg-name"))
return _gpgme_set_default_gpg_name (value);
+ else if (!strcmp (name, "w32-inst-dir"))
+ return _gpgme_set_override_inst_dir (value);
else
return -1;
}
+/* Set the flag NAME for CTX to VALUE. The supported flags are:
+ *
+ * - full-status :: With a value of "1" the status callback set by
+ * gpgme_set_status_cb returns all status lines
+ * except for PROGRESS lines. With the default of
+ * "0" the status callback is only called in certain
+ * situations.
+ */
+gpgme_error_t
+gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value)
+{
+ int abool;
+
+ if (!ctx || !name || !value)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ abool = *value? !!atoi (value) : 0;
+
+ if (!strcmp (name, "full-status"))
+ {
+ ctx->full_status = abool;
+ }
+ else if (!strcmp (name, "raw-description"))
+ {
+ ctx->raw_description = abool;
+ }
+ else
+ return gpg_error (GPG_ERR_UNKNOWN_NAME);
+
+ return 0;
+}
+
+
/* Create a new context as an environment for GPGME crypto
operations. */
@@ -91,7 +128,7 @@ gpgme_new (gpgme_ctx_t *r_ctx)
TRACE_BEG (DEBUG_CTX, "gpgme_new", r_ctx);
if (_gpgme_selftest)
- return TRACE_ERR (gpgme_error (_gpgme_selftest));
+ return TRACE_ERR (_gpgme_selftest);
if (!r_ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
@@ -994,41 +1031,70 @@ gpgme_sig_notation_get (gpgme_ctx_t ctx)
return ctx->sig_notations;
}
+
-const char *
-gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
+/* Return a public key algorithm string made of the algorithm and size
+ or the curve name. May return NULL on error. Caller must free the
+ result using gpgme_free. */
+char *
+gpgme_pubkey_algo_string (gpgme_subkey_t subkey)
{
- switch (algo)
+ const char *prefix = NULL;
+ char *result;
+
+ if (!subkey)
{
- case GPGME_PK_RSA:
- return "RSA";
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+ switch (subkey->pubkey_algo)
+ {
+ case GPGME_PK_RSA:
case GPGME_PK_RSA_E:
- return "RSA-E";
-
- case GPGME_PK_RSA_S:
- return "RSA-S";
-
- case GPGME_PK_ELG_E:
- return "ELG-E";
-
- case GPGME_PK_DSA:
- return "DSA";
-
+ case GPGME_PK_RSA_S: prefix = "rsa"; break;
+ case GPGME_PK_ELG_E: prefix = "elg"; break;
+ case GPGME_PK_DSA: prefix = "dsa"; break;
+ case GPGME_PK_ELG: prefix = "xxx"; break;
case GPGME_PK_ECC:
- return "ECC";
+ case GPGME_PK_ECDH:
+ case GPGME_PK_ECDSA:
+ case GPGME_PK_EDDSA: prefix = ""; break;
+ }
- case GPGME_PK_ELG:
- return "ELG";
+ if (prefix && *prefix)
+ {
+ char buffer[40];
+ snprintf (buffer, sizeof buffer, "%s%u", prefix, subkey->length);
+ result = strdup (buffer);
+ }
+ else if (prefix && subkey->curve && *subkey->curve)
+ result = strdup (subkey->curve);
+ else if (prefix)
+ result = strdup ("E_error");
+ else
+ result = strdup ("unknown");
- case GPGME_PK_ECDSA:
- return "ECDSA";
+ return result;
+}
- case GPGME_PK_ECDH:
- return "ECDH";
- default:
- return NULL;
+const char *
+gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
+{
+ switch (algo)
+ {
+ case GPGME_PK_RSA: return "RSA";
+ case GPGME_PK_RSA_E: return "RSA-E";
+ case GPGME_PK_RSA_S: return "RSA-S";
+ case GPGME_PK_ELG_E: return "ELG-E";
+ case GPGME_PK_DSA: return "DSA";
+ case GPGME_PK_ECC: return "ECC";
+ case GPGME_PK_ELG: return "ELG";
+ case GPGME_PK_ECDSA: return "ECDSA";
+ case GPGME_PK_ECDH: return "ECDH";
+ case GPGME_PK_EDDSA: return "EdDSA";
+ default: return NULL;
}
}
diff --git a/src/gpgme.def b/src/gpgme.def
index a3f5fb4..9815a83 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -223,5 +223,26 @@ EXPORTS
gpgme_set_status_cb @167
gpgme_get_status_cb @168
+
+ gpgme_pubkey_algo_string @169
+ gpgme_set_ctx_flag @170
+
+ gpgme_data_set_flag @171
+
+ gpgme_op_createkey_start @172
+ gpgme_op_createkey @173
+ gpgme_op_createsubkey_start @174
+ gpgme_op_createsubkey @175
+ gpgme_op_adduid_start @176
+ gpgme_op_adduid @177
+ gpgme_op_revuid_start @178
+ gpgme_op_revuid @179
+ gpgme_op_keysign_start @180
+ gpgme_op_keysign @181
+ gpgme_op_tofu_policy_start @182
+ gpgme_op_tofu_policy @183
+ gpgme_op_interact_start @184
+ gpgme_op_interact @185
+
; END
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 6cea2c7..20654db 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -1,6 +1,6 @@
/* gpgme.h - Public interface to GnuPG Made Easy. -*- c -*-
* Copyright (C) 2000 Werner Koch (dd9jn)
- * Copyright (C) 2001-2015 g10 Code GmbH
+ * Copyright (C) 2001-2016 g10 Code GmbH
*
* This file is part of GPGME.
*
@@ -67,29 +67,31 @@ extern "C" {
#endif
+/* The deprecated macro takes the version number of GPGME which
+ * introduced the deprecation as parameter for documentation. */
#ifdef GPGRT_ATTR_DEPRECATED
-# define _GPGME_DEPRECATED GPGRT_ATTR_DEPRECATED
+# define _GPGME_DEPRECATED(a,b) GPGRT_ATTR_DEPRECATED
#elif defined(__GNUC__)
# define _GPGME_GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
# if _GPGME_GCC_VERSION > 30100
-# define _GPGME_DEPRECATED __attribute__ ((__deprecated__))
+# define _GPGME_DEPRECATED(a,b) __attribute__ ((__deprecated__))
# else
-# define _GPGME_DEPRECATED
+# define _GPGME_DEPRECATED(a,b)
# endif
#else
-# define _GPGME_DEPRECATED
+# define _GPGME_DEPRECATED(a,b)
#endif
/* The macro _GPGME_DEPRECATED_OUTSIDE_GPGME suppresses warnings for
fields we must access in GPGME for ABI compatibility. */
#ifdef _GPGME_IN_GPGME
-#define _GPGME_DEPRECATED_OUTSIDE_GPGME
+#define _GPGME_DEPRECATED_OUTSIDE_GPGME(a,b)
#else
-#define _GPGME_DEPRECATED_OUTSIDE_GPGME _GPGME_DEPRECATED
+#define _GPGME_DEPRECATED_OUTSIDE_GPGME(a,b) _GPGME_DEPRECATED(a,b)
#endif
@@ -228,7 +230,8 @@ typedef enum
GPGME_DATA_ENCODING_ARMOR = 3, /* Either PEM or OpenPGP Armor. */
GPGME_DATA_ENCODING_URL = 4, /* LF delimited URL list. */
GPGME_DATA_ENCODING_URLESC = 5, /* Ditto, but percent escaped. */
- GPGME_DATA_ENCODING_URL0 = 6 /* Nul delimited URL list. */
+ GPGME_DATA_ENCODING_URL0 = 6, /* Nul delimited URL list. */
+ GPGME_DATA_ENCODING_MIME = 7 /* Data is a MIME part. */
}
gpgme_data_encoding_t;
@@ -239,8 +242,10 @@ typedef enum
GPGME_DATA_TYPE_INVALID = 0, /* Not detected. */
GPGME_DATA_TYPE_UNKNOWN = 1,
GPGME_DATA_TYPE_PGP_SIGNED = 0x10,
+ GPGME_DATA_TYPE_PGP_ENCRYPTED= 0x11,
GPGME_DATA_TYPE_PGP_OTHER = 0x12,
GPGME_DATA_TYPE_PGP_KEY = 0x13,
+ GPGME_DATA_TYPE_PGP_SIGNATURE= 0x18, /* Detached signature */
GPGME_DATA_TYPE_CMS_SIGNED = 0x20,
GPGME_DATA_TYPE_CMS_ENCRYPTED= 0x21,
GPGME_DATA_TYPE_CMS_OTHER = 0x22,
@@ -261,7 +266,8 @@ typedef enum
GPGME_PK_ECC = 18,
GPGME_PK_ELG = 20,
GPGME_PK_ECDSA = 301,
- GPGME_PK_ECDH = 302
+ GPGME_PK_ECDH = 302,
+ GPGME_PK_EDDSA = 303
}
gpgme_pubkey_algo_t;
@@ -303,7 +309,7 @@ typedef enum
GPGME_SIG_STAT_GOOD_EXPKEY = 8
}
_gpgme_sig_stat_t;
-typedef _gpgme_sig_stat_t gpgme_sig_stat_t _GPGME_DEPRECATED;
+typedef _gpgme_sig_stat_t gpgme_sig_stat_t _GPGME_DEPRECATED(0,4);
/* The available signature modes. */
@@ -354,7 +360,7 @@ typedef enum
GPGME_ATTR_SIG_CLASS = 32
}
_gpgme_attr_t;
-typedef _gpgme_attr_t gpgme_attr_t _GPGME_DEPRECATED;
+typedef _gpgme_attr_t gpgme_attr_t _GPGME_DEPRECATED(0,4);
/* The available validities for a trust item or key. */
@@ -370,6 +376,19 @@ typedef enum
gpgme_validity_t;
+/* The TOFU policies. */
+typedef enum
+ {
+ GPGME_TOFU_POLICY_NONE = 0,
+ GPGME_TOFU_POLICY_AUTO = 1,
+ GPGME_TOFU_POLICY_GOOD = 2,
+ GPGME_TOFU_POLICY_UNKNOWN = 3,
+ GPGME_TOFU_POLICY_BAD = 4,
+ GPGME_TOFU_POLICY_ASK = 5
+ }
+gpgme_tofu_policy_t;
+
+
/* The available protocols. */
typedef enum
{
@@ -394,6 +413,7 @@ gpgme_protocol_t;
#define GPGME_KEYLIST_MODE_SIGS 4
#define GPGME_KEYLIST_MODE_SIG_NOTATIONS 8
#define GPGME_KEYLIST_MODE_WITH_SECRET 16
+#define GPGME_KEYLIST_MODE_WITH_TOFU 32
#define GPGME_KEYLIST_MODE_EPHEMERAL 128
#define GPGME_KEYLIST_MODE_VALIDATE 256
@@ -426,7 +446,9 @@ typedef unsigned int gpgme_export_mode_t;
#define GPGME_AUDITLOG_HTML 1
#define GPGME_AUDITLOG_WITH_HELP 128
-/* The possible stati for the edit operation. */
+
+/* The possible stati for gpgme_op_edit. The use of that function and
+ * these status codes are deprecated in favor of gpgme_op_interact. */
typedef enum
{
GPGME_STATUS_EOF = 0,
@@ -531,7 +553,12 @@ typedef enum
GPGME_STATUS_BEGIN_SIGNING = 90,
GPGME_STATUS_KEY_NOT_CREATED = 91,
GPGME_STATUS_INQUIRE_MAXLEN = 92,
- GPGME_STATUS_FAILURE = 93
+ GPGME_STATUS_FAILURE = 93,
+ GPGME_STATUS_KEY_CONSIDERED = 94,
+ GPGME_STATUS_TOFU_USER = 95,
+ GPGME_STATUS_TOFU_STATS = 96,
+ GPGME_STATUS_TOFU_STATS_LONG = 97,
+ GPGME_STATUS_NOTATION_FLAGS = 98
}
gpgme_status_code_t;
@@ -602,6 +629,43 @@ struct _gpgme_engine_info
typedef struct _gpgme_engine_info *gpgme_engine_info_t;
+/* An object with TOFU information. */
+struct _gpgme_tofu_info
+{
+ struct _gpgme_tofu_info *next;
+
+ /* The TOFU validity:
+ * 0 := conflict
+ * 1 := key without history
+ * 2 := key with too little history
+ * 3 := key with enough history for basic trust
+ * 4 := key with a lot of history
+ */
+ unsigned int validity : 3;
+
+ /* The TOFU policy (gpgme_tofu_policy_t). */
+ unsigned int policy : 4;
+
+ unsigned int _rfu : 25;
+
+ /* Number of signatures seen for this binding. Capped at USHRT_MAX. */
+ unsigned short signcount;
+ /* Number of encryptions done with this binding. Capped at USHRT_MAX. */
+ unsigned short encrcount;
+
+ /* Number of seconds since Epoch when the first and the most
+ * recently seen message were verified/decrypted. 0 means unknown. */
+ unsigned long signfirst;
+ unsigned long signlast;
+ unsigned long encrfirst;
+ unsigned long encrlast;
+
+ /* If non-NULL a human readable string summarizing the TOFU data. */
+ char *description;
+};
+typedef struct _gpgme_tofu_info *gpgme_tofu_info_t;
+
+
/* A subkey from a key. */
struct _gpgme_subkey
{
@@ -669,6 +733,9 @@ struct _gpgme_subkey
/* The name of the curve for ECC algorithms or NULL. */
char *curve;
+
+ /* The keygrip of the subkey in hex digit form or NULL if not availabale. */
+ char *keygrip;
};
typedef struct _gpgme_subkey *gpgme_subkey_t;
@@ -712,10 +779,10 @@ struct _gpgme_key_sig
gpgme_error_t status;
#ifdef __cplusplus
- unsigned int _obsolete_class _GPGME_DEPRECATED;
+ unsigned int _obsolete_class _GPGME_DEPRECATED(0,4);
#else
/* Must be set to SIG_CLASS below. */
- unsigned int class _GPGME_DEPRECATED_OUTSIDE_GPGME;
+ unsigned int class _GPGME_DEPRECATED_OUTSIDE_GPGME(0,4);
#endif
/* The user ID string. */
@@ -776,6 +843,15 @@ struct _gpgme_user_id
/* Internal to GPGME, do not use. */
gpgme_key_sig_t _last_keysig;
+
+ /* The mail address (addr-spec from RFC5322) of the UID string.
+ * This is general the same as the EMAIL part of this struct but
+ * might be slightly different. IF no mail address is available
+ * NULL is stored. */
+ char *address;
+
+ /* The malloced TOFU information or NULL. */
+ gpgme_tofu_info_t tofu;
};
typedef struct _gpgme_user_id *gpgme_user_id_t;
@@ -852,6 +928,11 @@ struct _gpgme_key
/* The keylist mode that was active when listing the key. */
gpgme_keylist_mode_t keylist_mode;
+
+ /* This field gives the fingerprint of the primary key. Note that
+ * this is a copy of the FPR of the first subkey. We need it here
+ * to allow for an incomplete key object. */
+ char *fpr;
};
typedef struct _gpgme_key *gpgme_key_t;
@@ -860,7 +941,12 @@ typedef struct _gpgme_key *gpgme_key_t;
struct _gpgme_invalid_key
{
struct _gpgme_invalid_key *next;
+
+ /* The string used to request the key. Despite the name this may
+ * not be a fingerprint. */
char *fpr;
+
+ /* The error code. */
gpgme_error_t reason;
};
typedef struct _gpgme_invalid_key *gpgme_invalid_key_t;
@@ -885,8 +971,13 @@ typedef void (*gpgme_progress_cb_t) (void *opaque, const char *what,
typedef gpgme_error_t (*gpgme_status_cb_t) (void *opaque, const char *keyword,
const char *args);
-
/* Interact with the user about an edit operation. */
+typedef gpgme_error_t (*gpgme_interact_cb_t) (void *opaque,
+ const char *keyword,
+ const char *args, int fd);
+
+/* The callback type used by the deprecated functions gpgme_op_edit
+ * and gpgme_op_card_edit. */
typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque,
gpgme_status_code_t status,
const char *args, int fd);
@@ -904,6 +995,10 @@ gpgme_error_t gpgme_new (gpgme_ctx_t *ctx);
/* Release the context CTX. */
void gpgme_release (gpgme_ctx_t ctx);
+/* Set the flag NAME for CTX to VALUE. */
+gpgme_error_t gpgme_set_ctx_flag (gpgme_ctx_t ctx,
+ const char *name, const char *value);
+
/* Set the protocol to be used by CTX to PROTO. */
gpgme_error_t gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t proto);
@@ -986,7 +1081,7 @@ void gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *cb,
void **hook_value);
/* Set the status callback function in CTX to CB. HOOK_VALUE is
- passed as first argument to thes status callback function. */
+ passed as first argument to the status callback function. */
void gpgme_set_status_cb (gpgme_ctx_t c, gpgme_status_cb_t cb,
void *hook_value);
@@ -1031,7 +1126,7 @@ gpgme_key_t gpgme_signers_enum (const gpgme_ctx_t ctx, int seq);
Deprecated, use verify result directly. */
const char *gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
_gpgme_sig_stat_t *r_stat,
- time_t *r_created) _GPGME_DEPRECATED;
+ time_t *r_created) _GPGME_DEPRECATED(0,4);
/* Retrieve certain attributes of a signature. IDX is the index
number of the signature after a successful verify operation. WHAT
@@ -1039,16 +1134,16 @@ const char *gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
one. WHATIDX is to be passed as 0 for most attributes . */
unsigned long gpgme_get_sig_ulong_attr (gpgme_ctx_t c, int idx,
_gpgme_attr_t what, int whatidx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
const char *gpgme_get_sig_string_attr (gpgme_ctx_t c, int idx,
_gpgme_attr_t what, int whatidx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
/* Get the key used to create signature IDX in CTX and return it in
R_KEY. */
gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
/* Clear all notation data from the context. */
@@ -1131,7 +1226,7 @@ void gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
void gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
/* Wrappers around the internal I/O functions for use with
- gpgme_passphrase_cb_t and gpgme_edit_cb_t. */
+ gpgme_passphrase_cb_t and gpgme_interact_cb_t. */
@API__SSIZE_T@ gpgme_io_read (int fd, void *buffer, size_t count);
@API__SSIZE_T@ gpgme_io_write (int fd, const void *buffer, size_t count);
int gpgme_io_writen (int fd, const void *buffer, size_t count);
@@ -1169,11 +1264,12 @@ typedef @API__SSIZE_T@ (*gpgme_data_write_cb_t) (void *handle, const void *buffe
/* Set the current position from where the next read or write starts
in the data object with the handle HANDLE to OFFSET, relativ to
- WHENCE. */
+ WHENCE. Returns the new offset in bytes from the beginning of the
+ data object. */
typedef @API__OFF_T@ (*gpgme_data_seek_cb_t) (void *handle,
@API__OFF_T@ offset, int whence);
-/* Close the data object with the handle DL. */
+/* Close the data object with the handle HANDLE. */
typedef void (*gpgme_data_release_cb_t) (void *handle);
struct gpgme_data_cbs
@@ -1196,8 +1292,9 @@ typedef struct gpgme_data_cbs *gpgme_data_cbs_t;
@API__SSIZE_T@ gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size);
/* Set the current position from where the next read or write starts
- in the data object with the handle DH to OFFSET, relativ to
- WHENCE. */
+ in the data object with the handle DH to OFFSET, relativ to WHENCE.
+ Returns the new offset in bytes from the beginning of the data
+ object. */
@API__OFF_T@ gpgme_data_seek (gpgme_data_t dh, @API__OFF_T@ offset, int whence);
/* Create a new data buffer and return it in R_DH. */
@@ -1218,7 +1315,8 @@ gpgme_error_t gpgme_data_new_from_mem (gpgme_data_t *r_dh,
size is returned in R_LEN. */
char *gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len);
-/* Release the memory returned by gpgme_data_release_and_get_mem(). */
+/* Release the memory returned by gpgme_data_release_and_get_mem() and
+ some other functions. */
void gpgme_free (void *buffer);
gpgme_error_t gpgme_data_new_from_cbs (gpgme_data_t *dh,
@@ -1245,6 +1343,10 @@ char *gpgme_data_get_file_name (gpgme_data_t dh);
gpgme_error_t gpgme_data_set_file_name (gpgme_data_t dh,
const char *file_name);
+/* Set a flag for the data object DH. See the manual for details. */
+gpg_error_t gpgme_data_set_flag (gpgme_data_t dh,
+ const char *name, const char *value);
+
/* Try to identify the type of the data in DH. */
gpgme_data_type_t gpgme_data_identify (gpgme_data_t dh, int reserved);
@@ -1256,11 +1358,11 @@ gpgme_error_t gpgme_data_new_with_read_cb (gpgme_data_t *r_dh,
int (*read_cb) (void*,char *,
size_t,size_t*),
void *read_cb_value)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
/* Create a new data buffer filled with the content of file FNAME.
COPY must be non-zero. For delayed read, please use
- gpgme_data_new_from_fd or gpgme_data_new_from stream instead. */
+ gpgme_data_new_from_fd or gpgme_data_new_from_stream instead. */
gpgme_error_t gpgme_data_new_from_file (gpgme_data_t *r_dh,
const char *fname,
int copy);
@@ -1274,7 +1376,7 @@ gpgme_error_t gpgme_data_new_from_filepart (gpgme_data_t *r_dh,
/* Reset the read pointer in DH. Deprecated, please use
gpgme_data_seek instead. */
-gpgme_error_t gpgme_data_rewind (gpgme_data_t dh) _GPGME_DEPRECATED;
+gpgme_error_t gpgme_data_rewind (gpgme_data_t dh) _GPGME_DEPRECATED(0,4);
@@ -1304,7 +1406,7 @@ void gpgme_key_release (gpgme_key_t key);
key structure directly instead. */
const char *gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
const void *reserved, int idx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of KEY, which has to be
representable by an unsigned integer. IDX specifies the sub key or
@@ -1312,7 +1414,7 @@ const char *gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
Deprecated, use key structure directly instead. */
unsigned long gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
const void *reserved, int idx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of a signature on user ID
UID_IDX in KEY, which has to be representable by a string. IDX
@@ -1321,7 +1423,7 @@ unsigned long gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
const char *gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx,
_gpgme_attr_t what,
const void *reserved, int idx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of a signature on user ID
UID_IDX in KEY, which has to be representable by an unsigned
@@ -1330,7 +1432,7 @@ const char *gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx,
unsigned long gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx,
_gpgme_attr_t what,
const void *reserved, int idx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
@@ -1355,7 +1457,8 @@ typedef enum
GPGME_ENCRYPT_NO_ENCRYPT_TO = 2,
GPGME_ENCRYPT_PREPARE = 4,
GPGME_ENCRYPT_EXPECT_SIGN = 8,
- GPGME_ENCRYPT_NO_COMPRESS = 16
+ GPGME_ENCRYPT_NO_COMPRESS = 16,
+ GPGME_ENCRYPT_SYMMETRIC = 32
}
gpgme_encrypt_flags_t;
@@ -1471,7 +1574,7 @@ struct _gpgme_new_signature
unsigned int _obsolete_class_2;
#else
/* Must be set to SIG_CLASS below. */
- unsigned int class _GPGME_DEPRECATED_OUTSIDE_GPGME;
+ unsigned int class _GPGME_DEPRECATED_OUTSIDE_GPGME(0,4);
#endif
/* Crypto backend specific signature class. */
@@ -1516,10 +1619,12 @@ typedef enum
GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */
GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */
GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */
- GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occured. */
+ GPGME_SIGSUM_SYS_ERROR = 0x0800, /* A system error occurred. */
+ GPGME_SIGSUM_TOFU_CONFLICT=0x1000 /* Tofu conflict detected. */
}
gpgme_sigsum_t;
+
struct _gpgme_signature
{
struct _gpgme_signature *next;
@@ -1527,7 +1632,7 @@ struct _gpgme_signature
/* A summary of the signature status. */
gpgme_sigsum_t summary;
- /* The fingerprint or key ID of the signature. */
+ /* The fingerprint of the signature. This can be a subkey. */
char *fpr;
/* The status of the signature. */
@@ -1539,7 +1644,7 @@ struct _gpgme_signature
/* Signature creation time. */
unsigned long timestamp;
- /* Signature exipration time or 0. */
+ /* Signature expiration time or 0. */
unsigned long exp_timestamp;
/* Key should not have been used for signing. */
@@ -1565,6 +1670,10 @@ struct _gpgme_signature
/* The mailbox from the PKA information or NULL. */
char *pka_address;
+
+ /* If non-NULL, a possible incomplete key object with the data
+ * available for the signature. */
+ gpgme_key_t key;
};
typedef struct _gpgme_signature *gpgme_signature_t;
@@ -1608,7 +1717,7 @@ struct _gpgme_import_status
/* Fingerprint. */
char *fpr;
- /* If a problem occured, the reason why the key could not be
+ /* If a problem occurred, the reason why the key could not be
imported. Otherwise GPGME_No_Error. */
gpgme_error_t result;
@@ -1676,7 +1785,7 @@ gpgme_import_result_t gpgme_op_import_result (gpgme_ctx_t ctx);
gpgme_error_t gpgme_op_import_start (gpgme_ctx_t ctx, gpgme_data_t keydata);
gpgme_error_t gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata);
gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata,
- int *nr) _GPGME_DEPRECATED;
+ int *nr) _GPGME_DEPRECATED(0,4);
/* Import the keys from the array KEYS into the keyring. */
gpgme_error_t gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t keys[]);
@@ -1715,6 +1824,18 @@ gpgme_error_t gpgme_op_export_keys (gpgme_ctx_t ctx,
* Key generation.
*/
+/* Flags for the key creation functions. */
+#define GPGME_CREATE_SIGN (1 << 0) /* Allow usage: signing. */
+#define GPGME_CREATE_ENCR (1 << 1) /* Allow usage: encryption. */
+#define GPGME_CREATE_CERT (1 << 2) /* Allow usage: certification. */
+#define GPGME_CREATE_AUTH (1 << 3) /* Allow usage: authentication. */
+#define GPGME_CREATE_NOPASSWD (1 << 7) /* Create w/o passphrase. */
+#define GPGME_CREATE_SELFSIGNED (1 << 8) /* Create self-signed cert. */
+#define GPGME_CREATE_NOSTORE (1 << 9) /* Do not store the key. */
+#define GPGME_CREATE_WANTPUB (1 << 10) /* Return the public key. */
+#define GPGME_CREATE_WANTSEC (1 << 11) /* Return the secret key. */
+#define GPGME_CREATE_FORCE (1 << 12) /* Force creation. */
+
struct _gpgme_op_genkey_result
{
/* A primary key was generated. */
@@ -1723,11 +1844,22 @@ struct _gpgme_op_genkey_result
/* A sub key was generated. */
unsigned int sub : 1;
+ /* A user id was generated. */
+ unsigned int uid : 1;
+
/* Internal to GPGME, do not use. */
- unsigned int _unused : 30;
+ unsigned int _unused : 29;
/* The fingerprint of the generated key. */
char *fpr;
+
+ /* A memory data object with the created public key. Only set when
+ * GPGME_CREATE_WANTPUB has been used. */
+ gpgme_data_t pubkey;
+
+ /* A memory data object with the created secret key. Only set when
+ * GPGME_CREATE_WANTSEC has been used. */
+ gpgme_data_t seckey;
};
typedef struct _gpgme_op_genkey_result *gpgme_genkey_result_t;
@@ -1739,7 +1871,55 @@ gpgme_error_t gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
gpgme_error_t gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms,
gpgme_data_t pubkey, gpgme_data_t seckey);
-/* Retrieve a pointer to the result of the genkey operation. */
+/* Generate a key pair using the modern interface. */
+gpgme_error_t gpgme_op_createkey_start (gpgme_ctx_t ctx,
+ const char *userid,
+ const char *algo,
+ unsigned long reserved,
+ unsigned long expires,
+ gpgme_key_t certkey,
+ unsigned int flags);
+gpgme_error_t gpgme_op_createkey (gpgme_ctx_t ctx,
+ const char *userid,
+ const char *algo,
+ unsigned long reserved,
+ unsigned long expires,
+ gpgme_key_t certkey,
+ unsigned int flags);
+/* Add a new subkey to KEY. */
+gpgme_error_t gpgme_op_createsubkey_start (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ const char *algo,
+ unsigned long reserved,
+ unsigned long expires,
+ unsigned int flags);
+gpgme_error_t gpgme_op_createsubkey (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ const char *algo,
+ unsigned long reserved,
+ unsigned long expires,
+ unsigned int flags);
+
+/* Add USERID to an existing KEY. */
+gpgme_error_t gpgme_op_adduid_start (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid,
+ unsigned int reserved);
+gpgme_error_t gpgme_op_adduid (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid,
+ unsigned int reserved);
+
+/* Revoke a USERID from a KEY. */
+gpgme_error_t gpgme_op_revuid_start (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid,
+ unsigned int reserved);
+gpgme_error_t gpgme_op_revuid (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid,
+ unsigned int reserved);
+
+
+
+/* Retrieve a pointer to the result of a genkey, createkey, or
+ * createsubkey operation. */
gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx);
@@ -1750,29 +1930,76 @@ gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key,
gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key,
int allow_secret);
+
+/*
+ * Key signing interface
+ */
+
+/* Flags for the key signing functions. */
+#define GPGME_KEYSIGN_LOCAL (1 << 7) /* Create a local signature. */
+#define GPGME_KEYSIGN_LFSEP (1 << 8) /* Indicate LF separated user ids. */
+#define GPGME_KEYSIGN_NOEXPIRE (1 << 9) /* Force no expiration. */
+
+
+/* Sign the USERID of KEY using the current set of signers. */
+gpgme_error_t gpgme_op_keysign_start (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid,
+ unsigned long expires,
+ unsigned int flags);
+gpgme_error_t gpgme_op_keysign (gpgme_ctx_t ctx,
+ gpgme_key_t key, const char *userid,
+ unsigned long expires,
+ unsigned int flags);
+
+
/*
- * Key Edit interface
+ * Key edit interface
*/
-/* Edit the key KEY. Send status and command requests to FNC and
+/* Flags to select the mode of the interact. */
+#define GPGME_INTERACT_CARD (1 << 0) /* Use --card-edit mode. */
+
+
+/* Edit the KEY. Send status and command requests to FNC and
output of edit commands to OUT. */
+gpgme_error_t gpgme_op_interact_start (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ unsigned int flags,
+ gpgme_interact_cb_t fnc,
+ void *fnc_value,
+ gpgme_data_t out);
+gpgme_error_t gpgme_op_interact (gpgme_ctx_t ctx, gpgme_key_t key,
+ unsigned int flags,
+ gpgme_interact_cb_t fnc,
+ void *fnc_value,
+ gpgme_data_t out);
+
gpgme_error_t gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
gpgme_edit_cb_t fnc, void *fnc_value,
- gpgme_data_t out);
-gpgme_error_t gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key,
- gpgme_edit_cb_t fnc, void *fnc_value,
- gpgme_data_t out);
-
-/* Edit the card for the key KEY. Send status and command requests to
- FNC and output of edit commands to OUT. */
+ gpgme_data_t out) _GPGME_DEPRECATED(1,7);
+gpgme_error_t gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value,
+ gpgme_data_t out) _GPGME_DEPRECATED(1,7);
gpgme_error_t gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
gpgme_edit_cb_t fnc, void *fnc_value,
- gpgme_data_t out);
-gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
- gpgme_edit_cb_t fnc, void *fnc_value,
- gpgme_data_t out);
+ gpgme_data_t out)
+ _GPGME_DEPRECATED(1,7);
+gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value,
+ gpgme_data_t out)
+ _GPGME_DEPRECATED(1,7);
+
+
+/* Set the Tofu policy of KEY to POLCIY. */
+gpgme_error_t gpgme_op_tofu_policy_start (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ gpgme_tofu_policy_t policy);
+gpgme_error_t gpgme_op_tofu_policy (gpgme_ctx_t ctx,
+ gpgme_key_t key,
+ gpgme_tofu_policy_t policy);
+
@@ -1875,7 +2102,7 @@ void gpgme_trust_item_unref (gpgme_trust_item_t item);
/* Release the trust item ITEM. Deprecated, use
gpgme_trust_item_unref. */
-void gpgme_trust_item_release (gpgme_trust_item_t item) _GPGME_DEPRECATED;
+void gpgme_trust_item_release (gpgme_trust_item_t item) _GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of ITEM, which has to be
representable by a string. Deprecated, use trust item structure
@@ -1883,7 +2110,7 @@ void gpgme_trust_item_release (gpgme_trust_item_t item) _GPGME_DEPRECATED;
const char *gpgme_trust_item_get_string_attr (gpgme_trust_item_t item,
_gpgme_attr_t what,
const void *reserved, int idx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of KEY, which has to be
representable by an integer. IDX specifies a running index if the
@@ -1891,7 +2118,7 @@ const char *gpgme_trust_item_get_string_attr (gpgme_trust_item_t item,
item structure directly. */
int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what,
const void *reserved, int idx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(0,4);
@@ -1974,14 +2201,14 @@ struct _gpgme_op_assuan_result
{
/* Deprecated. Use the second value in a DONE event or the
synchronous variant gpgme_op_assuan_transact_ext. */
- gpgme_error_t err _GPGME_DEPRECATED_OUTSIDE_GPGME;
+ gpgme_error_t err _GPGME_DEPRECATED_OUTSIDE_GPGME(1,2);
};
typedef struct _gpgme_op_assuan_result *gpgme_assuan_result_t;
/* Return the result of the last Assuan command. */
gpgme_assuan_result_t gpgme_op_assuan_result (gpgme_ctx_t ctx)
- _GPGME_DEPRECATED;
+ _GPGME_DEPRECATED(1,2);
gpgme_error_t
gpgme_op_assuan_transact (gpgme_ctx_t ctx,
@@ -1991,7 +2218,7 @@ gpgme_op_assuan_transact (gpgme_ctx_t ctx,
gpgme_assuan_inquire_cb_t inq_cb,
void *inq_cb_value,
gpgme_assuan_status_cb_t status_cb,
- void *status_cb_value) _GPGME_DEPRECATED;
+ void *status_cb_value) _GPGME_DEPRECATED(1,2);
/*
@@ -2077,7 +2304,7 @@ typedef struct gpgme_conf_arg
} *gpgme_conf_arg_t;
-/* The flags of a configuration option. See the gpg-conf
+/* The flags of a configuration option. See the gpgconf
documentation for details. */
#define GPGME_CONF_GROUP (1 << 0)
#define GPGME_CONF_OPTIONAL (1 << 1)
@@ -2232,6 +2459,10 @@ gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto);
void gpgme_result_ref (void *result);
void gpgme_result_unref (void *result);
+/* Return a public key algorithm string (e.g. "rsa2048"). Caller must
+ free using gpgme_free. */
+char *gpgme_pubkey_algo_string (gpgme_subkey_t subkey);
+
/* Return a statically allocated string with the name of the public
key algorithm ALGO, or NULL if that name is not known. */
const char *gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo);
@@ -2245,44 +2476,44 @@ const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo);
/*
* Deprecated types.
*/
-typedef gpgme_ctx_t GpgmeCtx _GPGME_DEPRECATED;
-typedef gpgme_data_t GpgmeData _GPGME_DEPRECATED;
-typedef gpgme_error_t GpgmeError _GPGME_DEPRECATED;
-typedef gpgme_data_encoding_t GpgmeDataEncoding _GPGME_DEPRECATED;
-typedef gpgme_pubkey_algo_t GpgmePubKeyAlgo _GPGME_DEPRECATED;
-typedef gpgme_hash_algo_t GpgmeHashAlgo _GPGME_DEPRECATED;
-typedef gpgme_sig_stat_t GpgmeSigStat _GPGME_DEPRECATED;
-typedef gpgme_sig_mode_t GpgmeSigMode _GPGME_DEPRECATED;
-typedef gpgme_attr_t GpgmeAttr _GPGME_DEPRECATED;
-typedef gpgme_validity_t GpgmeValidity _GPGME_DEPRECATED;
-typedef gpgme_protocol_t GpgmeProtocol _GPGME_DEPRECATED;
-typedef gpgme_engine_info_t GpgmeEngineInfo _GPGME_DEPRECATED;
-typedef gpgme_subkey_t GpgmeSubkey _GPGME_DEPRECATED;
-typedef gpgme_key_sig_t GpgmeKeySig _GPGME_DEPRECATED;
-typedef gpgme_user_id_t GpgmeUserID _GPGME_DEPRECATED;
-typedef gpgme_key_t GpgmeKey _GPGME_DEPRECATED;
-typedef gpgme_passphrase_cb_t GpgmePassphraseCb _GPGME_DEPRECATED;
-typedef gpgme_progress_cb_t GpgmeProgressCb _GPGME_DEPRECATED;
-typedef gpgme_io_cb_t GpgmeIOCb _GPGME_DEPRECATED;
-typedef gpgme_register_io_cb_t GpgmeRegisterIOCb _GPGME_DEPRECATED;
-typedef gpgme_remove_io_cb_t GpgmeRemoveIOCb _GPGME_DEPRECATED;
-typedef gpgme_event_io_t GpgmeEventIO _GPGME_DEPRECATED;
-typedef gpgme_event_io_cb_t GpgmeEventIOCb _GPGME_DEPRECATED;
+typedef gpgme_ctx_t GpgmeCtx _GPGME_DEPRECATED(0,4);
+typedef gpgme_data_t GpgmeData _GPGME_DEPRECATED(0,4);
+typedef gpgme_error_t GpgmeError _GPGME_DEPRECATED(0,4);
+typedef gpgme_data_encoding_t GpgmeDataEncoding _GPGME_DEPRECATED(0,4);
+typedef gpgme_pubkey_algo_t GpgmePubKeyAlgo _GPGME_DEPRECATED(0,4);
+typedef gpgme_hash_algo_t GpgmeHashAlgo _GPGME_DEPRECATED(0,4);
+typedef gpgme_sig_stat_t GpgmeSigStat _GPGME_DEPRECATED(0,4);
+typedef gpgme_sig_mode_t GpgmeSigMode _GPGME_DEPRECATED(0,4);
+typedef gpgme_attr_t GpgmeAttr _GPGME_DEPRECATED(0,4);
+typedef gpgme_validity_t GpgmeValidity _GPGME_DEPRECATED(0,4);
+typedef gpgme_protocol_t GpgmeProtocol _GPGME_DEPRECATED(0,4);
+typedef gpgme_engine_info_t GpgmeEngineInfo _GPGME_DEPRECATED(0,4);
+typedef gpgme_subkey_t GpgmeSubkey _GPGME_DEPRECATED(0,4);
+typedef gpgme_key_sig_t GpgmeKeySig _GPGME_DEPRECATED(0,4);
+typedef gpgme_user_id_t GpgmeUserID _GPGME_DEPRECATED(0,4);
+typedef gpgme_key_t GpgmeKey _GPGME_DEPRECATED(0,4);
+typedef gpgme_passphrase_cb_t GpgmePassphraseCb _GPGME_DEPRECATED(0,4);
+typedef gpgme_progress_cb_t GpgmeProgressCb _GPGME_DEPRECATED(0,4);
+typedef gpgme_io_cb_t GpgmeIOCb _GPGME_DEPRECATED(0,4);
+typedef gpgme_register_io_cb_t GpgmeRegisterIOCb _GPGME_DEPRECATED(0,4);
+typedef gpgme_remove_io_cb_t GpgmeRemoveIOCb _GPGME_DEPRECATED(0,4);
+typedef gpgme_event_io_t GpgmeEventIO _GPGME_DEPRECATED(0,4);
+typedef gpgme_event_io_cb_t GpgmeEventIOCb _GPGME_DEPRECATED(0,4);
#define GpgmeIOCbs gpgme_io_cbs
-typedef gpgme_data_read_cb_t GpgmeDataReadCb _GPGME_DEPRECATED;
-typedef gpgme_data_write_cb_t GpgmeDataWriteCb _GPGME_DEPRECATED;
-typedef gpgme_data_seek_cb_t GpgmeDataSeekCb _GPGME_DEPRECATED;
-typedef gpgme_data_release_cb_t GpgmeDataReleaseCb _GPGME_DEPRECATED;
+typedef gpgme_data_read_cb_t GpgmeDataReadCb _GPGME_DEPRECATED(0,4);
+typedef gpgme_data_write_cb_t GpgmeDataWriteCb _GPGME_DEPRECATED(0,4);
+typedef gpgme_data_seek_cb_t GpgmeDataSeekCb _GPGME_DEPRECATED(0,4);
+typedef gpgme_data_release_cb_t GpgmeDataReleaseCb _GPGME_DEPRECATED(0,4);
#define GpgmeDataCbs gpgme_data_cbs
-typedef gpgme_encrypt_result_t GpgmeEncryptResult _GPGME_DEPRECATED;
-typedef gpgme_sig_notation_t GpgmeSigNotation _GPGME_DEPRECATED;
-typedef gpgme_signature_t GpgmeSignature _GPGME_DEPRECATED;
-typedef gpgme_verify_result_t GpgmeVerifyResult _GPGME_DEPRECATED;
-typedef gpgme_import_status_t GpgmeImportStatus _GPGME_DEPRECATED;
-typedef gpgme_import_result_t GpgmeImportResult _GPGME_DEPRECATED;
-typedef gpgme_genkey_result_t GpgmeGenKeyResult _GPGME_DEPRECATED;
-typedef gpgme_trust_item_t GpgmeTrustItem _GPGME_DEPRECATED;
-typedef gpgme_status_code_t GpgmeStatusCode _GPGME_DEPRECATED;
+typedef gpgme_encrypt_result_t GpgmeEncryptResult _GPGME_DEPRECATED(0,4);
+typedef gpgme_sig_notation_t GpgmeSigNotation _GPGME_DEPRECATED(0,4);
+typedef gpgme_signature_t GpgmeSignature _GPGME_DEPRECATED(0,4);
+typedef gpgme_verify_result_t GpgmeVerifyResult _GPGME_DEPRECATED(0,4);
+typedef gpgme_import_status_t GpgmeImportStatus _GPGME_DEPRECATED(0,4);
+typedef gpgme_import_result_t GpgmeImportResult _GPGME_DEPRECATED(0,4);
+typedef gpgme_genkey_result_t GpgmeGenKeyResult _GPGME_DEPRECATED(0,4);
+typedef gpgme_trust_item_t GpgmeTrustItem _GPGME_DEPRECATED(0,4);
+typedef gpgme_status_code_t GpgmeStatusCode _GPGME_DEPRECATED(0,4);
#ifdef __cplusplus
}
diff --git a/src/kdpipeiodevice.cpp b/src/kdpipeiodevice.cpp
deleted file mode 100644
index 5661790..0000000
--- a/src/kdpipeiodevice.cpp
+++ /dev/null
@@ -1,951 +0,0 @@
-/*
- Copyright (C) 2007 Klarälvdalens Datakonsult AB
-
- KDPipeIODevice is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- KDPipeIODevice 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 Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with KDPipeIODevice; see the file COPYING.LIB. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include "kdpipeiodevice.h"
-
-#include <QtCore>
-
-#include <cassert>
-#include <memory>
-#include <algorithm>
-
-#ifdef Q_OS_WIN32
-# ifndef NOMINMAX
-# define NOMINMAX
-# endif
-# include <windows.h>
-# include <io.h>
-#else
-# include <unistd.h>
-# include <errno.h>
-#endif
-
-using namespace _gpgme_;
-
-#ifndef KDAB_CHECK_THIS
-# define KDAB_CHECK_CTOR (void)1
-# define KDAB_CHECK_DTOR KDAB_CHECK_CTOR
-# define KDAB_CHECK_THIS KDAB_CHECK_CTOR
-#endif
-
-#define LOCKED( d ) const QMutexLocker locker( &d->mutex )
-#define synchronized( d ) if ( int i = 0 ) {} else for ( const QMutexLocker locker( &d->mutex ) ; !i ; ++i )
-
-const unsigned int BUFFER_SIZE = 4096;
-const bool ALLOW_QIODEVICE_BUFFERING = true;
-
-// comment to get trace output:
-//#define qDebug if(1){}else qDebug
-
-namespace {
-class Reader : public QThread {
- Q_OBJECT
-public:
- Reader( int fd, Qt::HANDLE handle );
- ~Reader();
-
- qint64 readData( char * data, qint64 maxSize );
-
- unsigned int bytesInBuffer() const {
- return ( wptr + sizeof buffer - rptr ) % sizeof buffer ;
- }
-
- bool bufferFull() const {
- return bytesInBuffer() == sizeof buffer - 1;
- }
-
- bool bufferEmpty() const {
- return bytesInBuffer() == 0;
- }
-
- bool bufferContains( char ch ) {
- const unsigned int bib = bytesInBuffer();
- for ( unsigned int i = rptr ; i < rptr + bib ; ++i )
- if ( buffer[i%sizeof buffer] == ch )
- return true;
- return false;
- }
-
- void notifyReadyRead();
-
-Q_SIGNALS:
- void readyRead();
-
-protected:
- /* reimp */ void run();
-
-private:
- int fd;
- Qt::HANDLE handle;
-public:
- QMutex mutex;
- QWaitCondition waitForCancelCondition;
- QWaitCondition bufferNotFullCondition;
- QWaitCondition bufferNotEmptyCondition;
- QWaitCondition hasStarted;
- QWaitCondition readyReadSentCondition;
- QWaitCondition blockedConsumerIsDoneCondition;
- bool cancel;
- bool eof;
- bool error;
- bool eofShortCut;
- int errorCode;
- bool isReading;
- bool consumerBlocksOnUs;
-
-private:
- unsigned int rptr, wptr;
- char buffer[BUFFER_SIZE+1]; // need to keep one byte free to detect empty state
-};
-
-
-Reader::Reader( int fd_, Qt::HANDLE handle_ )
- : QThread(),
- fd( fd_ ),
- handle( handle_ ),
- mutex(),
- bufferNotFullCondition(),
- bufferNotEmptyCondition(),
- hasStarted(),
- cancel( false ),
- eof( false ),
- error( false ),
- eofShortCut( false ),
- errorCode( 0 ),
- isReading( false ),
- consumerBlocksOnUs( false ),
- rptr( 0 ), wptr( 0 )
-{
-
-}
-
-Reader::~Reader() {}
-
-
-class Writer : public QThread {
- Q_OBJECT
-public:
- Writer( int fd, Qt::HANDLE handle );
- ~Writer();
-
- qint64 writeData( const char * data, qint64 size );
-
- unsigned int bytesInBuffer() const { return numBytesInBuffer; }
-
- bool bufferFull() const {
- return numBytesInBuffer == sizeof buffer;
- }
-
- bool bufferEmpty() const {
- return numBytesInBuffer == 0;
- }
-
-Q_SIGNALS:
- void bytesWritten( qint64 );
-
-protected:
- /* reimp */ void run();
-
-private:
- int fd;
- Qt::HANDLE handle;
-public:
- QMutex mutex;
- QWaitCondition bufferEmptyCondition;
- QWaitCondition bufferNotEmptyCondition;
- QWaitCondition hasStarted;
- bool cancel;
- bool error;
- int errorCode;
-private:
- unsigned int numBytesInBuffer;
- char buffer[BUFFER_SIZE];
-};
-}
-
-Writer::Writer( int fd_, Qt::HANDLE handle_ )
- : QThread(),
- fd( fd_ ),
- handle( handle_ ),
- mutex(),
- bufferEmptyCondition(),
- bufferNotEmptyCondition(),
- hasStarted(),
- cancel( false ),
- error( false ),
- errorCode( 0 ),
- numBytesInBuffer( 0 )
-{
-
-}
-
-Writer::~Writer() {}
-
-
-class KDPipeIODevice::Private : public QObject {
-Q_OBJECT
- friend class ::KDPipeIODevice;
- KDPipeIODevice * const q;
-public:
- explicit Private( KDPipeIODevice * qq );
- ~Private();
-
- bool doOpen( int, Qt::HANDLE, OpenMode );
- bool startReaderThread();
- bool startWriterThread();
- void stopThreads();
-
-public Q_SLOTS:
- void emitReadyRead();
-
-private:
- int fd;
- Qt::HANDLE handle;
- Reader * reader;
- Writer * writer;
- bool triedToStartReader;
- bool triedToStartWriter;
-};
-
-KDPipeIODevice::Private::Private( KDPipeIODevice * qq )
- : QObject( qq ), q( qq ),
- fd( -1 ),
- handle( 0 ),
- reader( 0 ),
- writer( 0 ),
- triedToStartReader( false ), triedToStartWriter( false )
-{
-
-}
-
-KDPipeIODevice::Private::~Private() {
- qDebug( "KDPipeIODevice::~Private(): Destroying %p", q );
-}
-
-KDPipeIODevice::KDPipeIODevice( QObject * p )
- : QIODevice( p ), d( new Private( this ) )
-{
- KDAB_CHECK_CTOR;
-}
-
-KDPipeIODevice::KDPipeIODevice( int fd, OpenMode mode, QObject * p )
- : QIODevice( p ), d( new Private( this ) )
-{
- KDAB_CHECK_CTOR;
- open( fd, mode );
-}
-
-KDPipeIODevice::KDPipeIODevice( Qt::HANDLE handle, OpenMode mode, QObject * p )
- : QIODevice( p ), d( new Private( this ) )
-{
- KDAB_CHECK_CTOR;
- open( handle, mode );
-}
-
-KDPipeIODevice::~KDPipeIODevice() { KDAB_CHECK_DTOR;
- if ( isOpen() )
- close();
- delete d; d = 0;
-}
-
-
-bool KDPipeIODevice::open( int fd, OpenMode mode ) { KDAB_CHECK_THIS;
-
-#ifdef Q_OS_WIN32
- return d->doOpen( fd, (HANDLE)_get_osfhandle( fd ), mode );
-#else
- return d->doOpen( fd, 0, mode );
-#endif
-
-}
-
-bool KDPipeIODevice::open( Qt::HANDLE h, OpenMode mode ) { KDAB_CHECK_THIS;
-
-#ifdef Q_OS_WIN32
- return d->doOpen( -1, h, mode );
-#else
- Q_UNUSED( h );
- Q_UNUSED( mode );
- assert( !"KDPipeIODevice::open( Qt::HANDLE, OpenMode ) should never be called except on Windows." );
-#endif
-
-}
-
-bool KDPipeIODevice::Private::startReaderThread()
-{
- if ( triedToStartReader )
- return true;
- triedToStartReader = true;
- if ( reader && !reader->isRunning() && !reader->isFinished() ) {
- qDebug("KDPipeIODevice::Private::startReaderThread(): locking reader (CONSUMER THREAD)" );
- LOCKED( reader );
- qDebug("KDPipeIODevice::Private::startReaderThread(): locked reader (CONSUMER THREAD)" );
- reader->start( QThread::HighestPriority );
- qDebug("KDPipeIODevice::Private::startReaderThread(): waiting for hasStarted (CONSUMER THREAD)" );
- const bool hasStarted = reader->hasStarted.wait( &reader->mutex, 1000 );
- qDebug("KDPipeIODevice::Private::startReaderThread(): returned from hasStarted (CONSUMER THREAD)" );
-
- return hasStarted;
- }
- return true;
-}
-
-bool KDPipeIODevice::Private::startWriterThread()
-{
- if ( triedToStartWriter )
- return true;
- triedToStartWriter = true;
- if ( writer && !writer->isRunning() && !writer->isFinished() ) {
- LOCKED( writer );
-
- writer->start( QThread::HighestPriority );
- if ( !writer->hasStarted.wait( &writer->mutex, 1000 ) )
- return false;
- }
- return true;
-}
-
-void KDPipeIODevice::Private::emitReadyRead()
-{
- QPointer<Private> thisPointer( this );
- qDebug( "KDPipeIODevice::Private::emitReadyRead %p", this );
-
- emit q->readyRead();
-
- if ( !thisPointer )
- return;
-
- bool mustNotify = false;
-
- if ( reader ) {
- qDebug( "KDPipeIODevice::Private::emitReadyRead %p: locking reader (CONSUMER THREAD)", this );
- synchronized( reader ) {
- qDebug( "KDPipeIODevice::Private::emitReadyRead %p: locked reader (CONSUMER THREAD)", this );
- reader->readyReadSentCondition.wakeAll();
- mustNotify = !reader->bufferEmpty() && reader->isReading;
- qDebug( "KDPipeIODevice::emitReadyRead %p: bufferEmpty: %d reader in ReadFile: %d", this, reader->bufferEmpty(), reader->isReading );
- }
- }
- if ( mustNotify )
- QTimer::singleShot( 100, this, SLOT( emitReadyRead() ) );
- qDebug( "KDPipeIODevice::Private::emitReadyRead %p leaving", this );
-
-}
-
-bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode_ ) {
-
- if ( q->isOpen() )
- return false;
-
-#ifdef Q_OS_WIN32
- if ( !handle_ )
- return false;
-#else
- if ( fd_ < 0 )
- return false;
-#endif
-
- if ( !(mode_ & ReadWrite) )
- return false; // need to have at least read -or- write
-
-
- std::auto_ptr<Reader> reader_;
- std::auto_ptr<Writer> writer_;
-
- if ( mode_ & ReadOnly ) {
- reader_.reset( new Reader( fd_, handle_ ) );
- qDebug( "KDPipeIODevice::doOpen (%p): created reader (%p) for fd %d", this, reader_.get(), fd_ );
- connect( reader_.get(), SIGNAL(readyRead()), this, SLOT(emitReadyRead()),
-Qt::QueuedConnection );
- }
- if ( mode_ & WriteOnly ) {
- writer_.reset( new Writer( fd_, handle_ ) );
- qDebug( "KDPipeIODevice::doOpen (%p): created writer (%p) for fd %d", this, writer_.get(), fd_ );
- connect( writer_.get(), SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)),
-Qt::QueuedConnection );
- }
-
- // commit to *this:
- fd = fd_;
- handle = handle_;
- reader = reader_.release();
- writer = writer_.release();
-
- q->setOpenMode( mode_|Unbuffered );
- return true;
-}
-
-int KDPipeIODevice::descriptor() const { KDAB_CHECK_THIS;
- return d->fd;
-}
-
-
-Qt::HANDLE KDPipeIODevice::handle() const { KDAB_CHECK_THIS;
- return d->handle;
-}
-
-qint64 KDPipeIODevice::bytesAvailable() const { KDAB_CHECK_THIS;
- const qint64 base = QIODevice::bytesAvailable();
- if ( !d->triedToStartReader ) {
- d->startReaderThread();
- return base;
- }
- if ( d->reader )
- synchronized( d->reader ) {
- const qint64 inBuffer = d->reader->bytesInBuffer();
- return base + inBuffer;
- }
- return base;
-}
-
-qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS;
- d->startWriterThread();
- const qint64 base = QIODevice::bytesToWrite();
- if ( d->writer )
- synchronized( d->writer ) return base + d->writer->bytesInBuffer();
- return base;
-}
-
-bool KDPipeIODevice::canReadLine() const { KDAB_CHECK_THIS;
- d->startReaderThread();
- if ( QIODevice::canReadLine() )
- return true;
- if ( d->reader )
- synchronized( d->reader ) return d->reader->bufferContains( '\n' );
- return true;
-}
-
-bool KDPipeIODevice::isSequential() const {
- return true;
-}
-
-bool KDPipeIODevice::atEnd() const { KDAB_CHECK_THIS;
- d->startReaderThread();
- if ( !QIODevice::atEnd() ) {
- qDebug( "%p: KDPipeIODevice::atEnd returns false since QIODevice::atEnd does (with bytesAvailable=%ld)", this, static_cast<long>(bytesAvailable()) );
- return false;
- }
- if ( !isOpen() )
- return true;
- if ( d->reader->eofShortCut )
- return true;
- LOCKED( d->reader );
- const bool eof = ( d->reader->error || d->reader->eof ) && d->reader->bufferEmpty();
- if ( !eof ) {
- if ( !d->reader->error && !d->reader->eof )
- qDebug( "%p: KDPipeIODevice::atEnd returns false since !reader->error && !reader->eof", this );
- if ( !d->reader->bufferEmpty() )
- qDebug( "%p: KDPipeIODevice::atEnd returns false since !reader->bufferEmpty()", this );
- }
- return eof;
-}
-
-bool KDPipeIODevice::waitForBytesWritten( int msecs ) { KDAB_CHECK_THIS;
- d->startWriterThread();
- Writer * const w = d->writer;
- if ( !w )
- return true;
- LOCKED( w );
- qDebug( "KDPipeIODevice::waitForBytesWritten (%p,w=%p): entered locked area", this, w
-);
- return w->bufferEmpty() || w->error || w->bufferEmptyCondition.wait( &w->mutex, msecs ) ;
-}
-
-bool KDPipeIODevice::waitForReadyRead( int msecs ) { KDAB_CHECK_THIS;
- qDebug( "KDPipeIODEvice::waitForReadyRead()(%p)", this);
- d->startReaderThread();
- if ( ALLOW_QIODEVICE_BUFFERING ) {
- if ( bytesAvailable() > 0 )
- return true;
- }
- Reader * const r = d->reader;
- if ( !r || r->eofShortCut )
- return true;
- LOCKED( r );
- if ( r->bytesInBuffer() != 0 || r->eof || r->error )
- return true;
-
- return msecs >= 0 ? r->bufferNotEmptyCondition.wait( &r->mutex, msecs ) : r->bufferNotEmptyCondition.wait( &r->mutex );
-}
-
-template <typename T>
-class TemporaryValue {
-public:
- TemporaryValue( T& var_, const T& tv ) : var( var_ ), oldValue( var_ ) { var = tv; }
- ~TemporaryValue() { var = oldValue; }
-private:
- T& var;
- const T oldValue;
-};
-
-
-bool KDPipeIODevice::readWouldBlock() const
-{
- d->startReaderThread();
- LOCKED( d->reader );
- return d->reader->bufferEmpty() && !d->reader->eof && !d->reader->error;
-}
-
-bool KDPipeIODevice::writeWouldBlock() const
-{
- d->startWriterThread();
- LOCKED( d->writer );
- return !d->writer->bufferEmpty() && !d->writer->error;
-}
-
-
-qint64 KDPipeIODevice::readData( char * data, qint64 maxSize ) { KDAB_CHECK_THIS;
- qDebug( "%p: KDPipeIODevice::readData: data=%p, maxSize=%lld", this, data, maxSize );
- d->startReaderThread();
- Reader * const r = d->reader;
-
- assert( r );
-
-
- //assert( r->isRunning() ); // wrong (might be eof, error)
- assert( data || maxSize == 0 );
- assert( maxSize >= 0 );
-
- if ( r->eofShortCut ) {
- qDebug( "%p: KDPipeIODevice::readData: hit eofShortCut, returning 0", this );
- return 0;
- }
-
- if ( maxSize < 0 )
- maxSize = 0;
-
- if ( ALLOW_QIODEVICE_BUFFERING ) {
- if ( bytesAvailable() > 0 )
- maxSize = std::min( maxSize, bytesAvailable() ); // don't block
- }
- qDebug( "%p: KDPipeIODevice::readData: try to lock reader (CONSUMER THREAD)", this );
- LOCKED( r );
- qDebug( "%p: KDPipeIODevice::readData: locked reader (CONSUMER THREAD)", this );
-
- r->readyReadSentCondition.wakeAll();
- if ( /* maxSize > 0 && */ r->bufferEmpty() && !r->error && !r->eof ) { // ### block on maxSize == 0?
- qDebug( "%p: KDPipeIODevice::readData: waiting for bufferNotEmptyCondition (CONSUMER THREAD)", this );
- const TemporaryValue<bool> tmp( d->reader->consumerBlocksOnUs, true );
- r->bufferNotEmptyCondition.wait( &r->mutex );
- r->blockedConsumerIsDoneCondition.wakeAll();
- qDebug( "%p: KDPipeIODevice::readData: woke up from bufferNotEmptyCondition (CONSUMER THREAD)", this );
- }
-
- if ( r->bufferEmpty() ) {
- qDebug( "%p: KDPipeIODevice::readData: got empty buffer, signal eof", this );
- // woken with an empty buffer must mean either EOF or error:
- assert( r->eof || r->error );
- r->eofShortCut = true;
- return r->eof ? 0 : -1 ;
- }
-
- qDebug( "%p: KDPipeIODevice::readData: got bufferNotEmptyCondition, trying to read %lld bytes", this, maxSize );
- const qint64 bytesRead = r->readData( data, maxSize );
- qDebug( "%p: KDPipeIODevice::readData: read %lld bytes", this, bytesRead );
- qDebug( "%p (fd=%d): KDPipeIODevice::readData: %s", this, d->fd, data );
-
- return bytesRead;
-}
-
-qint64 Reader::readData( char * data, qint64 maxSize ) {
- qint64 numRead = rptr < wptr ? wptr - rptr : sizeof buffer - rptr ;
- if ( numRead > maxSize )
- numRead = maxSize;
-
- qDebug( "%p: KDPipeIODevice::readData: data=%p, maxSize=%lld; rptr=%u, wptr=%u (bytesInBuffer=%u); -> numRead=%lld", this,
- data, maxSize, rptr, wptr, bytesInBuffer(), numRead );
-
- std::memcpy( data, buffer + rptr, numRead );
-
- rptr = ( rptr + numRead ) % sizeof buffer ;
-
- if ( !bufferFull() ) {
- qDebug( "%p: KDPipeIODevice::readData: signal bufferNotFullCondition", this );
- bufferNotFullCondition.wakeAll();
- }
-
- return numRead;
-}
-
-qint64 KDPipeIODevice::writeData( const char * data, qint64 size ) { KDAB_CHECK_THIS;
- d->startWriterThread();
- Writer * const w = d->writer;
-
- assert( w );
- assert( w->error || w->isRunning() );
- assert( data || size == 0 );
- assert( size >= 0 );
-
- LOCKED( w );
-
- while ( !w->error && !w->bufferEmpty() ) {
- qDebug( "%p: KDPipeIODevice::writeData: wait for empty buffer", this );
- w->bufferEmptyCondition.wait( &w->mutex );
- qDebug( "%p: KDPipeIODevice::writeData: empty buffer signaled", this );
-
- }
- if ( w->error )
- return -1;
-
- assert( w->bufferEmpty() );
-
- return w->writeData( data, size );
-}
-
-qint64 Writer::writeData( const char * data, qint64 size ) {
- assert( bufferEmpty() );
-
- if ( size > static_cast<qint64>( sizeof buffer ) )
- size = sizeof buffer;
-
- std::memcpy( buffer, data, size );
-
- numBytesInBuffer = size;
-
- if ( !bufferEmpty() ) {
- bufferNotEmptyCondition.wakeAll();
- }
- return size;
-}
-
-void KDPipeIODevice::Private::stopThreads()
-{
- if ( triedToStartWriter )
- {
- if ( writer && q->bytesToWrite() > 0 )
- q->waitForBytesWritten( -1 );
-
- assert( q->bytesToWrite() == 0 );
- }
- if ( Reader * & r = reader ) {
- disconnect( r, SIGNAL( readyRead() ), this, SLOT( emitReadyRead() ) );
- synchronized( r ) {
- // tell thread to cancel:
- r->cancel = true;
- // and wake it, so it can terminate:
- r->waitForCancelCondition.wakeAll();
- r->bufferNotFullCondition.wakeAll();
- r->readyReadSentCondition.wakeAll();
- }
- }
- if ( Writer * & w = writer ) {
- synchronized( w ) {
- // tell thread to cancel:
- w->cancel = true;
- // and wake it, so it can terminate:
- w->bufferNotEmptyCondition.wakeAll();
- }
- }
-}
-
-void KDPipeIODevice::close() { KDAB_CHECK_THIS;
- qDebug( "KDPipeIODevice::close(%p)", this );
- if ( !isOpen() )
- return;
-
- // tell clients we're about to close:
- emit aboutToClose();
- d->stopThreads();
-
-#define waitAndDelete( t ) if ( t ) { t->wait(); QThread* const t2 = t; t = 0; delete t2; }
- qDebug( "KPipeIODevice::close(%p): wait and closing writer %p", this, d->writer );
- waitAndDelete( d->writer );
- qDebug( "KPipeIODevice::close(%p): wait and closing reader %p", this, d->reader );
- if ( d->reader ) {
- LOCKED( d->reader );
- d->reader->readyReadSentCondition.wakeAll();
- }
- waitAndDelete( d->reader );
-#undef waitAndDelete
-#ifdef Q_OS_WIN32
- if ( d->fd != -1 )
- _close( d->fd );
- else
- CloseHandle( d->handle );
-#else
- ::close( d->fd );
-#endif
-
- setOpenMode( NotOpen );
- d->fd = -1;
- d->handle = 0;
-}
-
-void Reader::run() {
-
- LOCKED( this );
-
- // too bad QThread doesn't have that itself; a signal isn't enough
- hasStarted.wakeAll();
-
- qDebug( "%p: Reader::run: started", this );
-
- while ( true ) {
- if ( !cancel && ( eof || error ) ) {
- //notify the client until the buffer is empty and then once
- //again so he receives eof/error. After that, wait for him
- //to cancel
- const bool wasEmpty = bufferEmpty();
- qDebug( "%p: Reader::run: received eof(%d) or error(%d), waking everyone", this, eof, error );
- notifyReadyRead();
- if ( !cancel && wasEmpty )
- waitForCancelCondition.wait( &mutex );
- } else if ( !cancel && !bufferFull() && !bufferEmpty() ) {
- qDebug( "%p: Reader::run: buffer no longer empty, waking everyone", this );
- notifyReadyRead();
- }
-
- while ( !cancel && !error && bufferFull() ) {
- notifyReadyRead();
- if ( !cancel && bufferFull() ) {
- qDebug( "%p: Reader::run: buffer is full, going to sleep", this );
- bufferNotFullCondition.wait( &mutex );
- }
- }
-
- if ( cancel ) {
- qDebug( "%p: Reader::run: detected cancel", this );
- goto leave;
- }
-
- if ( !eof && !error ) {
- if ( rptr == wptr ) // optimize for larger chunks in case the buffer is empty
- rptr = wptr = 0;
-
- unsigned int numBytes = ( rptr + sizeof buffer - wptr - 1 ) % sizeof buffer;
- if ( numBytes > sizeof buffer - wptr )
- numBytes = sizeof buffer - wptr;
-
- qDebug( "%p: Reader::run: rptr=%d, wptr=%d -> numBytes=%d", this, rptr, wptr, numBytes );
-
- assert( numBytes > 0 );
-
- qDebug( "%p: Reader::run: trying to read %d bytes", this, numBytes );
-#ifdef Q_OS_WIN32
- isReading = true;
- mutex.unlock();
- DWORD numRead;
- const bool ok = ReadFile( handle, buffer + wptr, numBytes, &numRead, 0 );
- mutex.lock();
- isReading = false;
- if ( ok ) {
- if ( numRead == 0 ) {
- qDebug( "%p: Reader::run: got eof (numRead==0)", this );
- eof = true;
- }
- } else { // !ok
- errorCode = static_cast<int>( GetLastError() );
- if ( errorCode == ERROR_BROKEN_PIPE ) {
- assert( numRead == 0 );
- qDebug( "%p: Reader::run: got eof (broken pipe)", this );
- eof = true;
- } else {
- assert( numRead == 0 );
- qDebug( "%p: Reader::run: got error: %s (%d)", this, strerror( errorCode ), errorCode );
- error = true;
- }
- }
-#else
- qint64 numRead;
- mutex.unlock();
- do {
- numRead = ::read( fd, buffer + wptr, numBytes );
- } while ( numRead == -1 && errno == EINTR );
- mutex.lock();
-
- if ( numRead < 0 ) {
- errorCode = errno;
- error = true;
- qDebug( "%p: Reader::run: got error: %d", this, errorCode );
- } else if ( numRead == 0 ) {
- qDebug( "%p: Reader::run: eof detected", this );
- eof = true;
- }
-#endif
- qDebug( "%p: Reader::run: read %ld bytes", this, static_cast<long>(numRead) );
- qDebug( "%p: Reader::run(fd=%d): %s", this, fd, buffer );
-
- if ( numRead > 0 ) {
- qDebug( "%p: Reader::run: buffer before: rptr=%4d, wptr=%4d", this, rptr, wptr );
- wptr = ( wptr + numRead ) % sizeof buffer;
- qDebug( "%p: Reader::run: buffer after: rptr=%4d, wptr=%4d", this, rptr, wptr );
- }
- }
- }
- leave:
- qDebug( "%p: Reader::run: terminated", this );
-}
-
-void Reader::notifyReadyRead()
-{
- qDebug( "notifyReadyRead: %d bytes available", bytesInBuffer() );
- assert( !cancel );
-
- if ( consumerBlocksOnUs ) {
- bufferNotEmptyCondition.wakeAll();
- blockedConsumerIsDoneCondition.wait( &mutex );
- return;
- }
- qDebug( "notifyReadyRead: emit signal" );
- emit readyRead();
- readyReadSentCondition.wait( &mutex );
- qDebug( "notifyReadyRead: returning from waiting, leave" );
-}
-
-void Writer::run() {
-
- LOCKED( this );
-
- // too bad QThread doesn't have that itself; a signal isn't enough
- hasStarted.wakeAll();
-
- qDebug( "%p: Writer::run: started", this );
-
- while ( true ) {
-
- while ( !cancel && bufferEmpty() ) {
- qDebug( "%p: Writer::run: buffer is empty, wake bufferEmptyCond listeners", this );
- bufferEmptyCondition.wakeAll();
- emit bytesWritten( 0 );
- qDebug( "%p: Writer::run: buffer is empty, going to sleep", this );
- bufferNotEmptyCondition.wait( &mutex );
- qDebug( "%p: Writer::run: woke up", this );
- }
-
- if ( cancel ) {
- qDebug( "%p: Writer::run: detected cancel", this );
- goto leave;
- }
-
- assert( numBytesInBuffer > 0 );
-
- qDebug( "%p: Writer::run: Trying to write %u bytes", this, numBytesInBuffer );
- qint64 totalWritten = 0;
- do {
- mutex.unlock();
-#ifdef Q_OS_WIN32
- DWORD numWritten;
- qDebug( "%p (fd=%d): Writer::run: buffer before WriteFile (numBytes=%lld): %s:", this, fd, numBytesInBuffer, buffer );
- qDebug( "%p (fd=%d): Writer::run: Going into WriteFile", this, fd );
- if ( !WriteFile( handle, buffer + totalWritten, numBytesInBuffer - totalWritten, &numWritten, 0 ) ) {
- mutex.lock();
- errorCode = static_cast<int>( GetLastError() );
- qDebug( "%p: Writer::run: got error code: %d", this, errorCode );
- error = true;
- goto leave;
- }
-#else
- qint64 numWritten;
- do {
- numWritten = ::write( fd, buffer + totalWritten, numBytesInBuffer - totalWritten );
- } while ( numWritten == -1 && errno == EINTR );
-
- if ( numWritten < 0 ) {
- mutex.lock();
- errorCode = errno;
- qDebug( "%p: Writer::run: got error code: %d", this, errorCode );
- error = true;
- goto leave;
- }
-#endif
- qDebug( "%p (fd=%d): Writer::run: buffer after WriteFile (numBytes=%u): %s:", this, fd, numBytesInBuffer, buffer );
- totalWritten += numWritten;
- mutex.lock();
- } while ( totalWritten < numBytesInBuffer );
-
- qDebug( "%p: Writer::run: wrote %lld bytes", this, totalWritten );
-
- numBytesInBuffer = 0;
-
- qDebug( "%p: Writer::run: buffer is empty, wake bufferEmptyCond listeners", this );
- bufferEmptyCondition.wakeAll();
- emit bytesWritten( totalWritten );
- }
- leave:
- qDebug( "%p: Writer::run: terminating", this );
- numBytesInBuffer = 0;
- qDebug( "%p: Writer::run: buffer is empty, wake bufferEmptyCond listeners", this );
- bufferEmptyCondition.wakeAll();
- emit bytesWritten( 0 );
-}
-
-// static
-std::pair<KDPipeIODevice*,KDPipeIODevice*> KDPipeIODevice::makePairOfConnectedPipes() {
- KDPipeIODevice * read = 0;
- KDPipeIODevice * write = 0;
-#ifdef Q_OS_WIN32
- HANDLE rh;
- HANDLE wh;
- SECURITY_ATTRIBUTES sa;
- memset( &sa, 0, sizeof(sa) );
- sa.nLength = sizeof(sa);
- sa.bInheritHandle = TRUE;
- if ( CreatePipe( &rh, &wh, &sa, BUFFER_SIZE ) ) {
- read = new KDPipeIODevice;
- read->open( rh, ReadOnly );
- write = new KDPipeIODevice;
- write->open( wh, WriteOnly );
- }
-#else
- int fds[2];
- if ( pipe( fds ) == 0 ) {
- read = new KDPipeIODevice;
- read->open( fds[0], ReadOnly );
- write = new KDPipeIODevice;
- write->open( fds[1], WriteOnly );
- }
-#endif
- return std::make_pair( read, write );
-}
-
-#ifdef KDAB_DEFINE_CHECKS
-KDAB_DEFINE_CHECKS( KDPipeIODevice ) {
- if ( !isOpen() ) {
- assert( openMode() == NotOpen );
- assert( !d->reader );
- assert( !d->writer );
-#ifdef Q_OS_WIN32
- assert( !d->handle );
-#else
- assert( d->fd < 0 );
-#endif
- } else {
- assert( openMode() != NotOpen );
- assert( openMode() & ReadWrite );
- if ( openMode() & ReadOnly ) {
- assert( d->reader );
- synchronized( d->reader )
- assert( d->reader->eof || d->reader->error || d->reader->isRunning() );
- }
- if ( openMode() & WriteOnly ) {
- assert( d->writer );
- synchronized( d->writer )
- assert( d->writer->error || d->writer->isRunning() );
- }
-#ifdef Q_OS_WIN32
- assert( d->handle );
-#else
- assert( d->fd >= 0 );
-#endif
- }
-}
-#endif // KDAB_DEFINE_CHECKS
-
-#include "moc_kdpipeiodevice.cpp"
-#include "kdpipeiodevice.moc"
diff --git a/src/kdpipeiodevice.h b/src/kdpipeiodevice.h
deleted file mode 100644
index 8da6af6..0000000
--- a/src/kdpipeiodevice.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- Copyright (C) 2007 Klarälvdalens Datakonsult AB
-
- KDPipeIODevice is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- KDPipeIODevice 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 Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with KDPipeIODevice; see the file COPYING.LIB. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#ifndef __KDTOOLSCORE_KDPIPEIODEVICE_H__
-#define __KDTOOLSCORE_KDPIPEIODEVICE_H__
-
-#include <QIODevice>
-
-#include <utility>
-
-//#include "checker.h"
-
-namespace _gpgme_ {
-
-class KDPipeIODevice : public QIODevice {
- Q_OBJECT
- //KDAB_MAKE_CHECKABLE( KDPipeIODevice )
-public:
- explicit KDPipeIODevice( QObject * parent=0 );
- explicit KDPipeIODevice( int fd, OpenMode=ReadOnly, QObject * parent=0 );
- explicit KDPipeIODevice( Qt::HANDLE handle, OpenMode=ReadOnly, QObject * parent=0 );
- ~KDPipeIODevice();
-
- static std::pair<KDPipeIODevice*, KDPipeIODevice*> makePairOfConnectedPipes();
-
- bool open( int fd, OpenMode mode=ReadOnly );
- bool open( Qt::HANDLE handle, OpenMode mode=ReadOnly );
-
- Qt::HANDLE handle() const;
- int descriptor() const;
-
- bool readWouldBlock() const;
- bool writeWouldBlock() const;
-
- /* reimp */ qint64 bytesAvailable() const;
- /* reimp */ qint64 bytesToWrite() const;
- /* reimp */ bool canReadLine() const;
- /* reimp */ void close();
- /* reimp */ bool isSequential() const;
- /* reimp */ bool atEnd() const;
-
- /* reimp */ bool waitForBytesWritten( int msecs );
- /* reimp */ bool waitForReadyRead( int msecs );
-
-protected:
- /* reimp */ qint64 readData( char * data, qint64 maxSize );
- /* reimp */ qint64 writeData( const char * data, qint64 maxSize );
-
-private:
- class Private;
- Private * d;
-};
-
-} /* namespace _gpgme_ */
-
-#endif /* __KDTOOLSCORE_KDPIPEIODEVICE_H__ */
-
diff --git a/src/kdpipeiodevice.moc b/src/kdpipeiodevice.moc
deleted file mode 100644
index 457f371..0000000
--- a/src/kdpipeiodevice.moc
+++ /dev/null
@@ -1,183 +0,0 @@
-/****************************************************************************
-** Meta object code from reading C++ file 'kdpipeiodevice.cpp'
-**
-** Created: Tue Oct 2 19:30:13 2007
-** by: The Qt Meta Object Compiler version 59 (Qt 4.3.1)
-**
-** WARNING! All changes made in this file will be lost!
-*****************************************************************************/
-
-#if !defined(Q_MOC_OUTPUT_REVISION)
-#error "The header file 'kdpipeiodevice.cpp' doesn't include <QObject>."
-#elif Q_MOC_OUTPUT_REVISION != 59
-#error "This file was generated using the moc from 4.3.1. It"
-#error "cannot be used with the include files from this version of Qt."
-#error "(The moc has changed too much.)"
-#endif
-
-static const uint qt_meta_data_Reader[] = {
-
- // content:
- 1, // revision
- 0, // classname
- 0, 0, // classinfo
- 1, 10, // methods
- 0, 0, // properties
- 0, 0, // enums/sets
-
- // signals: signature, parameters, type, tag, flags
- 8, 7, 7, 7, 0x05,
-
- 0 // eod
-};
-
-static const char qt_meta_stringdata_Reader[] = {
- "Reader\0\0readyRead()\0"
-};
-
-const QMetaObject Reader::staticMetaObject = {
- { &QThread::staticMetaObject, qt_meta_stringdata_Reader,
- qt_meta_data_Reader, 0 }
-};
-
-const QMetaObject *Reader::metaObject() const
-{
- return &staticMetaObject;
-}
-
-void *Reader::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_Reader))
- return static_cast<void*>(const_cast< Reader*>(this));
- return QThread::qt_metacast(_clname);
-}
-
-int Reader::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QThread::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- if (_c == QMetaObject::InvokeMetaMethod) {
- switch (_id) {
- case 0: readyRead(); break;
- }
- _id -= 1;
- }
- return _id;
-}
-
-// SIGNAL 0
-void Reader::readyRead()
-{
- QMetaObject::activate(this, &staticMetaObject, 0, 0);
-}
-static const uint qt_meta_data_Writer[] = {
-
- // content:
- 1, // revision
- 0, // classname
- 0, 0, // classinfo
- 1, 10, // methods
- 0, 0, // properties
- 0, 0, // enums/sets
-
- // signals: signature, parameters, type, tag, flags
- 8, 7, 7, 7, 0x05,
-
- 0 // eod
-};
-
-static const char qt_meta_stringdata_Writer[] = {
- "Writer\0\0bytesWritten(qint64)\0"
-};
-
-const QMetaObject Writer::staticMetaObject = {
- { &QThread::staticMetaObject, qt_meta_stringdata_Writer,
- qt_meta_data_Writer, 0 }
-};
-
-const QMetaObject *Writer::metaObject() const
-{
- return &staticMetaObject;
-}
-
-void *Writer::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_Writer))
- return static_cast<void*>(const_cast< Writer*>(this));
- return QThread::qt_metacast(_clname);
-}
-
-int Writer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QThread::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- if (_c == QMetaObject::InvokeMetaMethod) {
- switch (_id) {
- case 0: bytesWritten((*reinterpret_cast< qint64(*)>(_a[1]))); break;
- }
- _id -= 1;
- }
- return _id;
-}
-
-// SIGNAL 0
-void Writer::bytesWritten(qint64 _t1)
-{
- void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
- QMetaObject::activate(this, &staticMetaObject, 0, _a);
-}
-static const uint qt_meta_data_KDPipeIODevice__Private[] = {
-
- // content:
- 1, // revision
- 0, // classname
- 0, 0, // classinfo
- 1, 10, // methods
- 0, 0, // properties
- 0, 0, // enums/sets
-
- // slots: signature, parameters, type, tag, flags
- 25, 24, 24, 24, 0x0a,
-
- 0 // eod
-};
-
-static const char qt_meta_stringdata_KDPipeIODevice__Private[] = {
- "KDPipeIODevice::Private\0\0emitReadyRead()\0"
-};
-
-const QMetaObject KDPipeIODevice::Private::staticMetaObject = {
- { &QObject::staticMetaObject, qt_meta_stringdata_KDPipeIODevice__Private,
- qt_meta_data_KDPipeIODevice__Private, 0 }
-};
-
-const QMetaObject *KDPipeIODevice::Private::metaObject() const
-{
- return &staticMetaObject;
-}
-
-void *KDPipeIODevice::Private::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_KDPipeIODevice__Private))
- return static_cast<void*>(const_cast< Private*>(this));
- return QObject::qt_metacast(_clname);
-}
-
-int KDPipeIODevice::Private::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QObject::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- if (_c == QMetaObject::InvokeMetaMethod) {
- switch (_id) {
- case 0: emitReadyRead(); break;
- }
- _id -= 1;
- }
- return _id;
-}
diff --git a/src/key.c b/src/key.c
index 1a68966..38acc71 100644
--- a/src/key.c
+++ b/src/key.c
@@ -31,6 +31,8 @@
#include "ops.h"
#include "sema.h"
#include "debug.h"
+#include "mbox-util.h"
+
/* Protects all reference counters in keys. All other accesses to a
@@ -233,6 +235,14 @@ _gpgme_key_append_name (gpgme_key_t key, const char *src, int convert)
parse_user_id (uid->uid, &uid->name, &uid->email,
&uid->comment, dst);
+ uid->address = _gpgme_mailbox_from_userid (uid->uid);
+ if (uid->address && uid->email && !strcmp (uid->address, uid->email))
+ {
+ /* The ADDRESS is the same as EMAIL: Save some space. */
+ free (uid->address);
+ uid->address = uid->email;
+ }
+
if (!key->uids)
key->uids = uid;
if (key->_last_uid)
@@ -333,6 +343,8 @@ gpgme_key_unref (gpgme_key_t key)
free (subkey->fpr);
if (subkey->curve)
free (subkey->curve);
+ if (subkey->keygrip)
+ free (subkey->keygrip);
if (subkey->card_number)
free (subkey->card_number);
free (subkey);
@@ -344,6 +356,7 @@ gpgme_key_unref (gpgme_key_t key)
{
gpgme_user_id_t next_uid = uid->next;
gpgme_key_sig_t keysig = uid->signatures;
+ gpgme_tofu_info_t tofu = uid->tofu;
while (keysig)
{
@@ -361,6 +374,21 @@ gpgme_key_unref (gpgme_key_t key)
free (keysig);
keysig = next_keysig;
}
+
+ while (tofu)
+ {
+ /* NB: The ->next is currently not used but we are prepared
+ * for it. */
+ gpgme_tofu_info_t tofu_next = tofu->next;
+
+ free (tofu->description);
+ free (tofu);
+ tofu = tofu_next;
+ }
+
+ if (uid->address && uid->address != uid->email)
+ free (uid->address);
+
free (uid);
uid = next_uid;
}
@@ -372,10 +400,13 @@ gpgme_key_unref (gpgme_key_t key)
if (key->chain_id)
free (key->chain_id);
+ if (key->fpr)
+ free (key->fpr);
free (key);
}
+
/* Support functions. */
diff --git a/src/keylist.c b/src/keylist.c
index fcf574f..8a0c5a3 100644
--- a/src/keylist.c
+++ b/src/keylist.c
@@ -33,6 +33,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
/* Suppress warning for accessing deprecated member "class". */
#define _GPGME_IN_GPGME
@@ -121,6 +122,8 @@ keylist_status_handler (void *priv, gpgme_status_code_t code, char *args)
void *hook;
op_data_t opd;
+ (void)args;
+
err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
opd = hook;
if (err)
@@ -403,6 +406,98 @@ parse_sec_field15 (gpgme_key_t key, gpgme_subkey_t subkey, char *field)
}
+/* Parse a tfs record. */
+static gpg_error_t
+parse_tfs_record (gpgme_user_id_t uid, char **field, int nfield)
+{
+ gpg_error_t err;
+ gpgme_tofu_info_t ti;
+ unsigned long uval;
+
+ /* We add only the first TOFU record in case future versions emit
+ * several. */
+ if (uid->tofu)
+ return 0;
+
+ /* Check that we have enough fields and that the version is supported. */
+ if (nfield < 8 || atoi(field[1]) != 1)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+ ti = calloc (1, sizeof *ti);
+ if (!ti)
+ return gpg_error_from_syserror ();
+
+ /* Note that we allow a value of up to 7 which is what we can store
+ * in the ti->validity. */
+ err = _gpgme_strtoul_field (field[2], &uval);
+ if (err || uval > 7)
+ goto inv_engine;
+ ti->validity = uval;
+
+ /* Parse the sign-count. */
+ err = _gpgme_strtoul_field (field[3], &uval);
+ if (err)
+ goto inv_engine;
+ if (uval > USHRT_MAX)
+ uval = USHRT_MAX;
+ ti->signcount = uval;
+
+ /* Parse the encr-count. */
+ err = _gpgme_strtoul_field (field[4], &uval);
+ if (err)
+ goto inv_engine;
+ if (uval > USHRT_MAX)
+ uval = USHRT_MAX;
+ ti->encrcount = uval;
+
+ /* Parse the policy. */
+ if (!strcmp (field[5], "none"))
+ ti->policy = GPGME_TOFU_POLICY_NONE;
+ else if (!strcmp (field[5], "auto"))
+ ti->policy = GPGME_TOFU_POLICY_AUTO;
+ else if (!strcmp (field[5], "good"))
+ ti->policy = GPGME_TOFU_POLICY_GOOD;
+ else if (!strcmp (field[5], "bad"))
+ ti->policy = GPGME_TOFU_POLICY_BAD;
+ else if (!strcmp (field[5], "ask"))
+ ti->policy = GPGME_TOFU_POLICY_ASK;
+ else /* "unknown" and invalid policy strings. */
+ ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
+
+ /* Parse first and last seen timestamps. */
+ err = _gpgme_strtoul_field (field[6], &uval);
+ if (err)
+ goto inv_engine;
+ ti->signfirst = uval;
+ err = _gpgme_strtoul_field (field[7], &uval);
+ if (err)
+ goto inv_engine;
+ ti->signlast = uval;
+
+ if (nfield > 9)
+ {
+ /* This condition is only to allow for gpg 2.1.15 - can
+ * eventually be removed. */
+ err = _gpgme_strtoul_field (field[8], &uval);
+ if (err)
+ goto inv_engine;
+ ti->encrfirst = uval;
+ err = _gpgme_strtoul_field (field[9], &uval);
+ if (err)
+ goto inv_engine;
+ ti->encrlast = uval;
+ }
+
+ /* Ready. */
+ uid->tofu = ti;
+ return 0;
+
+ inv_engine:
+ free (ti);
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+}
+
+
/* We have read an entire key into tmp_key and should now finish it.
It is assumed that this releases tmp_key. */
static void
@@ -426,7 +521,7 @@ keylist_colon_handler (void *priv, char *line)
gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
enum
{
- RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR,
+ RT_NONE, RT_SIG, RT_UID, RT_TFS, RT_SUB, RT_PUB, RT_FPR, RT_GRP,
RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK
}
rectype = RT_NONE;
@@ -479,8 +574,12 @@ keylist_colon_handler (void *priv, char *line)
rectype = RT_CRS;
else if (!strcmp (field[0], "fpr") && key)
rectype = RT_FPR;
+ else if (!strcmp (field[0], "grp") && key)
+ rectype = RT_GRP;
else if (!strcmp (field[0], "uid") && key)
rectype = RT_UID;
+ else if (!strcmp (field[0], "tfs") && key)
+ rectype = RT_TFS;
else if (!strcmp (field[0], "sub") && key)
rectype = RT_SUB;
else if (!strcmp (field[0], "ssb") && key)
@@ -490,10 +589,10 @@ keylist_colon_handler (void *priv, char *line)
else
rectype = RT_NONE;
- /* Only look at signatures immediately following a user ID. For
- this, clear the user ID pointer when encountering anything but a
- signature. */
- if (rectype != RT_SIG && rectype != RT_REV)
+ /* Only look at signature and trust info records immediately
+ following a user ID. For this, clear the user ID pointer when
+ encountering anything but a signature or trust record. */
+ if (rectype != RT_SIG && rectype != RT_REV && rectype != RT_TFS)
opd->tmp_uid = NULL;
/* Only look at subpackets immediately following a signature. For
@@ -693,6 +792,15 @@ keylist_colon_handler (void *priv, char *line)
}
break;
+ case RT_TFS:
+ if (opd->tmp_uid)
+ {
+ err = parse_tfs_record (opd->tmp_uid, field, fields);
+ if (err)
+ return err;
+ }
+ break;
+
case RT_FPR:
/* Field 10 has the fingerprint (take only the first one). */
if (fields >= 10 && field[9] && *field[9])
@@ -706,6 +814,22 @@ keylist_colon_handler (void *priv, char *line)
if (!subkey->fpr)
return gpg_error_from_syserror ();
}
+ /* If this is the first subkey, store the fingerprint also
+ in the KEY object. */
+ if (subkey == key->subkeys)
+ {
+ if (key->fpr && strcmp (key->fpr, subkey->fpr))
+ {
+ /* FPR already set but mismatch: Should never happen. */
+ return trace_gpg_error (GPG_ERR_INTERNAL);
+ }
+ if (!key->fpr)
+ {
+ key->fpr = strdup (subkey->fpr);
+ if (!key->fpr)
+ return gpg_error_from_syserror ();
+ }
+ }
}
/* Field 13 has the gpgsm chain ID (take only the first one). */
@@ -717,6 +841,22 @@ keylist_colon_handler (void *priv, char *line)
}
break;
+ case RT_GRP:
+ /* Field 10 has the keygrip. */
+ if (fields >= 10 && field[9] && *field[9])
+ {
+ /* Need to apply it to the last subkey because all subkeys
+ have a keygrip. */
+ subkey = key->_last_subkey;
+ if (!subkey->keygrip)
+ {
+ subkey->keygrip = strdup (field[9]);
+ if (!subkey->keygrip)
+ return gpg_error_from_syserror ();
+ }
+ }
+ break;
+
case RT_SIG:
case RT_REV:
if (!opd->tmp_uid)
diff --git a/src/keysign.c b/src/keysign.c
new file mode 100644
index 0000000..7d08c11
--- /dev/null
+++ b/src/keysign.c
@@ -0,0 +1,218 @@
+/* keysign.c - OpenPGP key signing
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "debug.h"
+#include "context.h"
+#include "ops.h"
+#include "util.h"
+
+
+typedef struct
+{
+ /* The error code from a FAILURE status line or 0. */
+ gpg_error_t failure_code;
+
+ /* The error code from certain ERROR status lines or 0. */
+ gpg_error_t error_code;
+
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+
+ (void)opd;
+}
+
+
+/* Parse an error status line. Return the error location and the
+ error code. The function may modify ARGS. */
+static char *
+parse_error (char *args, gpg_error_t *r_err)
+{
+ char *where = strchr (args, ' ');
+ char *which;
+
+ if (where)
+ {
+ *where = '\0';
+ which = where + 1;
+
+ where = strchr (which, ' ');
+ if (where)
+ *where = '\0';
+
+ where = args;
+ }
+ else
+ {
+ *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
+ return NULL;
+ }
+
+ *r_err = atoi (which);
+
+ return where;
+}
+
+
+static gpgme_error_t
+keysign_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+ char *loc;
+
+ /* Pipe the status code through the progress status handler. */
+ err = _gpgme_progress_status_handler (ctx, code, args);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_ERROR:
+ loc = parse_error (args, &err);
+ if (!loc)
+ return err;
+ if (!opd->error_code)
+ opd->error_code = err;
+ break;
+
+ case GPGME_STATUS_FAILURE:
+ opd->failure_code = _gpgme_parse_failure (args);
+ break;
+
+ case GPGME_STATUS_EOF:
+ if (opd->error_code)
+ return opd->error_code;
+ else if (opd->failure_code)
+ return opd->failure_code;
+ break;
+
+ case GPGME_STATUS_INQUIRE_MAXLEN:
+ if (ctx->status_cb && !ctx->full_status)
+ {
+ err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
+ if (err)
+ return err;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/* Sign the USERID of KEY using the current set of signers. If USERID
+ * is NULL, sign all user ids. To put several user ids into USERID,
+ * separate them by LF and set the flag GPGME_KEYSIGN_LFSEP. */
+static gpgme_error_t
+keysign_start (gpgme_ctx_t ctx, int synchronous,
+ gpgme_key_t key, const char *userid,
+ unsigned long expires, unsigned int flags)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
+ return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ if (!key)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, keysign_status_handler, ctx);
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ return _gpgme_engine_op_keysign (ctx->engine,
+ key, userid, expires, flags, ctx);
+}
+
+
+/* Sign the USERID of KEY using the current set of signers. */
+gpgme_error_t
+gpgme_op_keysign_start (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
+ unsigned long expires, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_keysign_start", ctx,
+ "key=%p, uid='%s' flags=0x%x", key, userid, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = keysign_start (ctx, 0, key, userid, expires, flags);
+ return TRACE_ERR (err);
+}
+
+
+gpgme_error_t
+gpgme_op_keysign (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
+ unsigned long expires, unsigned int flags)
+{
+ gpgme_error_t err;
+
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_keysign", ctx,
+ "key=%p, uid='%s' flags=0x%x", key, userid, flags);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+ err = keysign_start (ctx, 1, key, userid, expires, flags);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index 6687571..aec9090 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -98,6 +98,25 @@ GPGME_1.1 {
gpgme_set_status_cb;
gpgme_get_status_cb;
+
+ gpgme_pubkey_algo_string;
+ gpgme_set_ctx_flag;
+ gpgme_data_set_flag;
+
+ gpgme_op_createkey_start;
+ gpgme_op_createkey;
+ gpgme_op_createsubkey_start;
+ gpgme_op_createsubkey;
+ gpgme_op_adduid_start;
+ gpgme_op_adduid;
+ gpgme_op_revuid_start;
+ gpgme_op_revuid;
+ gpgme_op_keysign_start;
+ gpgme_op_keysign;
+ gpgme_op_tofu_policy_start;
+ gpgme_op_tofu_policy;
+ gpgme_op_interact_start;
+ gpgme_op_interact;
};
diff --git a/src/mbox-util.c b/src/mbox-util.c
new file mode 100644
index 0000000..83c8b5e
--- /dev/null
+++ b/src/mbox-util.c
@@ -0,0 +1,257 @@
+/* mbox-util.c - Mail address helper functions
+ * Copyright (C) 1998-2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* NB: This code has been taken from GnuPG. Please keep it in sync
+ * with GnuPG. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "mbox-util.h"
+
+/* Lowercase all ASCII characters in STRING. */
+static char *
+ascii_strlwr (char *string)
+{
+ char *p;
+
+ for (p = string; *p; p++ )
+ if (!(*p & ~0x7f) && *p >= 'A' && *p <= 'Z')
+ *p |= 0x20;
+
+ return string;
+}
+
+
+static int
+string_count_chr (const char *string, int c)
+{
+ int count;
+
+ for (count=0; *string; string++ )
+ if ( *string == c )
+ count++;
+ return count;
+}
+
+static int
+mem_count_chr (const void *buffer, int c, size_t length)
+{
+ const char *s = buffer;
+ int count;
+
+ for (count=0; length; length--, s++)
+ if (*s == c)
+ count++;
+ return count;
+}
+
+
+/* This is a case-sensitive version of our memistr. I wonder why no
+ standard function memstr exists but I better do not use the name
+ memstr to avoid future conflicts. */
+static const char *
+my_memstr (const void *buffer, size_t buflen, const char *sub)
+{
+ const unsigned char *buf = buffer;
+ const unsigned char *t = (const unsigned char *)buf;
+ const unsigned char *s = (const unsigned char *)sub;
+ size_t n = buflen;
+
+ for ( ; n ; t++, n-- )
+ {
+ if (*t == *s)
+ {
+ for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
+ ;
+ if (!*s)
+ return (const char*)buf;
+ t = (const unsigned char *)buf;
+ s = (const unsigned char *)sub ;
+ n = buflen;
+ }
+ }
+ return NULL;
+}
+
+
+
+static int
+string_has_ctrl_or_space (const char *string)
+{
+ for (; *string; string++ )
+ if (!(*string & 0x80) && *string <= 0x20)
+ return 1;
+ return 0;
+}
+
+
+/* Return true if STRING has two consecutive '.' after an '@'
+ sign. */
+static int
+has_dotdot_after_at (const char *string)
+{
+ string = strchr (string, '@');
+ if (!string)
+ return 0; /* No at-sign. */
+ string++;
+ return !!strstr (string, "..");
+}
+
+
+/* Check whether BUFFER has characters not valid in an RFC-822
+ address. LENGTH gives the length of BUFFER.
+
+ To cope with OpenPGP we ignore non-ascii characters so that for
+ example umlauts are legal in an email address. An OpenPGP user ID
+ must be utf-8 encoded but there is no strict requirement for
+ RFC-822. Thus to avoid IDNA encoding we put the address verbatim
+ as utf-8 into the user ID under the assumption that mail programs
+ handle IDNA at a lower level and take OpenPGP user IDs as utf-8.
+ Note that we can't do an utf-8 encoding checking here because in
+ keygen.c this function is called with the native encoding and
+ native to utf-8 encoding is only done later. */
+static int
+has_invalid_email_chars (const void *buffer, size_t length)
+{
+ const unsigned char *s = buffer;
+ int at_seen=0;
+ const char *valid_chars=
+ "01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ for ( ; length && *s; length--, s++ )
+ {
+ if ((*s & 0x80))
+ continue; /* We only care about ASCII. */
+ if (*s == '@')
+ at_seen=1;
+ else if (!at_seen && !(strchr (valid_chars, *s)
+ || strchr ("!#$%&'*+/=?^`{|}~", *s)))
+ return 1;
+ else if (at_seen && !strchr (valid_chars, *s))
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Same as is_valid_mailbox (see below) but operates on non-nul
+ terminated buffer. */
+static int
+is_valid_mailbox_mem (const void *name_arg, size_t namelen)
+{
+ const char *name = name_arg;
+
+ return !( !name
+ || !namelen
+ || has_invalid_email_chars (name, namelen)
+ || mem_count_chr (name, '@', namelen) != 1
+ || *name == '@'
+ || name[namelen-1] == '@'
+ || name[namelen-1] == '.'
+ || my_memstr (name, namelen, ".."));
+}
+
+
+/* Check whether NAME represents a valid mailbox according to
+ RFC822. Returns true if so. */
+int
+_gpgme_is_valid_mailbox (const char *name)
+{
+ return name? is_valid_mailbox_mem (name, strlen (name)) : 0;
+}
+
+
+/* Return the mailbox (local-part@domain) form a standard user id.
+ All plain ASCII characters in the result are converted to
+ lowercase. Caller must free the result. Returns NULL if no valid
+ mailbox was found (or we are out of memory). */
+char *
+_gpgme_mailbox_from_userid (const char *userid)
+{
+ const char *s, *s_end;
+ size_t len;
+ char *result = NULL;
+
+ s = strchr (userid, '<');
+ if (s)
+ {
+ /* Seems to be a standard user id. */
+ s++;
+ s_end = strchr (s, '>');
+ if (s_end && s_end > s)
+ {
+ len = s_end - s;
+ result = malloc (len + 1);
+ if (!result)
+ return NULL; /* Ooops - out of core. */
+ strncpy (result, s, len);
+ result[len] = 0;
+ /* Apply some basic checks on the address. We do not use
+ is_valid_mailbox because those checks are too strict. */
+ if (string_count_chr (result, '@') != 1 /* Need exactly one '@. */
+ || *result == '@' /* local-part missing. */
+ || result[len-1] == '@' /* domain missing. */
+ || result[len-1] == '.' /* ends with a dot. */
+ || string_has_ctrl_or_space (result)
+ || has_dotdot_after_at (result))
+ {
+ free (result);
+ result = NULL;
+ errno = EINVAL;
+ }
+ }
+ else
+ errno = EINVAL;
+ }
+ else if (_gpgme_is_valid_mailbox (userid))
+ {
+ /* The entire user id is a mailbox. Return that one. Note that
+ this fallback method has some restrictions on the valid
+ syntax of the mailbox. However, those who want weird
+ addresses should know about it and use the regular <...>
+ syntax. */
+ result = strdup (userid);
+ }
+ else
+ errno = EINVAL;
+
+ return result? ascii_strlwr (result): NULL;
+}
+
+
+/* /\* Check whether UID is a valid standard user id of the form */
+/* "Heinrich Heine <heinrichh@duesseldorf.de>" */
+/* and return true if this is the case. *\/ */
+/* int */
+/* is_valid_user_id (const char *uid) */
+/* { */
+/* if (!uid || !*uid) */
+/* return 0; */
+
+/* return 1; */
+/* } */
diff --git a/src/mbox-util.h b/src/mbox-util.h
new file mode 100644
index 0000000..3195a4d
--- /dev/null
+++ b/src/mbox-util.h
@@ -0,0 +1,29 @@
+/* mbox-util.h - Defs for mail address helper functions
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef GNUPG_COMMON_MBOX_UTIL_H
+#define GNUPG_COMMON_MBOX_UTIL_H
+
+/* int has_invalid_email_chars (const void *buffer, size_t length); */
+int _gpgme_is_valid_mailbox (const char *name);
+/* int _gpgme_is_valid_mailbox_mem (const void *buffer, size_t length); */
+char *_gpgme_mailbox_from_userid (const char *userid);
+/* int is_valid_user_id (const char *uid); */
+
+
+#endif /*GNUPG_COMMON_MBOX_UTIL_H*/
diff --git a/src/moc_kdpipeiodevice.cpp b/src/moc_kdpipeiodevice.cpp
deleted file mode 100644
index eac7b23..0000000
--- a/src/moc_kdpipeiodevice.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
-** Meta object code from reading C++ file 'kdpipeiodevice.h'
-**
-** Created: Mon Aug 27 15:17:18 2007
-** by: The Qt Meta Object Compiler version 59 (Qt 4.3.0)
-**
-** WARNING! All changes made in this file will be lost!
-*****************************************************************************/
-
-#include "kdpipeiodevice.h"
-#if !defined(Q_MOC_OUTPUT_REVISION)
-#error "The header file 'kdpipeiodevice.h' doesn't include <QObject>."
-#elif Q_MOC_OUTPUT_REVISION != 59
-#error "This file was generated using the moc from 4.3.0. It"
-#error "cannot be used with the include files from this version of Qt."
-#error "(The moc has changed too much.)"
-#endif
-
-static const uint qt_meta_data_KDPipeIODevice[] = {
-
- // content:
- 1, // revision
- 0, // classname
- 0, 0, // classinfo
- 0, 0, // methods
- 0, 0, // properties
- 0, 0, // enums/sets
-
- 0 // eod
-};
-
-static const char qt_meta_stringdata_KDPipeIODevice[] = {
- "KDPipeIODevice\0"
-};
-
-const QMetaObject KDPipeIODevice::staticMetaObject = {
- { &QIODevice::staticMetaObject, qt_meta_stringdata_KDPipeIODevice,
- qt_meta_data_KDPipeIODevice, 0 }
-};
-
-const QMetaObject *KDPipeIODevice::metaObject() const
-{
- return &staticMetaObject;
-}
-
-void *KDPipeIODevice::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_KDPipeIODevice))
- return static_cast<void*>(const_cast< KDPipeIODevice*>(this));
- return QIODevice::qt_metacast(_clname);
-}
-
-int KDPipeIODevice::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QIODevice::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- return _id;
-}
diff --git a/src/op-support.c b/src/op-support.c
index 02940ef..9f10cd3 100644
--- a/src/op-support.c
+++ b/src/op-support.c
@@ -33,6 +33,11 @@
#include "util.h"
#include "debug.h"
+#if GPG_ERROR_VERSION_NUMBER < 0x011700 /* 1.23 */
+# define GPG_ERR_SUBKEYS_EXP_OR_REV 217
+#endif
+
+
gpgme_error_t
_gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook,
@@ -143,6 +148,12 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
err = 0;
}
+ if (!err && ctx->status_cb && ctx->full_status)
+ {
+ _gpgme_engine_set_status_cb (ctx->engine,
+ ctx->status_cb, ctx->status_cb_value);
+ }
+
if (err)
{
_gpgme_engine_release (ctx->engine);
@@ -190,16 +201,21 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
}
-/* Parse the INV_RECP or INV-SNDR status line in ARGS and return the
- result in KEY. */
+/* Parse the INV_RECP or INV_SNDR status line in ARGS and return the
+ result in KEY. If KC_FPR (from the KEY_CONSIDERED status line) is
+ not NULL take the KC_FLAGS in account. */
gpgme_error_t
-_gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
+_gpgme_parse_inv_recp (char *args, int for_signing,
+ const char *kc_fpr, unsigned int kc_flags,
+ gpgme_invalid_key_t *key)
{
gpgme_invalid_key_t inv_key;
char *tail;
long int reason;
- inv_key = malloc (sizeof (*inv_key));
+ (void)for_signing;
+
+ inv_key = calloc (1, sizeof (*inv_key));
if (!inv_key)
return gpg_error_from_syserror ();
inv_key->next = NULL;
@@ -214,9 +230,11 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
switch (reason)
{
- default:
case 0:
- inv_key->reason = gpg_error (GPG_ERR_GENERAL);
+ if (kc_fpr && (kc_flags & 2))
+ inv_key->reason = gpg_error (GPG_ERR_SUBKEYS_EXP_OR_REV);
+ else
+ inv_key->reason = gpg_error (GPG_ERR_GENERAL);
break;
case 1:
@@ -274,6 +292,10 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
case 14:
inv_key->reason = gpg_error (GPG_ERR_INV_USER_ID);
break;
+
+ default:
+ inv_key->reason = gpg_error (GPG_ERR_GENERAL);
+ break;
}
while (*tail && *tail == ' ')
@@ -287,14 +309,49 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
return gpg_error_from_syserror ();
}
}
- else
- inv_key->fpr = NULL;
*key = inv_key;
return 0;
}
+
+/* Parse a KEY_CONSIDERED status line in ARGS and store the
+ * fingerprint and the flags at R_FPR and R_FLAGS. The caller must
+ * free the value at R_FPR on success. */
+gpgme_error_t
+_gpgme_parse_key_considered (const char *args,
+ char **r_fpr, unsigned int *r_flags)
+{
+ char *pend;
+ size_t n;
+
+ *r_fpr = NULL;
+
+ pend = strchr (args, ' ');
+ if (!pend || pend == args)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Bogus status line. */
+ n = pend - args;
+ *r_fpr = malloc (n + 1);
+ if (!*r_fpr)
+ return gpg_error_from_syserror ();
+ memcpy (*r_fpr, args, n);
+ (*r_fpr)[n] = 0;
+ args = pend + 1;
+
+ gpg_err_set_errno (0);
+ *r_flags = strtoul (args, &pend, 0);
+ if (errno || args == pend || (*pend && *pend != ' '))
+ {
+ free (*r_fpr);
+ *r_fpr = NULL;
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ }
+
+ return 0;
+}
+
+
/* Parse the PLAINTEXT status line in ARGS and return the result in
FILENAMEP. */
gpgme_error_t
diff --git a/src/ops.h b/src/ops.h
index 3662d57..97b1019 100644
--- a/src/ops.h
+++ b/src/ops.h
@@ -57,9 +57,15 @@ gpgme_error_t _gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type,
/* Prepare a new operation on CTX. */
gpgme_error_t _gpgme_op_reset (gpgme_ctx_t ctx, int synchronous);
+/* Parse the KEY_CONSIDERED status line. */
+gpgme_error_t _gpgme_parse_key_considered (const char *args,
+ char **r_fpr, unsigned int *r_flags);
+
/* Parse the INV_RECP status line in ARGS and return the result in
KEY. */
-gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key);
+gpgme_error_t _gpgme_parse_inv_recp (char *args, int for_signing,
+ const char *kc_fpr, unsigned int kc_flags,
+ gpgme_invalid_key_t *key);
/* Parse the PLAINTEXT status line in ARGS and return the result in
FILENAMEP. */
@@ -132,9 +138,11 @@ gpgme_error_t _gpgme_progress_status_handler (void *priv,
gpgme_error_t _gpgme_key_new (gpgme_key_t *r_key);
gpgme_error_t _gpgme_key_add_subkey (gpgme_key_t key,
gpgme_subkey_t *r_subkey);
-gpgme_error_t _gpgme_key_append_name (gpgme_key_t key, const char *src, int convert);
+gpgme_error_t _gpgme_key_append_name (gpgme_key_t key,
+ const char *src, int convert);
gpgme_key_sig_t _gpgme_key_add_sig (gpgme_key_t key, char *src);
+
/* From keylist.c. */
void _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type,
diff --git a/src/passphrase.c b/src/passphrase.c
index c88e57d..74d235c 100644
--- a/src/passphrase.c
+++ b/src/passphrase.c
@@ -118,9 +118,8 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code,
case GPGME_STATUS_ERROR:
/* We abuse this status handler to forward ERROR status codes to
- the caller. This should better be done in a generic handler,
- but for now this is sufficient. */
- if (ctx->status_cb)
+ the caller. */
+ if (ctx->status_cb && !ctx->full_status)
{
err = ctx->status_cb (ctx->status_cb_value, "ERROR", args);
if (err)
@@ -130,9 +129,8 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code,
case GPGME_STATUS_FAILURE:
/* We abuse this status handler to forward FAILURE status codes
- to the caller. This should better be done in a generic
- handler, but for now this is sufficient. */
- if (ctx->status_cb)
+ to the caller. */
+ if (ctx->status_cb && !ctx->full_status)
{
err = ctx->status_cb (ctx->status_cb_value, "FAILURE", args);
if (err)
@@ -173,6 +171,7 @@ _gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code,
if (processed)
*processed = 1;
+ /* Fake a status line to to convey the MAXLEN info. */
if (ctx->status_cb && opd->maxlen)
err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN",
opd->maxlen);
diff --git a/src/passwd.c b/src/passwd.c
index ff30df0..c34f357 100644
--- a/src/passwd.c
+++ b/src/passwd.c
@@ -148,6 +148,14 @@ passwd_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key,
_gpgme_engine_set_status_handler (ctx->engine, passwd_status_handler, ctx);
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
return _gpgme_engine_op_passwd (ctx->engine, key, flags);
}
diff --git a/src/posix-io.c b/src/posix-io.c
index ac823fc..c0b2f4f 100644
--- a/src/posix-io.c
+++ b/src/posix-io.c
@@ -23,6 +23,9 @@
#endif
#include <stdio.h>
#include <stdlib.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
#include <string.h>
#include <assert.h>
#include <errno.h>
@@ -44,6 +47,12 @@
#include <ctype.h>
#include <sys/resource.h>
+#if __linux__
+# include <sys/types.h>
+# include <dirent.h>
+#endif /*__linux__ */
+
+
#include "util.h"
#include "priv-io.h"
#include "sema.h"
@@ -273,20 +282,54 @@ _gpgme_io_set_nonblocking (int fd)
static long int
get_max_fds (void)
{
- char *source = NULL;
+ const char *source = NULL;
long int fds = -1;
int rc;
-#ifdef RLIMIT_NOFILE
+ /* Under Linux we can figure out the highest used file descriptor by
+ * reading /proc/self/fd. This is in the common cases much fast than
+ * for example doing 4096 close calls where almost all of them will
+ * fail. */
+#ifdef __linux__
{
- struct rlimit rl;
- rc = getrlimit (RLIMIT_NOFILE, &rl);
- if (rc == 0)
+ DIR *dir = NULL;
+ struct dirent *dir_entry;
+ const char *s;
+ int x;
+
+ dir = opendir ("/proc/self/fd");
+ if (dir)
{
- source = "RLIMIT_NOFILE";
- fds = rl.rlim_max;
+ while ((dir_entry = readdir (dir)))
+ {
+ s = dir_entry->d_name;
+ if ( *s < '0' || *s > '9')
+ continue;
+ x = atoi (s);
+ if (x > fds)
+ fds = x;
+ }
+ closedir (dir);
}
- }
+ if (fds != -1)
+ {
+ fds++;
+ source = "/proc";
+ }
+ }
+#endif /* __linux__ */
+
+#ifdef RLIMIT_NOFILE
+ if (fds == -1)
+ {
+ struct rlimit rl;
+ rc = getrlimit (RLIMIT_NOFILE, &rl);
+ if (rc == 0)
+ {
+ source = "RLIMIT_NOFILE";
+ fds = rl.rlim_max;
+ }
+ }
#endif
#ifdef RLIMIT_OFILE
if (fds == -1)
@@ -331,6 +374,16 @@ get_max_fds (void)
fds = 1024;
}
+ /* AIX returns INT32_MAX instead of a proper value. We assume that
+ * this is always an error and use a more reasonable limit. */
+#ifdef INT32_MAX
+ if (fds == INT32_MAX)
+ {
+ source = "aix-fix";
+ fds = 1024;
+ }
+#endif
+
TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
return fds;
}
@@ -551,6 +604,12 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
continue;
if (fds[i].for_read)
{
+ if (fds[i].fd >= FD_SETSIZE)
+ {
+ TRACE_END (dbg_help, " -BAD- ]");
+ gpg_err_set_errno (EBADF);
+ return TRACE_SYSRES (-1);
+ }
assert (!FD_ISSET (fds[i].fd, &readfds));
FD_SET (fds[i].fd, &readfds);
if (fds[i].fd > max_fd)
@@ -560,6 +619,12 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
}
else if (fds[i].for_write)
{
+ if (fds[i].fd >= FD_SETSIZE)
+ {
+ TRACE_END (dbg_help, " -BAD- ]");
+ gpg_err_set_errno (EBADF);
+ return TRACE_SYSRES (-1);
+ }
assert (!FD_ISSET (fds[i].fd, &writefds));
FD_SET (fds[i].fd, &writefds);
if (fds[i].fd > max_fd)
diff --git a/src/posix-util.c b/src/posix-util.c
index f7e0a17..889c6aa 100644
--- a/src/posix-util.c
+++ b/src/posix-util.c
@@ -71,6 +71,15 @@ _gpgme_set_default_gpgconf_name (const char *name)
}
+/* Dummy function - see w32-util.c for the actual code. */
+int
+_gpgme_set_override_inst_dir (const char *dir)
+{
+ (void)dir;
+ return 0;
+}
+
+
/* Find an executable program PGM along the envvar PATH. */
static char *
walk_path (const char *pgm)
@@ -136,6 +145,8 @@ _gpgme_get_gpgconf_path (void)
int
_gpgme_get_conf_int (const char *key, int *value)
{
+ (void)key;
+ (void)value;
return 0;
}
diff --git a/src/sign.c b/src/sign.c
index 6c9fc03..bfd9ad1 100644
--- a/src/sign.c
+++ b/src/sign.c
@@ -42,6 +42,12 @@ typedef struct
/* The error code from a FAILURE status line or 0. */
gpg_error_t failure_code;
+ /* The fingerprint from the last KEY_CONSIDERED status line. */
+ char *kc_fpr;
+
+ /* The flags from the last KEY_CONSIDERED status line. */
+ unsigned int kc_flags;
+
/* A pointer to the next pointer of the last invalid signer in
the list. This makes appending new invalid signers painless
while preserving the order. */
@@ -86,6 +92,7 @@ release_op_data (void *hook)
}
release_signatures (opd->result.signatures);
+ free (opd->kc_fpr);
}
@@ -316,6 +323,17 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
opd->last_sig_p = &(*opd->last_sig_p)->next;
break;
+ case GPGME_STATUS_KEY_CONSIDERED:
+ /* This is emitted during gpg's key lookup to give information
+ * about the lookup results. We store the last one so it can be
+ * used in connection with INV_RECP. */
+ free (opd->kc_fpr);
+ opd->kc_fpr = NULL;
+ err = _gpgme_parse_key_considered (args, &opd->kc_fpr, &opd->kc_flags);
+ if (err)
+ return err;
+ break;
+
case GPGME_STATUS_INV_RECP:
if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
break;
@@ -323,11 +341,16 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
case GPGME_STATUS_INV_SGNR:
if (code == GPGME_STATUS_INV_SGNR)
opd->inv_sgnr_seen = 1;
- err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
+ free (opd->kc_fpr);
+ opd->kc_fpr = NULL;
+ err = _gpgme_parse_inv_recp (args, 1, opd->kc_fpr, opd->kc_flags,
+ opd->last_signer_p);
if (err)
return err;
opd->last_signer_p = &(*opd->last_signer_p)->next;
+ free (opd->kc_fpr);
+ opd->kc_fpr = NULL;
break;
case GPGME_STATUS_FAILURE:
@@ -346,7 +369,7 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
break;
case GPGME_STATUS_INQUIRE_MAXLEN:
- if (ctx->status_cb)
+ if (ctx->status_cb && !ctx->full_status)
err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
break;
diff --git a/src/status-table.c b/src/status-table.c
index 6d428d7..c9bf357 100644
--- a/src/status-table.c
+++ b/src/status-table.c
@@ -84,6 +84,7 @@ static struct status_table_s status_table[] =
{ "INQUIRE_MAXLEN", GPGME_STATUS_INQUIRE_MAXLEN },
{ "INV_RECP", GPGME_STATUS_INV_RECP },
{ "INV_SGNR", GPGME_STATUS_INV_SGNR },
+ { "KEY_CONSIDERED", GPGME_STATUS_KEY_CONSIDERED },
{ "KEY_CREATED", GPGME_STATUS_KEY_CREATED },
{ "KEY_NOT_CREATED", GPGME_STATUS_KEY_NOT_CREATED },
{ "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED },
@@ -101,6 +102,7 @@ static struct status_table_s status_table[] =
{ "NO_SGNR", GPGME_STATUS_NO_SGNR },
{ "NODATA", GPGME_STATUS_NODATA },
{ "NOTATION_DATA", GPGME_STATUS_NOTATION_DATA },
+ { "NOTATION_FLAGS", GPGME_STATUS_NOTATION_FLAGS },
{ "NOTATION_NAME", GPGME_STATUS_NOTATION_NAME },
{ "PINENTRY_LAUNCHED", GPGME_STATUS_PINENTRY_LAUNCHED},
{ "PKA_TRUST_BAD", GPGME_STATUS_PKA_TRUST_BAD },
@@ -123,6 +125,9 @@ static struct status_table_s status_table[] =
{ "SIG_SUBPACKET", GPGME_STATUS_SIG_SUBPACKET },
{ "SIGEXPIRED", GPGME_STATUS_SIGEXPIRED },
{ "SUCCESS", GPGME_STATUS_SUCCESS },
+ { "TOFU_STATS", GPGME_STATUS_TOFU_STATS },
+ { "TOFU_STATS_LONG", GPGME_STATUS_TOFU_STATS_LONG },
+ { "TOFU_USER", GPGME_STATUS_TOFU_USER },
{ "TRUNCATED", GPGME_STATUS_TRUNCATED },
{ "TRUST_FULLY", GPGME_STATUS_TRUST_FULLY },
{ "TRUST_MARGINAL", GPGME_STATUS_TRUST_MARGINAL },
@@ -164,3 +169,15 @@ _gpgme_parse_status (const char *name)
sizeof t, status_cmp);
return r ? r->code : -1;
}
+
+
+const char *
+_gpgme_status_to_string (gpgme_status_code_t code)
+{
+ int i;
+
+ for (i=0; i < DIM(status_table); i++)
+ if (status_table[i].code == code)
+ return status_table[i].name? status_table[i].name : "";
+ return "status_code_lost";
+}
diff --git a/src/sys-util.h b/src/sys-util.h
index 589634b..541c557 100644
--- a/src/sys-util.h
+++ b/src/sys-util.h
@@ -23,6 +23,7 @@
/*-- {posix,w32}-util.c --*/
int _gpgme_set_default_gpg_name (const char *name);
int _gpgme_set_default_gpgconf_name (const char *name);
+int _gpgme_set_override_inst_dir (const char *dir);
char *_gpgme_get_gpg_path (void);
char *_gpgme_get_gpgconf_path (void);
diff --git a/src/tofupolicy.c b/src/tofupolicy.c
new file mode 100644
index 0000000..799779e
--- /dev/null
+++ b/src/tofupolicy.c
@@ -0,0 +1,184 @@
+/* tofupolicy.c - Tofu policy helpers.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+
+#include "gpgme.h"
+#include "debug.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ /* The error code from a FAILURE status line or 0. */
+ gpg_error_t failure_code;
+
+ /* The error code from an ERROR status line or 0. */
+ gpg_error_t error_code;
+
+} *op_data_t;
+
+
+
+/* Parse an error status line. Return the error location and the
+ error code. The function may modify ARGS. */
+static char *
+parse_error (char *args, gpg_error_t *r_err)
+{
+ char *where = strchr (args, ' ');
+ char *which;
+
+ if (where)
+ {
+ *where = '\0';
+ which = where + 1;
+
+ where = strchr (which, ' ');
+ if (where)
+ *where = '\0';
+
+ where = args;
+ }
+ else
+ {
+ *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
+ return NULL;
+ }
+
+ *r_err = atoi (which);
+
+ return where;
+}
+
+
+static gpgme_error_t
+tofu_policy_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+ char *loc;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_TOFU_POLICY, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_ERROR:
+ loc = parse_error (args, &err);
+ if (!loc)
+ return err;
+ if (!opd->error_code)
+ opd->error_code = err;
+ break;
+
+ case GPGME_STATUS_FAILURE:
+ opd->failure_code = _gpgme_parse_failure (args);
+ break;
+
+ case GPGME_STATUS_EOF:
+ if (opd->error_code)
+ err = opd->error_code;
+ else if (opd->failure_code)
+ err = opd->failure_code;
+ break;
+
+ default:
+ break;
+ }
+
+ return err;
+}
+
+
+/* Set the TOFU policy for KEY to POLICY. */
+static gpgme_error_t
+tofu_policy_start (gpgme_ctx_t ctx, int synchronous,
+ gpgme_key_t key, gpgme_tofu_policy_t policy)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
+ return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+ if (!key)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_TOFU_POLICY, &hook,
+ sizeof (*opd), NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, tofu_policy_status_handler,
+ ctx);
+
+ return _gpgme_engine_op_tofu_policy (ctx->engine, key, policy);
+}
+
+
+
+/* Set the TOFU policy of KEY to POLCIY. This is the asynchronous
+ * variant. */
+gpgme_error_t
+gpgme_op_tofu_policy_start (gpgme_ctx_t ctx,
+ gpgme_key_t key, gpgme_tofu_policy_t policy)
+{
+ gpg_error_t err;
+ TRACE_BEG2 (DEBUG_CTX, "gpgme_op_tofu_policy_start", ctx,
+ "key=%p, policy=%u", key, (unsigned int)policy);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+ err = tofu_policy_start (ctx, 0, key, policy);
+ return TRACE_ERR (err);
+}
+
+
+/* This is the synchronous variant of gpgme_op_tofu_policy_start. */
+gpgme_error_t
+gpgme_op_tofu_policy (gpgme_ctx_t ctx,
+ gpgme_key_t key, gpgme_tofu_policy_t policy)
+{
+ gpgme_error_t err;
+ TRACE_BEG2 (DEBUG_CTX, "gpgme_op_tofu_policy", ctx,
+ "key=%p, policy=%u", key, (unsigned int)policy);
+
+ if (!ctx)
+ return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+ err = tofu_policy_start (ctx, 1, key, policy);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
+}
diff --git a/src/trustlist.c b/src/trustlist.c
index d456780..c85ef87 100644
--- a/src/trustlist.c
+++ b/src/trustlist.c
@@ -52,6 +52,9 @@ typedef struct
static gpgme_error_t
trustlist_status_handler (void *priv, gpgme_status_code_t code, char *args)
{
+ (void)priv;
+ (void)code;
+ (void)args;
return 0;
}
diff --git a/src/util.h b/src/util.h
index 365f1d8..88e7750 100644
--- a/src/util.h
+++ b/src/util.h
@@ -45,6 +45,11 @@
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#if GPG_ERROR_VERSION_NUMBER < 0x011500 /* 1.21 */
+# define GPG_ERR_FALSE 256
+#endif
+
+
/*-- {posix,w32}-util.c --*/
int _gpgme_get_conf_int (const char *key, int *value);
@@ -124,6 +129,18 @@ gpgme_error_t _gpgme_decode_percent_string (const char *src, char **destp,
gpgme_error_t _gpgme_encode_percent_string (const char *src, char **destp,
size_t len);
+/* Split a string into space delimited fields and remove leading and
+ * trailing spaces from each field. A pointer to the each field is
+ * stored in ARRAY. Stop splitting at ARRAYSIZE fields. The function
+ * modifies STRING. The number of parsed fields is returned. */
+int _gpgme_split_fields (char *string, char **array, int arraysize);
+
+/* Convert the field STRING into an unsigned long value. Check for
+ * trailing garbage. */
+gpgme_error_t _gpgme_strtoul_field (const char *string, unsigned long *result);
+
+/* Convert STRING into an offset value similar to atoi(). */
+gpgme_off_t _gpgme_string_to_off (const char *string);
/* Parse the string TIMESTAMP into a time_t. The string may either be
seconds since Epoch or in the ISO 8601 format like
@@ -138,6 +155,26 @@ gpgme_error_t _gpgme_map_gnupg_error (char *err);
int _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol);
+/*-- b64dec.c --*/
+
+struct b64state
+{
+ int idx;
+ int quad_count;
+ char *title;
+ unsigned char radbuf[4];
+ int stop_seen:1;
+ int invalid_encoding:1;
+ gpg_error_t lasterr;
+};
+
+gpg_error_t _gpgme_b64dec_start (struct b64state *state, const char *title);
+gpg_error_t _gpgme_b64dec_proc (struct b64state *state,
+ void *buffer, size_t length, size_t *r_nbytes);
+gpg_error_t _gpgme_b64dec_finish (struct b64state *state);
+
+
+
/* Retrieve the environment variable NAME and return a copy of it in a
malloc()'ed buffer in *VALUE. If the environment variable is not
set, return NULL in *VALUE. */
@@ -148,6 +185,7 @@ gpgme_error_t _gpgme_getenv (const char *name, char **value);
/* Convert a status string to a status code. */
void _gpgme_status_init (void);
gpgme_status_code_t _gpgme_parse_status (const char *name);
+const char *_gpgme_status_to_string (gpgme_status_code_t code);
#ifdef HAVE_W32_SYSTEM
diff --git a/src/verify.c b/src/verify.c
index 75914e2..eb1cc10 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -26,6 +26,7 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <limits.h>
#include "gpgme.h"
#include "debug.h"
@@ -71,6 +72,8 @@ release_op_data (void *hook)
free (sig->fpr);
if (sig->pka_address)
free (sig->pka_address);
+ if (sig->key)
+ gpgme_key_unref (sig->key);
free (sig);
sig = next;
}
@@ -363,25 +366,10 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
end++;
/* Parse the return code. */
- if (end[0] && (!end[1] || end[1] == ' '))
- {
- switch (end[0])
- {
- case '4':
- sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
- break;
-
- case '9':
- sig->status = gpg_error (GPG_ERR_NO_PUBKEY);
- break;
-
- default:
- sig->status = gpg_error (GPG_ERR_GENERAL);
- }
- }
- else
+ if (!*end)
goto parse_err_sig_fail;
+ sig->status = strtoul (end, NULL, 10);
goto parse_err_sig_ok;
parse_err_sig_fail:
@@ -486,13 +474,14 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
gpgme_error_t err;
gpgme_sig_notation_t *lastp = &sig->notations;
gpgme_sig_notation_t notation = sig->notations;
- char *end = strchr (args, ' ');
-
- if (end)
- *end = '\0';
+ char *p;
if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
{
+ p = strchr (args, ' ');
+ if (p)
+ *p = '\0';
+
/* FIXME: We could keep a pointer to the last notation in the list. */
while (notation && notation->value)
{
@@ -520,9 +509,8 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
notation->name_len = strlen (notation->name);
- /* FIXME: For now we fake the human-readable flag. The
- critical flag can not be reported as it is not
- provided. */
+ /* Set default flags for use with older gpg versions which
+ * do not emit a NOTATIONS_FLAG line. */
notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
notation->human_readable = 1;
}
@@ -541,6 +529,37 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
}
*lastp = notation;
}
+ else if (code == GPGME_STATUS_NOTATION_FLAGS)
+ {
+ char *field[2];
+
+ while (notation && notation->next)
+ {
+ lastp = &notation->next;
+ notation = notation->next;
+ }
+
+ if (!notation || !notation->name)
+ { /* There are notation flags without a previous notation name.
+ * The crypto backend misbehaves. */
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ }
+ if (_gpgme_split_fields (args, field, DIM (field)) < 2)
+ { /* Required args missing. */
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ }
+ notation->flags = 0;
+ if (atoi (field[0]))
+ {
+ notation->flags |= GPGME_SIG_NOTATION_CRITICAL;
+ notation->critical = 1;
+ }
+ if (atoi (field[1]))
+ {
+ notation->flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
+ notation->human_readable = 1;
+ }
+ }
else if (code == GPGME_STATUS_NOTATION_DATA)
{
int len = strlen (args) + 1;
@@ -635,6 +654,213 @@ parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
}
+/* Parse a TOFU_USER line and put the info into SIG. */
+static gpgme_error_t
+parse_tofu_user (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
+{
+ gpg_error_t err;
+ char *tail;
+ gpgme_user_id_t uid;
+ gpgme_tofu_info_t ti;
+ char *fpr = NULL;
+ char *address = NULL;
+
+ tail = strchr (args, ' ');
+ if (!tail || tail == args)
+ {
+ err = trace_gpg_error (GPG_ERR_INV_ENGINE); /* No fingerprint. */
+ goto leave;
+ }
+ *tail++ = 0;
+
+ fpr = strdup (args);
+ if (!fpr)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ args = tail;
+ tail = strchr (args, ' ');
+ if (tail == args)
+ {
+ err = trace_gpg_error (GPG_ERR_INV_ENGINE); /* No addr-spec. */
+ goto leave;
+ }
+ if (tail)
+ *tail = 0;
+
+ err = _gpgme_decode_percent_string (args, &address, 0, 0);
+ if (err)
+ goto leave;
+
+ if (!sig->key)
+ {
+ err = _gpgme_key_new (&sig->key);
+ if (err)
+ goto leave;
+ sig->key->fpr = fpr;
+ sig->key->protocol = protocol;
+ fpr = NULL;
+ }
+ else if (!sig->key->fpr)
+ {
+ err = trace_gpg_error (GPG_ERR_INTERNAL);
+ goto leave;
+ }
+ else if (strcmp (sig->key->fpr, fpr))
+ {
+ /* The engine did not emit NEWSIG before a new key. */
+ err = trace_gpg_error (GPG_ERR_INV_ENGINE);
+ goto leave;
+ }
+
+ err = _gpgme_key_append_name (sig->key, address, 0);
+ if (err)
+ goto leave;
+
+ uid = sig->key->_last_uid;
+ assert (uid);
+
+ ti = calloc (1, sizeof *ti);
+ if (!ti)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ uid->tofu = ti;
+
+
+ leave:
+ free (fpr);
+ free (address);
+ return err;
+}
+
+
+/* Parse a TOFU_STATS line and store it in the last tofu info of SIG.
+ *
+ * TOFU_STATS <validity> <sign-count> <encr-count> \
+ * [<policy> [<tm1> <tm2> <tm3> <tm4>]]
+ */
+static gpgme_error_t
+parse_tofu_stats (gpgme_signature_t sig, char *args)
+{
+ gpgme_error_t err;
+ gpgme_tofu_info_t ti;
+ char *field[8];
+ int nfields;
+ unsigned long uval;
+
+ if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen. */
+ if (ti->signfirst || ti->signcount || ti->validity || ti->policy)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set. */
+
+ nfields = _gpgme_split_fields (args, field, DIM (field));
+ if (nfields < 3)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required args missing. */
+
+ /* Note that we allow a value of up to 7 which is what we can store
+ * in the ti->validity. */
+ err = _gpgme_strtoul_field (field[0], &uval);
+ if (err || uval > 7)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ ti->validity = uval;
+
+ /* Parse the sign-count. */
+ err = _gpgme_strtoul_field (field[1], &uval);
+ if (err)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ if (uval > USHRT_MAX)
+ uval = USHRT_MAX;
+ ti->signcount = uval;
+
+ /* Parse the encr-count. */
+ err = _gpgme_strtoul_field (field[2], &uval);
+ if (err)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ if (uval > USHRT_MAX)
+ uval = USHRT_MAX;
+ ti->encrcount = uval;
+
+ if (nfields == 3)
+ return 0; /* All mandatory fields parsed. */
+
+ /* Parse the policy. */
+ if (!strcmp (field[3], "none"))
+ ti->policy = GPGME_TOFU_POLICY_NONE;
+ else if (!strcmp (field[3], "auto"))
+ ti->policy = GPGME_TOFU_POLICY_AUTO;
+ else if (!strcmp (field[3], "good"))
+ ti->policy = GPGME_TOFU_POLICY_GOOD;
+ else if (!strcmp (field[3], "bad"))
+ ti->policy = GPGME_TOFU_POLICY_BAD;
+ else if (!strcmp (field[3], "ask"))
+ ti->policy = GPGME_TOFU_POLICY_ASK;
+ else /* "unknown" and invalid policy strings. */
+ ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
+
+ if (nfields == 4)
+ return 0; /* No more optional fields. */
+
+ /* Parse first and last seen timestamps (none or both are required). */
+ if (nfields < 6)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* "tm2" missing. */
+ err = _gpgme_strtoul_field (field[4], &uval);
+ if (err)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ ti->signfirst = uval;
+ err = _gpgme_strtoul_field (field[5], &uval);
+ if (err)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ ti->signlast = uval;
+ if (nfields > 7)
+ {
+ /* This condition is only to allow for gpg 2.1.15 - can
+ * eventually be removed. */
+ err = _gpgme_strtoul_field (field[6], &uval);
+ if (err)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ ti->encrfirst = uval;
+ err = _gpgme_strtoul_field (field[7], &uval);
+ if (err)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+ ti->encrlast = uval;
+ }
+
+ return 0;
+}
+
+
+/* Parse a TOFU_STATS_LONG line and store it in the last tofu info of SIG. */
+static gpgme_error_t
+parse_tofu_stats_long (gpgme_signature_t sig, char *args, int raw)
+{
+ gpgme_error_t err;
+ gpgme_tofu_info_t ti;
+ char *p;
+
+ if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen. */
+ if (ti->description)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set. */
+
+ err = _gpgme_decode_percent_string (args, &ti->description, 0, 0);
+ if (err)
+ return err;
+
+ /* Remove the non-breaking spaces. */
+ if (!raw)
+ {
+ for (p = ti->description; *p; p++)
+ if (*p == '~')
+ *p = ' ';
+ }
+ return 0;
+}
+
+
/* Parse an error status line and if SET_STATUS is true update the
result status as appropriate. With SET_STATUS being false, only
check for an error. */
@@ -737,6 +963,7 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
break;
case GPGME_STATUS_NOTATION_NAME:
+ case GPGME_STATUS_NOTATION_FLAGS:
case GPGME_STATUS_NOTATION_DATA:
case GPGME_STATUS_POLICY_URL:
opd->only_newsig_seen = 0;
@@ -766,6 +993,21 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
sig->pka_address = strdup (args);
break;
+ case GPGME_STATUS_TOFU_USER:
+ opd->only_newsig_seen = 0;
+ return sig ? parse_tofu_user (sig, args, ctx->protocol)
+ /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+ case GPGME_STATUS_TOFU_STATS:
+ opd->only_newsig_seen = 0;
+ return sig ? parse_tofu_stats (sig, args)
+ /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+ case GPGME_STATUS_TOFU_STATS_LONG:
+ opd->only_newsig_seen = 0;
+ return sig ? parse_tofu_stats_long (sig, args, ctx->raw_description)
+ /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
+
case GPGME_STATUS_ERROR:
opd->only_newsig_seen = 0;
/* Some error stati are informational, so we don't return an
@@ -861,8 +1103,6 @@ verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
if (!sig)
return gpg_error (GPG_ERR_NO_DATA);
- if (!signed_text && !plaintext)
- return gpg_error (GPG_ERR_INV_VALUE);
return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext);
}
@@ -1009,6 +1249,8 @@ gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
gpgme_verify_result_t result;
gpgme_signature_t sig;
+ (void)whatidx;
+
result = gpgme_op_verify_result (ctx);
sig = result->signatures;
diff --git a/src/version.c b/src/version.c
index 15e5aee..8bc898f 100644
--- a/src/version.c
+++ b/src/version.c
@@ -124,7 +124,7 @@ parse_version_number (const char *str, int *number)
/* Parse the version string STR in the format MAJOR.MINOR.MICRO (for
example, 9.3.2) and return the components in MAJOR, MINOR and MICRO
as integers. The function returns the tail of the string that
- follows the version number. This might be te empty string if there
+ follows the version number. This might be the empty string if there
is nothing following the version number, or a patchlevel. The
function returns NULL if the version string is not valid. */
static const char *
@@ -196,7 +196,7 @@ _gpgme_compare_versions (const char *my_version,
const char *
gpgme_check_version (const char *req_version)
{
- char *result;
+ const char *result;
do_subsystem_inits ();
/* Catch-22: We need to get at least the debug subsystem ready
@@ -307,7 +307,7 @@ _gpgme_get_program_version (const char *const file_name)
char *mark = NULL;
int rp[2];
int nread;
- char *argv[] = {NULL /* file_name */, "--version", 0};
+ char *argv[] = {NULL /* file_name */, (char*)"--version", 0};
struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
{-1, -1} };
int status;
diff --git a/src/versioninfo.rc.in b/src/versioninfo.rc.in
index 7f19b30..3ce38f0 100644
--- a/src/versioninfo.rc.in
+++ b/src/versioninfo.rc.in
@@ -39,7 +39,7 @@ BEGIN
VALUE "FileDescription", "GPGME - GnuPG Made Easy\0"
VALUE "FileVersion", "@LIBGPGME_LT_CURRENT@.@LIBGPGME_LT_AGE@.@LIBGPGME_LT_REVISION@.@BUILD_REVISION@\0"
VALUE "InternalName", "gpgme\0"
- VALUE "LegalCopyright", "Copyright © 2001-2015 g10 Code GmbH\0"
+ VALUE "LegalCopyright", "Copyright © 2001-2016 g10 Code GmbH\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "gpgme.dll\0"
VALUE "PrivateBuild", "\0"
diff --git a/src/vfs-create.c b/src/vfs-create.c
index 48931b9..a01d4da 100644
--- a/src/vfs-create.c
+++ b/src/vfs-create.c
@@ -118,6 +118,8 @@ _gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[],
char *container_file_esc = NULL;
int i;
+ (void)flags;
+
/* We want to encourage people to check error values, so not getting
them is discouraged here. Also makes our code easier. */
if (! op_err)
diff --git a/src/vfs-mount.c b/src/vfs-mount.c
index b9b1b4d..5d2f2a9 100644
--- a/src/vfs-mount.c
+++ b/src/vfs-mount.c
@@ -173,6 +173,8 @@ _gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file,
char *cmd;
char *container_file_esc = NULL;
+ (void)flags;
+
/* We want to encourage people to check error values, so not getting
them is discouraged here. Also makes our code easier. */
if (! op_err)
diff --git a/src/w32-glib-io.c b/src/w32-glib-io.c
index a5af4e6..66dc9bf 100644
--- a/src/w32-glib-io.c
+++ b/src/w32-glib-io.c
@@ -98,7 +98,7 @@ static struct
FD is closed. This, together with the fact that dup'ed file
descriptors are closed before the file descriptors from which
they are dup'ed are closed, ensures that CHAN is always valid,
- and shared among all file descriptors refering to the same
+ and shared among all file descriptors referring to the same
underlying object.
The logic behind this is that there is only one reason for us to
diff --git a/src/w32-io.c b/src/w32-io.c
index 42961e3..3a69541 100644
--- a/src/w32-io.c
+++ b/src/w32-io.c
@@ -50,6 +50,7 @@
#include "sema.h"
#include "priv-io.h"
#include "debug.h"
+#include "sys-util.h"
/* FIXME: Optimize. */
@@ -74,7 +75,7 @@ static struct
that dup'ed file descriptors are closed before the file
descriptors from which they are dup'ed are closed, ensures that
the handle or socket is always valid, and shared among all file
- descriptors refering to the same underlying object.
+ descriptors referring to the same underlying object.
The logic behind this is that there is only one reason for us to
dup file descriptors anyway: to allow simpler book-keeping of
@@ -978,7 +979,7 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
return TRACE_SYSRES (-1);
}
- /* If no error occured, the number of bytes in the buffer must be
+ /* If no error occurred, the number of bytes in the buffer must be
zero. */
assert (!ctx->nbytes);
@@ -1550,6 +1551,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
int debug_me = 0;
int tmp_fd;
char *tmp_name;
+ const char *spawnhelper;
TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
"path=%s", path);
@@ -1603,7 +1605,33 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
if ((flags & IOSPAWN_FLAG_DETACHED))
cr_flags |= DETACHED_PROCESS;
cr_flags |= GetPriorityClass (GetCurrentProcess ());
- if (!CreateProcessA (_gpgme_get_w32spawn_path (),
+ spawnhelper = _gpgme_get_w32spawn_path ();
+ if (!spawnhelper)
+ {
+ /* This is a common mistake for new users of gpgme not to include
+ gpgme-w32spawn.exe with their binary. So we want to make
+ this transparent to developers. If users have somehow messed
+ up their installation this should also be properly communicated
+ as otherwise calls to gnupg will result in unsupported protocol
+ errors that do not explain a lot. */
+ char *msg;
+ gpgrt_asprintf (&msg, "gpgme-w32spawn.exe was not found in the "
+ "detected installation directory of GpgME"
+ "\n\t\"%s\"\n\n"
+ "Crypto operations will not work.\n\n"
+ "If you see this it indicates a problem "
+ "with your installation.\n"
+ "Please report the problem to your "
+ "distributor of GpgME.\n\n"
+ "Developers Note: The install dir can be "
+ "manually set with: gpgme_set_global_flag",
+ _gpgme_get_inst_dir ());
+ MessageBoxA (NULL, msg, "GpgME not installed correctly", MB_OK);
+ free (msg);
+ gpg_err_set_errno (EIO);
+ return TRACE_SYSRES (-1);
+ }
+ if (!CreateProcessA (spawnhelper,
arg_string,
&sec_attr, /* process security attributes */
&sec_attr, /* thread security attributes */
@@ -1614,7 +1642,8 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
&si, /* startup information */
&pi)) /* returns process information */
{
- TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
+ int lasterr = (int)GetLastError ();
+ TRACE_LOG1 ("CreateProcess failed: ec=%d", lasterr);
free (arg_string);
close (tmp_fd);
DeleteFileA (tmp_name);
diff --git a/src/w32-qt-io.cpp b/src/w32-qt-io.cpp
deleted file mode 100644
index 44655ec..0000000
--- a/src/w32-qt-io.cpp
+++ /dev/null
@@ -1,700 +0,0 @@
-/* w32-qt-io.c - W32 Glib I/O functions
- Copyright (C) 2000 Werner Koch (dd9jn)
- Copyright (C) 2001, 2002, 2004, 2005, 2007 g10 Code GmbH
-
- This file is part of GPGME.
-
- GPGME is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of
- the License, or (at your option) any later version.
-
- GPGME is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <windows.h>
-#include <io.h>
-
-#include "kdpipeiodevice.h"
-
-extern "C"
-{
-#include "util.h"
-#include "priv-io.h"
-#include "sema.h"
-#include "debug.h"
-}
-
-#ifndef O_BINARY
-#ifdef _O_BINARY
-#define O_BINARY _O_BINARY
-#else
-#define O_BINARY 0
-#endif
-#endif
-
-using _gpgme_::KDPipeIODevice;
-
-
-/* This file is an ugly hack to get GPGME working with Qt on Windows
- targets. On Windows, you can not select() on file descriptors.
-
- The only way to check if there is something to read is to read
- something. This means that GPGME can not let Qt check for data
- without letting Qt also handle the data on Windows targets.
-
- The ugly consequence is that we need to work on QIODevices in
- GPGME, creating a Qt dependency. Also, we need to export an
- interface for the application to get at GPGME's QIODevices. There
- is no good way to abstract all this with callbacks, because the
- whole thing is also interconnected with the creation of pipes and
- child processes.
-
- The following rule applies only to this I/O backend:
-
- * ALL operations must use the user defined event loop. GPGME can
- not anymore provide its own event loop. This is mostly a sanity
- requirement: Although we have in theory all information we need to
- make the GPGME W32 code for select still work, it would be a big
- complication and require changes throughout GPGME.
-
- Eventually, we probably have to bite the bullet and make some
- really nice callback interfaces to let the user control all this at
- a per-context level. */
-
-#define MAX_SLAFD 1024
-
-struct DeviceEntry {
- DeviceEntry() : iodev( 0 ), refCount( 1 ), blocking( true ) {}
- KDPipeIODevice* iodev;
- bool blocking;
- mutable int refCount;
- void ref() const { ++refCount; }
- int unref() const { assert( refCount > 0 ); return --refCount; }
-};
-
-DeviceEntry* iodevice_table[MAX_SLAFD];
-
-
-static KDPipeIODevice *
-find_channel (int fd, int create)
-{
- assert( fd < MAX_SLAFD );
- if (fd < 0 || fd >= MAX_SLAFD)
- return NULL;
-
- if (create && !iodevice_table[fd])
- {
- DeviceEntry* entry = new DeviceEntry;
- entry->iodev = new KDPipeIODevice
- (fd, QIODevice::ReadWrite|QIODevice::Unbuffered);
- iodevice_table[fd] = entry;
- }
- return iodevice_table[fd] ? iodevice_table[fd]->iodev : 0;
-}
-
-/* Write the printable version of FD to the buffer BUF of length
- BUFLEN. The printable version is the representation on the command
- line that the child process expects. */
-int
-_gpgme_io_fd2str (char *buf, int buflen, int fd)
-{
- return snprintf (buf, buflen, "%d", (long)_get_osfhandle( fd ) );
-}
-
-
-void
-_gpgme_io_subsystem_init (void)
-{
-}
-
-
-static struct
-{
- _gpgme_close_notify_handler_t handler;
- void *value;
-} notify_table[MAX_SLAFD];
-
-
-int
-_gpgme_io_read (int fd, void *buffer, size_t count)
-{
- int saved_errno = 0;
- qint64 nread;
- KDPipeIODevice *chan;
- TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
- "buffer=%p, count=%u", buffer, count);
-
- chan = find_channel (fd, 0);
- if (!chan)
- {
- TRACE_LOG ("no channel registered");
- errno = EINVAL;
- return TRACE_SYSRES (-1);
- }
- TRACE_LOG1 ("channel %p", chan);
- if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->readWouldBlock() ) {
- errno = EAGAIN;
- return TRACE_SYSRES( -1 );
- }
-
- nread = chan->read ((char *) buffer, count);
- if (nread < 0)
- {
- TRACE_LOG1 ("err %s", qPrintable (chan->errorString ()));
- saved_errno = EIO;
- nread = -1;
- }
-
- TRACE_LOGBUF ((char *) buffer, nread);
-
- errno = saved_errno;
- return TRACE_SYSRES (nread);
-}
-
-
-int
-_gpgme_io_write (int fd, const void *buffer, size_t count)
-{
- qint64 nwritten;
- KDPipeIODevice *chan;
- TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
- "buffer=%p, count=%u", buffer, count);
- TRACE_LOGBUF ((char *) buffer, count);
-
- chan = find_channel (fd, 0);
- if (!chan)
- {
- TRACE_LOG ("fd %d: no channel registered");
- errno = EINVAL;
- return -1;
- }
-
- if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->writeWouldBlock() )
- {
- errno = EAGAIN;
- return TRACE_SYSRES( -1 );
- }
- nwritten = chan->write ((char *) buffer, count);
-
- if (nwritten < 0)
- {
- nwritten = -1;
- errno = EIO;
- return TRACE_SYSRES(-1);
- }
- errno = 0;
- return TRACE_SYSRES (nwritten);
-}
-
-
-int
-_gpgme_io_pipe (int filedes[2], int inherit_idx)
-{
- KDPipeIODevice *chan;
- TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
- "inherit_idx=%i (GPGME uses it for %s)",
- inherit_idx, inherit_idx ? "reading" : "writing");
-
-#define PIPEBUF_SIZE 4096
- if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
- return TRACE_SYSRES (-1);
-
- /* Make one end inheritable. */
- if (inherit_idx == 0)
- {
- int new_read;
-
- new_read = _dup (filedes[0]);
- _close (filedes[0]);
- filedes[0] = new_read;
-
- if (new_read < 0)
- {
- _close (filedes[1]);
- return TRACE_SYSRES (-1);
- }
- }
- else if (inherit_idx == 1)
- {
- int new_write;
-
- new_write = _dup (filedes[1]);
- _close (filedes[1]);
- filedes[1] = new_write;
-
- if (new_write < 0)
- {
- _close (filedes[0]);
- return TRACE_SYSRES (-1);
- }
- }
-
- /* Now we have a pipe with the right end inheritable. The other end
- should have a giochannel. */
-
- chan = find_channel (filedes[1 - inherit_idx], 1);
-
- if (!chan)
- {
- int saved_errno = errno;
- _close (filedes[0]);
- _close (filedes[1]);
- errno = saved_errno;
- return TRACE_SYSRES (-1);
- }
-
- return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
- filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
- filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
- chan);
-}
-
-int
-_gpgme_io_close (int fd)
-{
- KDPipeIODevice *chan;
- TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
-
- if (fd < 0 || fd >= MAX_SLAFD)
- {
- errno = EBADF;
- return TRACE_SYSRES (-1);
- }
-
- /* First call the notify handler. */
- if (notify_table[fd].handler)
- {
- notify_table[fd].handler (fd, notify_table[fd].value);
- notify_table[fd].handler = NULL;
- notify_table[fd].value = NULL;
- }
-
- /* Then do the close. */
-
- DeviceEntry* const entry = iodevice_table[fd];
- if ( entry ) {
- if ( entry->unref() == 0 ) {
- entry->iodev->close();
- delete entry->iodev;
- delete entry;
- iodevice_table[fd] = 0;
- }
- } else {
- _close( fd );
- }
-
-
-
- return 0;
-}
-
-
-int
-_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
- void *value)
-{
- TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
- "close_handler=%p/%p", handler, value);
-
- assert (fd != -1);
-
- if (fd < 0 || fd >= (int) DIM (notify_table))
- {
- errno = EINVAL;
- return TRACE_SYSRES (-1);
- }
- notify_table[fd].handler = handler;
- notify_table[fd].value = value;
- return TRACE_SYSRES (0);
-}
-
-
-int
-_gpgme_io_set_nonblocking (int fd)
-{
- DeviceEntry* const entry = iodevice_table[fd];
- assert( entry );
- entry->blocking = false;
- TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
- return TRACE_SYSRES (0);
-}
-
-
-static char *
-build_commandline (char **argv)
-{
- int i;
- int n = 0;
- char *buf;
- char *p;
-
- /* We have to quote some things because under Windows the program
- parses the commandline and does some unquoting. We enclose the
- whole argument in double-quotes, and escape literal double-quotes
- as well as backslashes with a backslash. We end up with a
- trailing space at the end of the line, but that is harmless. */
- for (i = 0; argv[i]; i++)
- {
- p = argv[i];
- /* The leading double-quote. */
- n++;
- while (*p)
- {
- /* An extra one for each literal that must be escaped. */
- if (*p == '\\' || *p == '"')
- n++;
- n++;
- p++;
- }
- /* The trailing double-quote and the delimiter. */
- n += 2;
- }
- /* And a trailing zero. */
- n++;
-
- buf = p = (char *) malloc (n);
- if (!buf)
- return NULL;
- for (i = 0; argv[i]; i++)
- {
- char *argvp = argv[i];
-
- *(p++) = '"';
- while (*argvp)
- {
- if (*argvp == '\\' || *argvp == '"')
- *(p++) = '\\';
- *(p++) = *(argvp++);
- }
- *(p++) = '"';
- *(p++) = ' ';
- }
- *(p++) = 0;
-
- return buf;
-}
-
-
-int
-_gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
- struct spawn_fd_item_s *fd_list,
- void (*atfork) (void *opaque, int reserved),
- void *atforkvalue, pid_t *r_pid)
-{
- SECURITY_ATTRIBUTES sec_attr;
- PROCESS_INFORMATION pi =
- {
- NULL, /* returns process handle */
- 0, /* returns primary thread handle */
- 0, /* returns pid */
- 0 /* returns tid */
- };
- STARTUPINFO si;
- int cr_flags = CREATE_DEFAULT_ERROR_MODE
- | GetPriorityClass (GetCurrentProcess ());
- int i;
- char **args;
- char *arg_string;
- /* FIXME. */
- int debug_me = 0;
- int tmp_fd;
- char *tmp_name;
-
- TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
- "path=%s", path);
- i = 0;
- while (argv[i])
- {
- TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
- i++;
- }
-
- /* We do not inherit any handles by default, and just insert those
- handles we want the child to have afterwards. But some handle
- values occur on the command line, and we need to move
- stdin/out/err to the right location. So we use a wrapper program
- which gets the information from a temporary file. */
- if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
- {
- TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
- return TRACE_SYSRES (-1);
- }
- TRACE_LOG1 ("tmp_name = %s", tmp_name);
-
- args = (char **) calloc (2 + i + 1, sizeof (*args));
- args[0] = (char *) _gpgme_get_w32spawn_path ();
- args[1] = tmp_name;
- args[2] = const_cast<char *>(path);
- memcpy (&args[3], &argv[1], i * sizeof (*args));
-
- memset (&sec_attr, 0, sizeof sec_attr);
- sec_attr.nLength = sizeof sec_attr;
- sec_attr.bInheritHandle = FALSE;
-
- arg_string = build_commandline (args);
- free (args);
- if (!arg_string)
- {
- close (tmp_fd);
- DeleteFile (tmp_name);
- return TRACE_SYSRES (-1);
- }
-
- memset (&si, 0, sizeof si);
- si.cb = sizeof (si);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
- si.hStdInput = INVALID_HANDLE_VALUE;
- si.hStdOutput = INVALID_HANDLE_VALUE;
- si.hStdError = INVALID_HANDLE_VALUE;
-
- cr_flags |= CREATE_SUSPENDED;
- if ((flags & IOSPAWN_FLAG_DETACHED))
- cr_flags |= DETACHED_PROCESS;
- if (!CreateProcessA (_gpgme_get_w32spawn_path (),
- arg_string,
- &sec_attr, /* process security attributes */
- &sec_attr, /* thread security attributes */
- FALSE, /* inherit handles */
- cr_flags, /* creation flags */
- NULL, /* environment */
- NULL, /* use current drive/directory */
- &si, /* startup information */
- &pi)) /* returns process information */
- {
- TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
- free (arg_string);
- close (tmp_fd);
- DeleteFile (tmp_name);
-
- /* FIXME: Should translate the error code. */
- errno = EIO;
- return TRACE_SYSRES (-1);
- }
-
- free (arg_string);
-
- if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
- _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
-
- /* Insert the inherited handles. */
- for (i = 0; fd_list[i].fd != -1; i++)
- {
- HANDLE hd;
-
- if (!DuplicateHandle (GetCurrentProcess(),
- (HANDLE) _get_osfhandle (fd_list[i].fd),
- pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
- {
- TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
- TerminateProcess (pi.hProcess, 0);
- /* Just in case TerminateProcess didn't work, let the
- process fail on its own. */
- ResumeThread (pi.hThread);
- CloseHandle (pi.hThread);
- CloseHandle (pi.hProcess);
-
- close (tmp_fd);
- DeleteFile (tmp_name);
-
- /* FIXME: Should translate the error code. */
- errno = EIO;
- return TRACE_SYSRES (-1);
- }
- /* Return the child name of this handle. */
- fd_list[i].peer_name = (int) hd;
- }
-
- /* Write the handle translation information to the temporary
- file. */
- {
- /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
- notation: "0xFEDCBA9876543210" with an extra white space after
- every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead
- for a time when a HANDLE is 64 bit. */
-#define BUFFER_MAX 800
- char line[BUFFER_MAX + 1];
- int res;
- int written;
- size_t len;
-
- if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
- strcpy (line, "~1 \n");
- else
- strcpy (line, "\n");
- for (i = 0; fd_list[i].fd != -1; i++)
- {
- /* Strip the newline. */
- len = strlen (line) - 1;
-
- /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */
- snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n",
- fd_list[i].fd, fd_list[i].dup_to,
- fd_list[i].peer_name, fd_list[i].arg_loc);
- /* Rather safe than sorry. */
- line[BUFFER_MAX - 1] = '\n';
- line[BUFFER_MAX] = '\0';
- }
- len = strlen (line);
- written = 0;
- do
- {
- res = write (tmp_fd, &line[written], len - written);
- if (res > 0)
- written += res;
- }
- while (res > 0 || (res < 0 && errno == EAGAIN));
- }
- close (tmp_fd);
- /* The temporary file is deleted by the gpgme-w32spawn process
- (hopefully). */
-
- TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
- "dwProcessID=%d, dwThreadId=%d",
- pi.hProcess, pi.hThread,
- (int) pi.dwProcessId, (int) pi.dwThreadId);
-
- if (r_pid)
- *r_pid = (pid_t)pi.dwProcessId;
-
- if (ResumeThread (pi.hThread) < 0)
- TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
-
- if (!CloseHandle (pi.hThread))
- TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
- (int) GetLastError ());
-
- TRACE_LOG1 ("process=%p", pi.hProcess);
-
- /* We don't need to wait for the process. */
- if (!CloseHandle (pi.hProcess))
- TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
- (int) GetLastError ());
-
- for (i = 0; fd_list[i].fd != -1; i++)
- _gpgme_io_close (fd_list[i].fd);
-
- for (i = 0; fd_list[i].fd != -1; i++)
- if (fd_list[i].dup_to == -1)
- TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
- fd_list[i].peer_name);
- else
- TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
- fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
- ((fd_list[i].dup_to == 1) ? "out" : "err"));
-
- return TRACE_SYSRES (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, int nonblock)
-{
- /* Use a 1s timeout. */
-
- void *dbg_help = NULL;
- TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
- "nfds=%u, nonblock=%u", nfds, nonblock);
-
- int count = 0;
-
- TRACE_SEQ (dbg_help, "select on [ ");
- for (int i = 0; i < nfds; i++)
- {
- if (fds[i].fd == -1)
- {
- fds[i].signaled = 0;
- }
- else if (fds[i].for_read )
- {
- KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
- assert (chan);
- if ( nonblock )
- fds[i].signaled = chan->readWouldBlock() ? 0 : 1;
- else
- fds[i].signaled = chan->waitForReadyRead( 1000 ) ? 1 : 0;
- TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
- if ( fds[i].signaled )
- count++;
- }
- else if (fds[i].for_write)
- {
- const KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
- assert (chan);
- fds[i].signaled = nonblock ? ( chan->writeWouldBlock() ? 0 : 1 ) : 1;
- TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
- if ( fds[i].signaled )
- count++;
- }
- }
- TRACE_END (dbg_help, "]");
-
- return TRACE_SYSRES (count);
-}
-
-
-/* Look up the qiodevice for file descriptor FD. */
-extern "C"
-void *
-gpgme_get_fdptr (int fd)
-{
- return find_channel (fd, 0);
-}
-
-
-/* Obsolete compatibility interface. */
-extern "C"
-void *
-gpgme_get_giochannel (int fd)
-{
- return NULL;
-}
-
-
-int
-_gpgme_io_dup (int fd)
-{
- assert( iodevice_table[fd] );
- iodevice_table[fd]->ref();
- return fd;
-}
-
-
-extern "C"
-int
-_gpgme_io_socket (int domain, int type, int proto)
-{
- errno = EIO;
- return -1;
-}
-
-
-extern "C"
-int
-_gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
-{
- errno = EIO;
- return -1;
-}
diff --git a/src/w32-util.c b/src/w32-util.c
index 9aba26f..0086fe3 100644
--- a/src/w32-util.c
+++ b/src/w32-util.c
@@ -85,7 +85,10 @@ static HMODULE my_hmodule;
binaries. The are set only once by gpgme_set_global_flag. */
static char *default_gpg_name;
static char *default_gpgconf_name;
-
+/* If this variable is not NULL the value is assumed to be the
+ installation directory. The variable may only be set once by
+ gpgme_set_global_flag and accessed by _gpgme_get_inst_dir. */
+static char *override_inst_dir;
#ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
@@ -347,6 +350,9 @@ _gpgme_get_inst_dir (void)
{
static char *inst_dir;
+ if (override_inst_dir)
+ return override_inst_dir;
+
LOCK (get_path_lock);
if (!inst_dir)
{
@@ -403,8 +409,13 @@ find_program_at_standard_place (const char *name)
char path[MAX_PATH];
char *result = NULL;
- /* See http://wiki.tcl.tk/17492 for details on compatibility. */
- if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
+ /* See http://wiki.tcl.tk/17492 for details on compatibility.
+
+ We First try the generic place and then fallback to the x86
+ (i.e. 32 bit) place. This will prefer a 64 bit of the program
+ over a 32 bit version on 64 bit Windows if installed. */
+ if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0)
+ || SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
{
result = malloc (strlen (path) + 1 + strlen (name) + 1);
if (result)
@@ -456,6 +467,28 @@ _gpgme_set_default_gpgconf_name (const char *name)
}
+/* Set the override installation directory. This function may only be
+ called by gpgme_set_global_flag. Returns 0 on success. */
+int
+_gpgme_set_override_inst_dir (const char *dir)
+{
+ if (!override_inst_dir)
+ {
+ override_inst_dir = malloc (strlen (dir) + 1);
+ if (override_inst_dir)
+ {
+ strcpy (override_inst_dir, dir);
+ replace_slashes (override_inst_dir);
+ /* Remove a trailing slash. */
+ if (*override_inst_dir
+ && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
+ override_inst_dir[strlen (override_inst_dir)-1] = 0;
+ }
+ }
+ return !override_inst_dir;
+}
+
+
/* Return the full file name of the GPG binary. This function is used
iff gpgconf was not found and thus it can be assumed that gpg2 is
not installed. This function is only called by get_gpgconf_item
@@ -530,15 +563,26 @@ _gpgme_get_gpgconf_path (void)
gpgconf = find_program_at_standard_place (name2);
}
- /* 3. Try to find gpgconf.exe using that ancient registry key. This
- should eventually be removed. */
+ /* 3. Try to find gpgconf.exe using the Windows registry. */
if (!gpgconf)
{
char *dir;
- dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
+ dir = read_w32_registry_string (NULL,
"Software\\GNU\\GnuPG",
"Install Directory");
+ if (!dir)
+ {
+ char *tmp = read_w32_registry_string (NULL,
+ "Software\\GnuPG",
+ "Install Directory");
+ if (tmp)
+ {
+ if (gpgrt_asprintf (&dir, "%s\\bin", tmp) == -1)
+ return NULL;
+ free (tmp);
+ }
+ }
if (dir)
{
gpgconf = find_program_in_dir (dir, name);
@@ -614,7 +658,7 @@ static const char letters[] =
does not exist at the time of the call to mkstemp. TMPL is
overwritten with the result. */
static int
-mkstemp (char *tmpl)
+my_mkstemp (char *tmpl)
{
int len;
char *XXXXXX;
@@ -722,7 +766,7 @@ _gpgme_mkstemp (int *fd, char **name)
if (!tmpname)
return -1;
strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX");
- *fd = mkstemp (tmpname);
+ *fd = my_mkstemp (tmpname);
if (fd < 0)
{
free (tmpname);
diff --git a/src/wait-global.c b/src/wait-global.c
index f03775e..28f3921 100644
--- a/src/wait-global.c
+++ b/src/wait-global.c
@@ -206,7 +206,7 @@ _gpgme_wait_global_event_cb (void *data, gpgme_event_io_t type,
gpgme_error_t err = ctx_active (ctx);
if (err)
- /* An error occured. Close all fds in this context, and
+ /* An error occurred. Close all fds in this context, and
send the error in a done event. */
_gpgme_cancel_with_err (ctx, err, 0);
}
@@ -325,7 +325,7 @@ gpgme_wait_ext (gpgme_ctx_t ctx, gpgme_error_t *status,
err = _gpgme_run_io_cb (&fdt.fds[i], 0, &local_op_err);
if (err || local_op_err)
{
- /* An error occured. Close all fds in this context,
+ /* An error occurred. Close all fds in this context,
and signal it. */
_gpgme_cancel_with_err (ictx, err, local_op_err);
diff --git a/src/wait-private.c b/src/wait-private.c
index 9a43110..12d3180 100644
--- a/src/wait-private.c
+++ b/src/wait-private.c
@@ -89,7 +89,7 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond,
if (nr < 0)
{
- /* An error occured. Close all fds in this context, and
+ /* An error occurred. Close all fds in this context, and
signal it. */
err = gpg_error_from_syserror ();
_gpgme_cancel_with_err (ctx, err, 0);
@@ -116,7 +116,7 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond,
err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0, &op_err);
if (err)
{
- /* An error occured. Close all fds in this context,
+ /* An error occurred. Close all fds in this context,
and signal it. */
_gpgme_cancel_with_err (ctx, err, 0);
@@ -124,7 +124,7 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond,
}
else if (op_err)
{
- /* An operational error occured. Cancel the current
+ /* An operational error occurred. Cancel the current
operation but not the session, and signal it. */
_gpgme_cancel_with_err (ctx, 0, op_err);
diff --git a/src/wait-user.c b/src/wait-user.c
index ba28761..c7bc80f 100644
--- a/src/wait-user.c
+++ b/src/wait-user.c
@@ -46,6 +46,8 @@ _gpgme_user_io_cb_handler (void *data, int fd)
struct tag *tag = (struct tag *) data;
gpgme_ctx_t ctx;
+ (void)fd;
+
assert (data);
ctx = tag->ctx;
assert (ctx);